Node.js7 min read
Logging with Winston and Morgan
Implement professional logging in Node.js. Use Winston for application logs and Morgan for HTTP requests.
Sarah Chen
December 19, 2025
0.0k0
Logging with Winston and Morgan
Good logging is essential for debugging and monitoring. Console.log won't cut it in production.
Setup
npm install winston morgan
Winston - Application Logs
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
// Add console in development
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}
module.exports = logger;
Log Levels
logger.error('Database connection failed');
logger.warn('Deprecated API called');
logger.info('User logged in');
logger.http('GET /api/users');
logger.debug('Processing data...');
Custom Format
const logger = winston.createLogger({
format: winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.printf(({ timestamp, level, message, ...meta }) => {
return `${timestamp} [${level.toUpperCase()}]: ${message} ${Object.keys(meta).length ? JSON.stringify(meta) : ''}`;
})
),
transports: [
new winston.transports.Console()
]
});
logger.info('User created', { userId: 1, email: 'alice@example.com' });
// 2024-01-15 10:30:00 [INFO]: User created {"userId":1,"email":"alice@example.com"}
Morgan - HTTP Request Logs
const morgan = require('morgan');
// Predefined formats
app.use(morgan('dev')); // :method :url :status :response-time ms
app.use(morgan('combined')); // Apache combined format
app.use(morgan('tiny')); // Minimal output
// Custom format
app.use(morgan(':method :url :status :response-time ms - :res[content-length]'));
Morgan + Winston Integration
const morgan = require('morgan');
const logger = require('./logger');
// Create stream for winston
const stream = {
write: (message) => logger.http(message.trim())
};
app.use(morgan('combined', { stream }));
Skip Logging for Health Checks
app.use(morgan('combined', {
skip: (req, res) => req.url === '/health'
}));
Daily Rotate File
npm install winston-daily-rotate-file
require('winston-daily-rotate-file');
const logger = winston.createLogger({
transports: [
new winston.transports.DailyRotateFile({
filename: 'logs/app-%DATE%.log',
datePattern: 'YYYY-MM-DD',
maxSize: '20m',
maxFiles: '14d' // Keep 14 days of logs
})
]
});
Complete Logger Setup
// logger.js
const winston = require('winston');
require('winston-daily-rotate-file');
const levels = {
error: 0,
warn: 1,
info: 2,
http: 3,
debug: 4
};
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
levels,
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
defaultMeta: { service: 'my-app' },
transports: [
new winston.transports.DailyRotateFile({
filename: 'logs/error-%DATE%.log',
datePattern: 'YYYY-MM-DD',
level: 'error',
maxFiles: '30d'
}),
new winston.transports.DailyRotateFile({
filename: 'logs/combined-%DATE%.log',
datePattern: 'YYYY-MM-DD',
maxFiles: '14d'
})
]
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
)
}));
}
module.exports = logger;
Usage in Application
const logger = require('./logger');
// In route handlers
app.post('/api/users', async (req, res) => {
try {
const user = await User.create(req.body);
logger.info('User created', { userId: user.id });
res.status(201).json(user);
} catch (error) {
logger.error('Failed to create user', { error: error.message, stack: error.stack });
res.status(500).json({ error: 'Internal error' });
}
});
Key Takeaway
Use Winston for application logs and Morgan for HTTP requests. Set up daily rotation to manage log files. Include timestamps and structured metadata. Different log levels help filter what's important. Good logging saves hours of debugging.
#Node.js#Logging#Winston#Morgan#Intermediate