Como formatar a saída JSON do Node.js?

2

Eu tenho um servidor Node.js que usa o registro em log JSON. Ao executar o servidor localmente, ele gera entradas de log como objetos JSON, que são muito entediantes de serem lidos. Eu gostaria de canalizar a saída através de um comando para que seja mais fácil de seguir.

Eu tentei algumas alternativas como jq mas o problema é que quando o servidor Node.js é iniciado, ele é impresso algumas linhas que não são válidas JSON e não encontrei nenhum comando que possa ignorar o JSON inválido.

Existe algum comando pronto que eu possa usar ou tenho que começar a implementar o meu próprio? Cada linha na saída do servidor é um objeto JSON completo (exceto as poucas linhas no início).

    
por Visa Kopu 01.09.2016 / 07:30

2 respostas

0

Eu não toco muito jq ou json, então eu tive que simular um ambiente, mas a ideia geral deveria resolver o seu problema.

Aqui eu gero três linhas de cabeçalho e alguma saída JSON (falsa):

#!/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

e aqui está um script que lerá três linhas de cabeçalho, depois passará o resto da entrada para o comando jq real (ou, para simular jq, estou passando por sed):

#!/usr/bin/env bash

for((HEADLINES=3; HEADLINES > 0; HEADLINES--))
do
  IFS= read -r header
  printf "%s\n" "$header"
done

sed 's/^/parsing: /'

A idéia principal aqui é read do número desejado de linhas de cabeçalho, imprimi-las de volta sem alteração e, em seguida, passar o restante da entrada para jq (sed, aqui). Substitua o comando sed pelo seu comando jq desejado.

Uma amostra de corrida:

$ ./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
    
por 04.09.2016 / 00:13
0

Supondo que haja n linhas de saída não-JSON, o seguinte script curto passará essas linhas como estão e usará jq para formatar as linhas restantes. A entrada é assumida como entrada padrão para o script e o script usa o número n do primeiro argumento de linha de comando (ou o padrão é 5 se esse argumento não existir).

#!/bin/sh

n=${1-5}

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

jq .

O script assume que o comando head consumirá exatamente n de linhas de entrada. Existem implementações de head que não se comportam assim e que lerão mais de n linhas, não deixando nenhuma entrada para jq processar. O% GNUhead é bem comportado neste aspecto e funciona como pretendido.

Teste:

$ 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"
}

A seguir, uma variação do que foi mencionado acima, que adiciona uma detecção simplista do início do conteúdo JSON na entrada. Supõe-se que o documento JSON comece na primeira linha que tenha um { como o primeiro caractere.

Primeiro, o script salva a entrada em um arquivo temporário (que é excluído quando o script é encerrado) e, em seguida, analisa esse arquivo duas vezes. Uma vez para extrair os dados não-JSON e novamente para extrair o documento JSON.

#!/bin/sh

tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"' EXIT

cat >"$tmpfile"

sed -n '/^[^{]/{p;d;}; q' <"$tmpfile"
sed -n '/^{/,$p'          <"$tmpfile" | jq .

Teste:

$ 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"
}

Se o uso de um arquivo temporário parece deselegante, a seguinte variação leva o nome do caminho do arquivo de entrada a partir da linha de comando:

#!/bin/sh

infile=$1

sed -n '/^[^{]/{p;d;}; q' <"$infile"
sed -n '/^{/,$p'          <"$infile" | jq .
    
por 05.09.2018 / 16:25