Script Valley
Debugging: A Systematic Approach
Strategic Logging and ObservabilityLesson 4.1

Why console.log debugging fails at scale and what replaces it

console.log limitations, structured logging, log levels, production logging, noise vs signal in logs

The Limits of console.log

console.log works for local debugging. In production, it fails: logs have no severity level (you cannot filter for errors only), no timestamps, no context (which request triggered this?), and no structured format (you cannot query them). One production incident with 10,000 unfiltered log lines will permanently change how you think about logging.

Log Levels

Every production logger uses severity levels. Learn them in order: DEBUG (internal state, development only), INFO (normal operations, key events), WARN (unexpected but handled situations), ERROR (failures that need attention), FATAL (unrecoverable failures). Log at the right level -- if everything is INFO, nothing is INFO.

// Node.js with pino (fast structured logger)
const logger = require('pino')();

logger.info({ userId: '123', action: 'login' }, 'User logged in');
logger.warn({ orderId: '456', reason: 'low_stock' }, 'Order at risk');
logger.error({ err: error, orderId: '456' }, 'Payment failed');

// Output (structured JSON, queryable):
// {"level":30,"time":1234567890,"userId":"123","msg":"User logged in"}

What Goes in a Log Entry

Every log entry should answer: when (timestamp), what severity, what happened (message), and what context (request ID, user ID, resource ID). Context is the most commonly omitted field and the most valuable when tracing a bug. Logging Payment failed is useless. Logging Payment failed for orderId 456, userId 123, amount 99.00, reason card_declined is actionable.

Up next

Where to place logs to trace a bug through your system

Sign in to track progress