π Logging Practices β
Structured, useful logging that helps debug production issues.
Log levels β
| Level | When to use | Example |
|---|---|---|
error | Something broke, needs attention | Unhandled exception, failed payment |
warn | Something unexpected but handled | Retry succeeded, deprecated API used |
info | Key business events | User signed up, order placed |
debug | Development details | Query executed, cache hit/miss |
Structured logging β
typescript
// BAD
console.log('User ' + userId + ' placed order ' + orderId)
// GOOD
logger.info('Order placed', {
userId,
orderId,
amount: order.total,
requestId: req.id,
})Output (JSON):
json
{
"level": "info",
"message": "Order placed",
"userId": "usr_123",
"orderId": "ord_456",
"amount": 99.99,
"requestId": "req_789",
"timestamp": "2026-03-06T12:00:00Z"
}What to log β
- Incoming requests (method, path, status, duration)
- Business events (signup, purchase, cancellation)
- External API calls (URL, status, duration)
- Errors with full context
- Background job execution (start, end, result)
What NOT to log β
- Passwords, tokens, API keys
- Full credit card numbers
- Personal data (email, phone) unless necessary
- Request/response bodies in production (too verbose)
- Health check pings (noise)
Request context β
Add a unique request ID to every log in a request lifecycle:
typescript
app.use((req, res, next) => {
req.id = crypto.randomUUID()
next()
})This enables tracing a single request across all log entries.
Log aggregation β
- Development: console output
- Production: Ship to ELK, Loki, Datadog, or CloudWatch
- Set retention policies (30 days for debug, 1 year for errors)
- Create alerts on error patterns