Home > Software design >  Stuctured logs in shell script using JQ
Stuctured logs in shell script using JQ

Time:02-04

I've been wanting to logs some shells scripts to a file to be picked up by an agent like Fluentbit and shipped off to Cloudwatch and Datadog.

I found this example on the web which works like a charm using jq.

__timestamp(){
  date " %Y%m%dT%H%M%S"
}
__log(){
  log_level="$1"
  message="$2"
  echo '{}' | jq \
    --arg timestamp "$(__timestamp)"
    --arg log_level "$log_level" \
    --arg message "$message" \
    '.timestamp=$timestamp|.log_level=$log_level|.message=$message' >> logs.log
}
__log "INFO" "Hello, World!"

The one issue is that the output is rendering a full json with newlines and tabs. Easy on the eyes, but not great for cloud logging services.

{
  "timestamp": "20220203T162320",
  "log_level": "INFO",
  "message": "Hello, World!"
}

How would I modify to render the output on one line like so?

{"timestamp": "20220203T171908","log_level": "INFO","message": "Hello, World!"}

CodePudding user response:

Use the --compact-output or -c option: jq -c --arg … '…' >> logs.log

From the manual:

--compact-output / -c:
    By default, jq pretty-prints JSON output. Using this option will
    result in more compact output by instead putting  each JSON object
    on a single line.

Note that instead of echo '{}' | jq … you could also use the --null-input or -n option: jq -n -c --arg …

--null-input/-n:
    Don't read any input at all! Instead, the filter is run once using
    null as the input. This is useful when using jq as a simple
    calculator or to construct JSON data from scratch.

Lastly, the filter .timestamp=$timestamp|.log_level=$log_level|.message=$message could also be simplified to just {$timestamp,$log_level,$message}.

CodePudding user response:

  •  Tags:  
  • Related