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

JSON이 아닌 출력 줄이 있다고 가정하면 n다음 짧은 스크립트는 이러한 줄을 있는 그대로 전달하고 jq나머지 줄의 형식을 지정하는 데 사용됩니다. 입력이 스크립트의 표준 입력에서 온다고 가정하면 스크립트는 n첫 번째 명령줄 인수에서 숫자를 가져옵니다(이 인수가 없으면 기본값은 5입니다).

#!/bin/sh

n=${1-5}

if [ "$n" -gt 0 ]; then
    head -n "$n"
fi

jq .

스크립트는 명령이 정확한 입력 head줄만 소비한다고 가정합니다. n일부 구현에서는 head이러한 방식으로 동작하지 않으며 n행보다 더 많은 내용을 읽고 처리할 입력이 남지 않습니다 jq. GNU는 head이 점에서 잘 작동하며 예상대로 작동합니다.

시험:

$ 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 .

관련 정보