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

How to debug performance issues using timing logs

performance debugging, timing measurements, bottleneck identification, slow queries, profiling vs timing logs

Performance Bugs Are Logic Bugs

A slow function is a function with a bug -- something in the execution path is doing more work than necessary. Finding that something requires measurement, not intuition. Timing logs measure how long each segment of an operation takes and reveal which segment is the bottleneck.

Timing with console.time and performance.now

// Browser or Node.js
console.time('db-query');
const result = await db.query(sql);
console.timeEnd('db-query');  // prints: db-query: 2341.22ms

// Structured timing for production
const start = performance.now();
const users = await db.getActiveUsers();
const elapsed = performance.now() - start;
logger.info({ operation: 'getActiveUsers', duration_ms: elapsed, count: users.length });

// If elapsed > 1000ms: this is the bottleneck
// Check: is there an index on the query column?
// Check: is the query returning more rows than needed?

Finding the Bottleneck

Time each major step in a slow operation separately -- not the whole operation as one block. A 3-second API response might be 2ms of logic and 2998ms of a missing database index. Without per-step timing you cannot tell. Once you find the bottleneck, investigate it specifically: missing index, N+1 query pattern, synchronous loop doing async work, or unnecessary data transfer.

Up next

How to write a log query to diagnose a bug from log output

Sign in to track progress