Backend Logging
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).
What Logging Is (and What It Isn't)
Understand the role of logs in the observability trifecta, and why random print statements fail in production.
What is a Log?
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:
- Diagnosing Failures: Pinpointing the exact database query, parameter, or external API timeout that crashed a request.
- Forensic Security Auditing: Investigating compromised accounts, brute-force attempts, or unauthorized access patterns.
- Business Milestones: Confirming that an invoice was generated, an email was dispatched, or an inventory lock was acquired.
Logging vs. Metrics vs. Tracing
Engineers frequently blur these three pillars together. Here is how they cleanly differ:
- Logs: Detailed event descriptions with text context ("User 42 failed payment because card expired").
- Metrics: Numeric aggregations over time windows ("Payment failure rate is currently 4.2% across 1,000 requests").
- Tracing: Visual spans tracking a single request flowing through Gateway → Service A → Service B → Database.
Log Levels: DEBUG, INFO, WARN, ERROR
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 |
Structured Logging (JSON & Correlation IDs)
Stop outputting plain-text strings. Format logs as JSON so aggregators can index fields for instant search.
Unstructured Logging (Anti-Pattern)
Why it fails at scale:
- Log aggregators must execute slow regex scans to extract the user ID or order ID.
- Cannot filter by numeric values (e.g.
latency > 500ms). - Interleaved concurrent logs are impossible to separate.
Structured JSON (Production Standard)
Why it excels:
- Directly queryable:
event:order.payment_failed AND userId:user_42. - Correlation ID (
reqId) groups all logs for that single HTTP request.
Node.js & Express Practices (Pino / Winston)
Why console.log() is not enough for production, and how fast JSON loggers like Pino automate request tracing.
Why Pino Over console.log?
- Zero Event-Loop Lag:
console.logcan be synchronous in Node.js when writing to terminals or file descriptors, causing thread blocking under load. - Built-in Redaction: Pino scrubs sensitive keys (
password,authorization) automatically before writing to standard out. - Child Loggers:
req.loginherits request correlation metadata without manually passingreqIdinto every function.
Python & FastAPI Logging (exc_info)
Leverage Python's standard logging module with structured context and capture complete tracebacks safely.
What NOT to Log (OWASP Security Rules)
Logs are persistent across backups, aggregators, and developer dashboards. Never log sensitive credentials or private user data.
Data Strictly Forbidden in Logs (OWASP)
- Passwords: Plaintext, hashes, salts, or recovery codes.
- Authentication Tokens: JWT Bearer tokens, OAuth refresh tokens, session cookies.
- API Keys & Secrets: Stripe keys, AWS credentials, webhook secrets.
- Financial Data: Full credit card numbers (PANs), CVVs, bank account numbers.
- Unrestricted Dumps: Full
req.bodyor raw query string dumps on checkout endpoints.
Safe Logging & Masking Techniques
- Partial Masking: Displaying only the last 4 digits (e.g.
cardEnding: "4242"). - Redaction Placeholders: Replacing sensitive keys with
[REDACTED]. - Event Codes Over Text: Emitting discrete error codes (
INVALID_CREDENTIALS) instead of echoing input. - Scoped Context: Log entity IDs (
userId: "u_99") instead of full personal profiles.
Interactive Logging & Debugging Studio
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!
Production Debugging: 7 Logging Pitfalls
Analyze real-world architectural bugs where improper logging compromised security or made incident response impossible.
Scenario #1: Catastrophic Credential Leak: Logging Raw Request Bodies
Mini Challenge, 5 Golden Rules & Mastery Quiz
Test your incident investigation skills and solidify the 5 Golden Rules of production logging.
Incident Investigation Mini-Challenge
A customer reports that their order failed on POST /api/orders. You query your log aggregator and retrieve the following structured JSON record:
5 Golden Rules of Production Logging
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.