Skip to content
Latchkey

How to Emit Structured Logs From Pipeline Steps

Structured logs are one JSON object per line, which lets aggregators filter builds by field instead of grepping free text.

Print one JSON object per log line with stable keys (level, stage, run, message). Aggregators like Loki and Elasticsearch index those fields so you can query level=error stage=build across all runs.

Steps

  • Agree on a small schema: level, stage, run, message.
  • Emit one JSON object per line from each step.
  • Let the aggregator parse JSON so fields become queryable.

Emit a structured line

.github/workflows/ci.yml
- name: Structured log
  run: |
    log() {
      printf '{"level":"%s","stage":"%s","run":"%s","msg":"%s"}\n' \
        "$1" "build" "${{ github.run_id }}" "$2"
    }
    log info "starting build"
    npm run build || { log error "build failed"; exit 1; }

Gotchas

  • Escape quotes and newlines in the message, or the line stops being valid JSON.
  • Keep the key set stable; renaming fields breaks saved queries and dashboards.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →