All posts

Express.js Logging Best Practices for Production

Implement structured logging in Express.js with Winston, request correlation IDs, sensitive data filtering, and log level management.

Express.js Logging Best Practices for Production

Good logging is the difference between debugging a production issue in minutes versus hours. Here's how to set up Express logging properly.

Use Structured Logging

Ditch console.log for structured JSON logs with Winston:

const winston = require('winston');

const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  transports: [
    new winston.transports.Console(),
  ],
});

Add Request Correlation IDs

Trace requests across services with unique IDs:

const { v4: uuidv4 } = require('uuid');

app.use((req, res, next) => {
  req.id = req.headers['x-request-id'] || uuidv4();
  res.setHeader('x-request-id', req.id);
  next();
});

// Use in route handlers
app.get('/api/orders', async (req, res) => {
  logger.info('Fetching orders', { requestId: req.id, userId: req.user.id });
  // ...
});

Filter Sensitive Data

Never log passwords, tokens, or PII:

const sanitize = (obj) => {
  const redacted = { ...obj };
  const sensitive = ['password', 'token', 'authorization', 'ssn', 'creditCard'];
  for (const key of Object.keys(redacted)) {
    if (sensitive.includes(key.toLowerCase())) {
      redacted[key] = '[REDACTED]';
    }
  }
  return redacted;
};

Log Levels Guide

  • error — something broke, needs immediate attention
  • warn — something unexpected but handled (retry succeeded, fallback used)
  • info — significant business events (user signup, order placed)
  • debug — detailed diagnostic data (disabled in production)

Request Logging Middleware

app.use((req, res, next) => {
  const start = Date.now();
  res.on('finish', () => {
    logger.info('request completed', {
      method: req.method,
      path: req.originalUrl,
      status: res.statusCode,
      duration: Date.now() - start,
      requestId: req.id,
    });
  });
  next();
});

Pair structured logs with Bugsly's error tracking to correlate log entries with specific exceptions, giving you the full context when investigating production issues.

Try Bugsly Free

AI-powered error tracking that explains your bugs. Set up in 2 minutes, free forever for small projects.

Get Started Free