Logging & Monitoring

5 questions found

Why is structured (JSON) logging generally preferred over plain-text console.log() statements in a production Node.js application?

Beginner
Structured logging outputs each log entry as a machine-parseable object (typically JSON) with consistent fields (timestamp, level, message, and contextual metadata) rather than a free-form text string -- this makes logs searchable, filterable, and aggregatable by a centralized logging system (like an ELK stack or Datadog), letting you query for 'all error-level logs for user X in the last hour' precisely, something that's difficult and fragile with unstructured plain-text logs relying on regex parsing.
// Unstructured: hard to search/filter reliably at scale
console.log('User ' + userId + ' logged in at ' + new Date());

// Structured: easily queryable by any field
const pino = require('pino')();
pino.info({ event: 'user_login', userId, timestamp: Date.now() }, 'User logged in');
Real-world example An operations team investigating a specific customer's reported issue searches their centralized log system for {"userId": "12345"} across every service, instantly finding every relevant structured log entry for that customer -- a query that would have been impractical to perform reliably against unstructured plain-text logs scattered across many services.

Common follow-ups: What specific fields should almost every structured log entry include as a baseline?;How does structured logging support building automated alerts based on specific field values, unlike plain text?

Debugging & Diagnostics;Cloud & DevOps

What is log level (debug, info, warn, error), and how do you configure a logger like Pino or Winston to filter output by level per environment?

Intermediate
Log levels categorize the severity/importance of a log entry, letting a logger be configured to only actually output entries at or above a certain threshold -- typically 'debug' level (very verbose, useful during active development) is enabled locally but suppressed in production, where only 'info' and above are emitted, reducing log volume and cost while still capturing everything operationally relevant; 'error' level logs are reserved for genuine failures needing attention.
const pino = require('pino')({
  level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
});

pino.debug('Detailed diagnostic info'); // only shown in development
pino.info('Server started');            // shown in both
pino.error({ err }, 'Payment processing failed'); // always shown, needs attention
Real-world example A production service configured with log level 'info' silently drops thousands of verbose debug-level log lines per minute that would otherwise be generated during normal operation, keeping log storage costs manageable while a developer can temporarily set the level to 'debug' via an environment variable when actively investigating a specific issue.

Common follow-ups: How would you dynamically change a running production service's log level without restarting it, for temporary deep debugging?;What's the risk of setting the production log level too high (like only 'error'), potentially missing useful warning signs before an actual failure?

Environment Variables & Configuration;Debugging & Diagnostics

How would you implement distributed tracing across multiple Node.js microservices using OpenTelemetry?

Advanced
OpenTelemetry is a vendor-neutral standard and set of libraries for generating traces, metrics, and logs -- for distributed tracing specifically, each service creates 'spans' representing units of work, and a trace context (a unique trace ID plus the current span ID) is propagated across service boundaries via HTTP headers, letting a tracing backend (like Jaeger, Zipkin, or a commercial APM tool) reconstruct the full end-to-end path and timing of a single request as it flows through multiple independent services.
const { trace } = require('@opentelemetry/api');
const tracer = trace.getTracer('order-service');

async function processOrder(orderId) {
  const span = tracer.startSpan('process-order');
  try {
    await chargePayment(orderId); // this call automatically propagates trace context via HTTP headers
    span.setStatus({ code: 0 });
  } catch (err) {
    span.recordException(err);
    span.setStatus({ code: 2 });
    throw err;
  } finally {
    span.end();
  }
}
Real-world example A team debugging why a specific customer's checkout occasionally takes eight seconds uses distributed tracing to visualize the full request path across their order, inventory, and payment microservices, immediately spotting that the payment service's fraud-check step is the single slow component responsible for nearly the entire delay.

Common follow-ups: How does trace context propagation actually work at the HTTP header level (the traceparent header) across service boundaries?;What's the sampling tradeoff between tracing every single request versus only a percentage, given the storage cost of full tracing at scale?

Microservices Architecture with Node.js;Architecture & Design Patterns

How would you implement request correlation IDs to trace a single request's logs across multiple log lines and services?

Intermediate
A correlation (or request/trace) ID is generated once when a request first enters the system (or extracted if it was already provided by an upstream caller), attached to the request context (commonly via AsyncLocalStorage, as discussed earlier), and included in every log line emitted while handling that request -- as well as forwarded in outgoing headers to any downstream services called -- letting an engineer search logs across an entire distributed system for that single ID to reconstruct the complete story of one specific request.
app.use((req, res, next) => {
  req.correlationId = req.headers['x-correlation-id'] || crypto.randomUUID();
  res.setHeader('x-correlation-id', req.correlationId);
  next();
});

// Every log line during this request includes the same ID
logger.info({ correlationId: req.correlationId, event: 'processing_order' });

// Forwarded to downstream services
fetch(downstreamUrl, { headers: { 'x-correlation-id': req.correlationId } });
Real-world example An engineer debugging a customer-reported error asks the customer for the correlation ID shown in their error message, then searches the centralized logging system for that exact ID, instantly retrieving every log line from every microservice involved in handling that specific failed request.

Common follow-ups: How does a correlation ID differ from and relate to a full distributed trace ID from a system like OpenTelemetry?;What happens if a downstream service fails to forward the correlation ID header, breaking the trace continuity?

Microservices Architecture with Node.js;Async Patterns

What is an APM (Application Performance Monitoring) tool, and what capabilities does it typically add beyond basic logging?

Intermediate
An APM tool (like New Relic, Datadog APM, or Dynatrace) automatically instruments an application to capture detailed performance data -- transaction traces showing exactly where time is spent within a request (including database query timing and external API call timing), error tracking with full stack traces and grouping of similar errors, and real-time dashboards of throughput, latency percentiles, and error rates -- generally requiring far less manual instrumentation effort than building equivalent visibility purely from custom logs and metrics.
// Typical APM setup: install and initialize the agent, often at the very top of the entry file
require('newrelic'); // must be required before any other module in many APM tools

const express = require('express');
const app = express();
// The APM agent automatically instruments Express routes, database calls, etc.
Real-world example A team investigating a vague customer complaint of 'the app feels slow sometimes' installs an APM tool, which within a day surfaces a clear pattern: a specific database query used on one particular page consistently takes 2-3 seconds during peak hours, pinpointing exactly where to focus their optimization effort without needing to add any custom instrumentation themselves.

Common follow-ups: What's the performance overhead of running an APM agent's automatic instrumentation in production?;How do APM tools typically handle the cost tradeoff of capturing full trace data for every single request versus a sampled subset?

Performance Optimization & Profiling;Debugging & Diagnostics