Structured Logging with Correlation IDs
Emit machine-parseable JSON logs and thread correlation IDs through async context for request tracing.
Why Structured Logging
In production, logs are read by machines before humans. A line like console.log('User ' + id + ' failed login') is a free-form string: to find it later you must write brittle regex and you cannot aggregate or filter reliably.
Structured logging emits each log as a JSON object with consistent fields. Log aggregators (Loki, Elasticsearch, Datadog, CloudWatch) index those fields so you can query level="error" AND userId=42 instantly.
- Free-form: easy to write, painful to query.
- Structured: one JSON object per line (NDJSON), trivially parseable.
A Minimal JSON Logger
The core idea is small: build a plain object, stamp it with a level and timestamp, and write one JSON string per line to stdout. The runtime or container collects stdout and ships it to your aggregator.
Each log is a single line of valid JSON. This format is called NDJSON (newline-delimited JSON) and every modern log backend understands it.
function log(level, message, fields = {}) {
const entry = {
level,
time: new Date().toISOString(),
message,
...fields,
};
process.stdout.write(JSON.stringify(entry) + '\n');
}
log('info', 'server started', { port: 3000 });
log('error', 'login failed', { userId: 42, reason: 'bad_password' });All lessons in this course
- Structured Logging with Correlation IDs
- Distributed Tracing with OpenTelemetry Spans
- Exposing Application Metrics and the RED Method
- Context Propagation with AsyncLocalStorage