Why Structured Logging Matters
grep vs query — why JSON logs change everything in production debugging
The Problem
Your app has 50 servers generating 10,000 log lines per minute. A user reports a failed request. You need to find it.
Unstructured logs
2026-04-11 10:15:23 INFO Processing request from 192.168.1.50
2026-04-11 10:15:23 ERROR Failed to create item: price cannot be negative
2026-04-11 10:15:24 INFO Request completed in 45ms
How do you find all logs for a specific request? grep? Across 50 servers? Which “INFO Processing request” belongs to which response?
Structured logs (JSON)
{"timestamp": "2026-04-11T10:15:23Z", "level": "info", "event": "request_started", "request_id": "abc-123", "method": "POST", "path": "/api/v1/items/", "client_ip": "192.168.1.50"}
{"timestamp": "2026-04-11T10:15:23Z", "level": "error", "event": "validation_failed", "request_id": "abc-123", "field": "price", "reason": "must be greater than 0"}
{"timestamp": "2026-04-11T10:15:24Z", "level": "info", "event": "request_completed", "request_id": "abc-123", "status_code": 422, "duration_ms": 45}
Now search Elasticsearch: request_id: "abc-123" — find every log line for that request, across all servers, in milliseconds.
Structured vs Unstructured
| Feature | print() / text logs | structlog JSON |
|---|---|---|
| Parse programmatically | Regex (fragile) | JSON parse (reliable) |
| Search across servers | grep + ssh loops | Elasticsearch query |
| Correlate request flow | Impossible | request_id field |
| Alert on patterns | Custom scripts | Kibana/Grafana rules |
| Add context | String concatenation | Key-value pairs |
| Filter by level | Text search | level: "error" |
The Cost of Unstructured Logging
- Slower incident response — 30 minutes grepping vs 30 seconds querying
- Lost context — which user? which request? which server?
- No alerting — can’t alert on what you can’t parse
- No dashboards — can’t visualize unstructured text
What Structured Logging Gives You
- Correlation — every log in a request shares
request_id - Context —
method,path,user_id,duration_msare first-class fields - Queryability — Elasticsearch, Loki, CloudWatch all parse JSON natively
- Alerting — alert when
status_code: 500count exceeds threshold - Dashboards — graph
duration_msby endpoint over time
Next Step
In the next lesson, we implement structured logging with structlog — JSON renderers, processors, and context binding.