如何格式化 Node.js 的流式 JSON 输出?

如何格式化 Node.js 的流式 JSON 输出?

我有一个使用 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 .

相关内容