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 .