Understand application behavior, investigate production outages, and trace requests across asynchronous boundaries. Master Log Levels (DEBUG, INFO, WARN, ERROR), JSON structured formatting, correlation IDs, and OWASP data sanitization.
Core Logging Principle: Logging is for understanding and diagnosing discrete application behavior. Do not confuse logging with numeric metrics or distributed tracing. In production, logs must be structured JSON, contain a correlation ID, and NEVER expose sensitive secrets (passwords, tokens, or PII).
Understand the role of logs in the observability trifecta, and why random print statements fail in production.
A log is an append-only, timestamped record of a discrete event that occurred inside an application. When an outage strikes at 3:00 AM, logs are the flight recorder that reconstructs reality:
Engineers frequently blur these three pillars together. Here is how they cleanly differ:
Choose appropriate severity levels to avoid flooding production systems while ensuring genuine errors trigger alerts.
| Level | Intended Purpose | Production Status | Realistic Backend Example |
|---|---|---|---|
| DEBUG | Detailed developer tracing (SQL params, intermediate loop variables, raw payload shapes). | Disabled by default (Huge I/O & cost). | DEBUG: Parsed 42 items from redis cache key 'user:101:cart' |
| INFO | Coarse-grained operational milestones (server started, order created, worker processed batch). | Enabled (Baseline operational pulse). | INFO: Order #9812 created for customer #44. Total: $150.00 |
| WARN | Unexpected conditions handled gracefully without failing the user (cache miss fallback, retry attempt). | Enabled (Monitored for degradation). | WARN: Redis timeout. Falling back to primary Postgres query. |
| ERROR | Actionable failures where an operation failed (unhandled exceptions, DB connection down, payment 500). | Enabled + Alerted (Triggers PagerDuty). | ERROR: Stripe gateway timeout after 5000ms on order #9812 |
Stop outputting plain-text strings. Format logs as JSON so aggregators can index fields for instant search.
Why it fails at scale:
latency > 500ms).Why it excels:
event:order.payment_failed AND userId:user_42.reqId) groups all logs for that single HTTP request.Why console.log() is not enough for production, and how fast JSON loggers like Pino automate request tracing.
console.log can be synchronous in Node.js when writing to terminals or file descriptors, causing thread blocking under load.password, authorization) automatically before writing to standard out.req.log inherits request correlation metadata without manually passing reqId into every function.Leverage Python's standard logging module with structured context and capture complete tracebacks safely.
Logs are persistent across backups, aggregators, and developer dashboards. Never log sensitive credentials or private user data.
req.body or raw query string dumps on checkout endpoints.cardEnding: "4242").[REDACTED].INVALID_CREDENTIALS) instead of echoing input.userId: "u_99") instead of full personal profiles.Hands-on exercise: An application has poor logging, a password leak, and an intermittent bug on large orders. Refactor the code to structured JSON logs, redact secrets, trigger requests, read the output, and fix the bug!
Analyze real-world architectural bugs where improper logging compromised security or made incident response impossible.
Test your incident investigation skills and solidify the 5 Golden Rules of production logging.
A customer reports that their order failed on POST /api/orders. You query your log aggregator and retrieve the following structured JSON record:
Always format logs as JSON objects with standardized keys (timestamp, level, event, reqId).
OWASP rule: Scrub passwords, API keys, bearer tokens, and payment data. Redact request headers and query parameters.
Attach a correlation ID (reqId) at HTTP ingress and forward it into services, repositories, and queue payloads.
Reserve ERROR for actionable system failures. User validation mistakes belong in WARN/INFO to avoid alert fatigue.
Never log inside high-frequency loops in production. Emit aggregated summaries at INFO and restrict loop details to DEBUG.