A Complete Guide to Logging in Node.js with Winston and AWS CloudWatch

Search for a command to run...

No comments yet. Be the first to comment.
Claude is incredibly good at reasoning. But reasoning is only as useful as the context available to it. Your architecture might be in GitHub. Your notes might be in Obsidian. Your decisions might be b

Mind maps are an excellent addition to an MCP ecosystem when they help users understand relationships between data, tools, and reasoning. They should complement—not replace—traditional dashboards, tab
Most AI agents today depend heavily on cloud APIs. They're fast, but every request costs money, depends on an internet connection, and sends your data to external providers. Over the weekend, I experi
How I use Fable 5 to research, build, and maintain custom Claude Code plugins, marketplaces, agents, and skills—creating reusable AI tooling that works across every project. 01 · The problem with copy

The way people search is changing. Is your site ready? For the past two decades, SEO (Search Engine Optimization) was the undisputed king of web visibility. Rank on Google's first page and you win tr
Logging is a crucial part of any application development. It helps track application behavior, debug issues, monitor performance, and ensure everything works as expected.
Winston is a logging library for Node.js designed to be simple, flexible, and extensible. It supports multiple logging transports, which means you can send your logs to different destinations such as a file, the console, or even cloud services like AWS CloudWatch.
Start by installing Winston in your Node.js project:
npm install winston
Create a new file logger.js and add the following code to set up Winston:
const winston = require('winston');
// Create a Winston logger instance
const logger = winston.createLogger({
level: 'info', // Default log level
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json() // Logs will be in JSON format
),
transports: [
new winston.transports.File({ filename: 'logs/error.log', level: 'error' }), // Log errors to error.log
new winston.transports.File({ filename: 'logs/combined.log' }) // Log all messages to combined.log
],
});
// If we're in development, log to the console
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple(), // Simple output in the console for readability
}));
}
module.exports = logger;
In this setup:
We log all messages to combined.log.
Errors are logged separately to error.log.
For development environments, logs are also sent to the console.
You can now import and use your logger throughout your Node.js app:
const logger = require('./logger');
logger.info('Server started successfully');
logger.error('Error occurred during server initialization');
Winston has a useful plugin called winston-daily-rotate-file that allows you to automatically rotate logs daily.
npm install winston-daily-rotate-file
Modify your logger.js to include log rotation:
const winston = require('winston');
const DailyRotateFile = require('winston-daily-rotate-file');
// Configure Winston with Daily Rotate File transport
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new DailyRotateFile({
filename: 'logs/application-%DATE%.log',
datePattern: 'YYYY-MM-DD',
maxFiles: '14d', // Keep logs for 14 days
}),
],
});
This setup creates new log files daily, and older logs are automatically deleted after 14 days.
Security is another important aspect, especially for web applications. Helmet is a middleware that helps secure your Express app by setting HTTP headers.
npm install helmet
Add Helmet to your Express app to automatically apply security headers:
const express = require('express');
const helmet = require('helmet');
const app = express();
// Use Helmet for security
app.use(helmet());
app.get('/', (req, res) => {
res.send('Hello World with Security Headers!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
To manage and monitor logs from various servers or instances, you can use AWS CloudWatch. We'll use the WinstonCloudWatch transport to send logs directly to CloudWatch.
npm install winston-cloudwatch aws-sdk
Modify your logger.js to include AWS CloudWatch as a log transport:
const winston = require('winston');
const WinstonCloudWatch = require('winston-cloudwatch');
// Configure AWS credentials (optional if using IAM roles)
const AWS = require('aws-sdk');
AWS.config.update({ region: 'us-east-1' });
// Configure Winston logger with CloudWatch transport
const logger = winston.createLogger({
transports: [
new WinstonCloudWatch({
logGroupName: 'node-app-logs', // CloudWatch log group name
logStreamName: 'node-app-stream', // CloudWatch log stream name
awsRegion: 'us-east-1',
}),
],
});
Now, whenever you use the logger, it will send logs to AWS CloudWatch:
logger.info('This is an info message');
logger.error('This is an error message');
You can view and analyze the logs in the AWS CloudWatch Console by navigating to Log Groups and selecting your logGroupName.
While Winston rotates and manages logs automatically, you may still want to run custom cron jobs to delete old logs or manage log retention.
npm install node-cron
In logger.js, you can set up a cron job to run every day and delete log files older than 14 days:
const cron = require('node-cron');
const fs = require('fs');
const path = require('path');
const logDirectory = path.join(__dirname, 'logs');
// Set up a cron job to delete old logs every day at midnight
cron.schedule('0 0 * * *', () => {
fs.readdir(logDirectory, (err, files) => {
if (err) throw err;
files.forEach((file) => {
const filePath = path.join(logDirectory, file);
fs.stat(filePath, (err, stats) => {
if (err) throw err;
const now = Date.now();
const fileAge = now - stats.mtimeMs;
if (fileAge > 14 * 24 * 60 * 60 * 1000) { // 14 days in ms
fs.unlink(filePath, (err) => {
if (err) throw err;
console.log(`Deleted old log file: ${file}`);
});
}
});
});
});
});
By combining Winston for logging, Helmet for security, and AWS CloudWatch for centralized log management, you create a robust, scalable, and secure logging infrastructure for your Node.js application. This setup ensures that logs are handled efficiently, with automatic rotation, cloud-based storage, and optional cron jobs for custom log management.
By integrating these tools, your application becomes easier to monitor, debug, and scale in production environments.