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
Track up to 100 issues per month on the free plan, with unlimited events and no credit card required.
Get Started FreeRelated Articles
How to Catch Broken Releases Before Users Report Them
A practical guide to using error tracking, release tagging, and automated alerts to detect broken deploys within minutes — not after user complaints.
Read moreReact Logging Best Practices for Production
Implement effective logging in React applications with structured client-side logging, error boundaries, and remote log aggregation strategies.
Read moreRemix Performance Monitoring Best Practices
Monitor Remix application performance with loader timing, action profiling, streaming metrics, and server-side rendering optimization.
Read moreGo Error Handling Patterns for Production Code
Learn idiomatic Go error handling patterns including error wrapping, custom types, sentinel errors, and structured error reporting.
Read more