Structured JSON Logging and Correlation IDs
Emit structured logs with request-scoped correlation IDs that survive across async boundaries and services.
Why Structured Logs
In production, logs are data, not prose. A line like User 42 failed login from 10.0.0.3 reads fine to a human but is painful for machines: you cannot reliably filter, aggregate, or alert on it.
Structured logging emits each event as a JSON object with stable, queryable fields:
timestamp,level,messagerequest_id/correlation_id- context such as
user_id,path,status_code,duration_ms
Log aggregators (Loki, Elasticsearch, Datadog) then index those fields so you can run queries like level=ERROR AND path=/checkout.
A JSON Log in One Line
The simplest structured log is just a dictionary serialized to JSON on one line. One JSON object per line is the JSON Lines (NDJSON) format that virtually every log shipper understands.
This standalone example shows the shape we are aiming for. Notice the fields are flat and named consistently.
import json
import time
def log(level, message, **fields):
record = {
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
"level": level,
"message": message,
**fields,
}
print(json.dumps(record))
log("INFO", "request completed", path="/checkout", status_code=200, duration_ms=42)
log("ERROR", "db timeout", path="/orders", correlation_id="abc-123")All lessons in this course
- Structured JSON Logging and Correlation IDs
- Distributed Tracing with OpenTelemetry
- Prometheus Metrics and RED/USE Dashboards
- Alerting on SLOs and Error Budgets