我有一个使用 JSON 日志记录的 Node.js 服务器。当本地运行服务器时,它会将日志条目输出为 JSON 对象,读取起来非常繁琐。我想通过命令传输输出,以便更容易理解。
我尝试过一些替代方案,比如杰克但问题是,当 Node.js 服务器启动时,它会打印出几行无效的 JSON,而且我还没有找到任何能够忽略无效 JSON 的命令。
是否有任何我可以使用的现成命令,或者我是否必须开始实施自己的命令?服务器输出中的每一行都是一个完整的 JSON 对象(除了开头的几行)。
答案1
如果您要输出 json 日志,请使用它在终端中查看漂亮的 json
node my.js | jq -R 'split("\n")|.[length - 1]|fromjson'
答案2
我不太使用 jq 或 json,所以我必须模拟一个环境,但总体思路应该可以解决您的问题。
这里我生成了三个标题行和一些(假的)JSON 输出:
#!/bin/sh
echo line 1
echo line 2
echo line 3
echo real json output 1
echo real json output 2
echo real json output 3
这是一个脚本,它将读取三个标题行,然后将其余输入传递给真正的jq
命令(或者,为了模拟 jq,我通过 sed 传递它):
#!/usr/bin/env bash
for((HEADLINES=3; HEADLINES > 0; HEADLINES--))
do
IFS= read -r header
printf "%s\n" "$header"
done
sed 's/^/parsing: /'
这里的核心思想是获得read
所需数量的标题行,将它们原封不动地打印出来,然后将其余的输入传递给 jq (sed,此处)。将 sed 命令替换为您所需的jq
命令。
示例运行:
$ ./json.sh | ./jq.sh
line 1
line 2
line 3
parsing: real json output 1
parsing: real json output 2
parsing: real json output 3
答案3
假设有n
非 JSON 输出行,以下简短脚本会按原样传递这些行,并用于jq
格式化其余行。假设输入来自脚本的标准输入,脚本n
从第一个命令行参数中获取数字(如果此参数不存在,则默认为 5)。
#!/bin/sh
n=${1-5}
if [ "$n" -gt 0 ]; then
head -n "$n"
fi
jq .
该脚本假设该head
命令将仅消耗精确的n
输入行。有些实现的行为head
并非如此,并且会读取多于n
行的内容,而不会留下任何输入可供jq
处理。 GNUhead
在这方面表现良好并且按预期工作。
测试:
$ sh script.sh 2 <file.json
non-json text
on two lines
{
"name": "myapp",
"hostname": "myhost.local",
"pid": 64662,
"source_file_path": "/path/to/src/connector.js",
"req_id": "2339717c-6c3b-4e51-a4b2-5c647efd9c25",
"connector": "abc123",
"level": "INFO",
"req": {
"method": "GET",
"url": "http://backend/server/url"
},
"time": "2016-09-01T06:31:55.099Z",
"v": 0,
"message": "Outgoing request"
}
以下是上述内容的变体,添加了对输入中 JSON 内容开头的非常简单的检测。假定 JSON 文档从以 a{
作为第一个字符的第一行开始。
该脚本首先将输入保存到临时文件(该文件在脚本终止时被删除),然后解析该文件两次。一次提取非 JSON 数据,然后再次提取 JSON 文档。
#!/bin/sh
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"' EXIT
cat >"$tmpfile"
sed -n '/^[^{]/{p;d;}; q' <"$tmpfile"
sed -n '/^{/,$p' <"$tmpfile" | jq .
测试:
$ sh script.sh <file.json
non-json text
on two lines
{
"name": "myapp",
"hostname": "myhost.local",
"pid": 64662,
"source_file_path": "/path/to/src/connector.js",
"req_id": "2339717c-6c3b-4e51-a4b2-5c647efd9c25",
"connector": "abc123",
"level": "INFO",
"req": {
"method": "GET",
"url": "http://backend/server/url"
},
"time": "2016-09-01T06:31:55.099Z",
"v": 0,
"message": "Outgoing request"
}
如果使用临时文件看起来不优雅,那么以下变体从命令行获取输入文件的路径名:
#!/bin/sh
infile=$1
sed -n '/^[^{]/{p;d;}; q' <"$infile"
sed -n '/^{/,$p' <"$infile" | jq .