Structured logging — logs in machine-readable format (JSON) instead of plain text. Key benefits: searchable ("error AND user.id=123"), aggregatable (count errors by endpoint), correlatable (trace_id links logs to trace). 2026 stack: Pino (Node, fastest), Zap (Go), Zerolog (Rust), structlog (Python). Backend: Loki (Grafana), Elasticsearch, Datadog.
Below: step-by-step, working examples, common pitfalls, FAQ.
npm install pino (Node), Python: pip install structloglogger = pino({ level: "info" })| Scenario | Config |
|---|---|
| Node.js Pino | const pino = require('pino');
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
redact: ['password', 'token', '*.creditCard'],
timestamp: pino.stdTimeFunctions.isoTime
});
logger.info({ user_id: 123, action: 'login' }, 'User logged in');
// Output: {"level":30,"time":"2026-04-18T...","user_id":123,"action":"login","msg":"User logged in"} |
| Python structlog | import structlog
logger = structlog.get_logger()
logger.info('user_login', user_id=123, method='oauth')
# Output: event='user_login' user_id=123 method='oauth'
# With JSON renderer
structlog.configure(
processors=[structlog.processors.JSONRenderer()]
) |
| Correlation ID middleware | // Express
app.use((req, res, next) => {
req.correlationId = req.headers['x-correlation-id'] || crypto.randomUUID();
req.logger = logger.child({ correlationId: req.correlationId });
res.setHeader('x-correlation-id', req.correlationId);
next();
});
// Then:
req.logger.info({ path: req.path }, 'Request received'); |
| Promtail (ship to Loki) | # promtail-config.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: app
static_configs:
- targets: [localhost]
labels:
job: myapp
__path__: /var/log/myapp/*.log |
| Grafana Loki query | # LogQL
{job="myapp"} |= "error" | json | user_id="123"
# Visual: rate of errors
sum by (path) (rate({job="myapp"} |= "error" [5m])) |
Loki: indexes labels only (not log content), cheap ($0.50/GB), Grafana-native. Elasticsearch: full-text index, expensive ($5/GB), powerful search. For most — Loki is enough.
Logs: discrete events ("Error in checkout"). Traces: request flow + timing. Modern: logs include trace_id → cross-reference.
Hot (instant search): 7-30 days. Warm (S3): 90 days. Cold (Glacier): 1+ year for compliance.
Enterno uses PSR-3 compatible + Papertrail backend. For end-users — <a href="/en/monitors">monitor endpoint</a> covers availability.