How to Log Events and Errors in Node.js
Systematic logging is essential for maintaining, debugging, and monitoring Node.js applications in production environments. This article provides a straightforward guide on how to implement structured logging for application events and errors using two of the most popular logging libraries in the Node.js ecosystem: Winston and Bunyan. You will learn how to configure both tools, structure your log outputs in JSON format, capture error stack traces, and direct logs to different destinations.
Why Structured Logging Matters
Traditional console.log statements are insufficient for
production because they lack metadata, log levels, and standard
formatting. Structured logging outputs logs as machine-readable JSON,
making it easy for log management tools (like Elasticsearch, Datadog, or
AWS CloudWatch) to parse, search, and filter your application data.
Logging with Winston
Winston is a highly versatile and customizable logging library. It supports multiple storage transports, allowing you to route logs to the console, files, or external services simultaneously.
1. Installation
Install Winston via npm:
npm install winston2. Configuration and Usage
Here is a complete configuration setup for Winston that handles standard events, formats outputs as JSON, and captures error stack traces.
const winston = require('winston');
// Create the logger instance
const logger = winston.createLogger({
level: 'info', // Default minimum log level
format: winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.errors({ stack: true }), // Captures stack traces automatically
winston.format.json() // Outputs logs in structured JSON
),
transports: [
// Output logs to the console
new winston.transports.Console(),
// Save error logs to a separate file
new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
// Save all logs to a combined file
new winston.transports.File({ filename: 'logs/combined.log' })
]
});
// Logging standard events
logger.info('Application started successfully', { port: 3000 });
// Logging errors systematically
try {
throw new Error('Database connection failed');
} catch (error) {
logger.error('An error occurred during startup', error);
}Logging with Bunyan
Bunyan is an alternative logging library designed specifically for JSON logging. It is exceptionally fast and enforces JSON formatting by default, ensuring all logs are structured.
1. Installation
Install Bunyan via npm:
npm install bunyan2. Configuration and Usage
Bunyan uses “serializers” to format complex JavaScript objects, such as standard Error objects, into JSON properties.
const bunyan = require('bunyan');
// Create the logger instance
const logger = bunyan.createLogger({
name: 'my-app',
serializers: {
err: bunyan.stdSerializers.err // Standard serializer to extract error details
},
streams: [
{
level: 'info',
stream: process.stdout // Log info and above to the console
},
{
level: 'error',
path: './logs/bunyan-error.log' // Log errors to a file
}
]
});
// Logging standard events
logger.info({ event: 'user_login', userId: '12345' }, 'User logged in successfully');
// Logging errors systematically
try {
throw new Error('Payment gateway timeout');
} catch (error) {
// Pass the error object using the 'err' key to trigger the serializer
logger.error({ err: error }, 'Failed to process transaction');
}Key Best Practices for Systematic Logging
- Use Appropriate Log Levels: Categorize your
messages systematically. Use
infofor general operational events,warnfor unexpected but non-blocking issues, anderrorfor system failures that require immediate attention. - Always Log Stack Traces: When logging errors, pass the actual Error object (not just the error message string) to ensure the stack trace is captured for debugging.
- Keep Log Messages Static: Avoid dynamic strings
like
logger.info(`User ${id} logged in`). Instead, keep the message static and pass dynamic values as metadata:logger.info('User logged in', { userId: id }). This makes aggregation and querying much easier in log analyzers.