Logging with Winston and Morgan
Implement professional logging in Node.js. Use Winston for application logs and Morgan for HTTP requests.
Logging with Winston and Morgan
Good logging is essential for debugging and monitoring. Console.log won't cut it in production.
Setup
```bash npm install winston morgan ```
Winston - Application Logs
```javascript 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
```javascript 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
```javascript 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
```javascript 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
```javascript 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
```javascript app.use(morgan('combined', { skip: (req, res) => req.url === '/health' })); ```
Daily Rotate File
```bash npm install winston-daily-rotate-file ```
```javascript 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
```javascript // 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
```javascript 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.