Winston Logging in Node.js: Clean, Structured, and Scalable Logs
Are your Node.js logs messy, hard to read, or missing critical information? In this guide, you’ll learn how to configure Winston logging in Node.js to create clean, structured, and scalable logs.
Why Logging Matters in Node.js Applications
Logging is a crucial part of any application. It helps with:
- Debugging: Tracking down issues in your code.
- Monitoring: Keeping an eye on application performance.
- Auditing: Recording important events.
- Error Tracking: Identifying and resolving errors.
- Traceability: Understanding the flow of execution.
⚠️ Important: Never log sensitive information such as passwords, secrets, or personally identifiable information (PII).
Installing Winston for Node.js Logging
The first step is to install Winston in your project. Open your terminal and run:
npm install winston
Next, create a logger.ts
file in the src
folder and import Winston:
import winston from 'winston'; import config from './config';
Configuring Winston Logger in Node.js
Define log levels based on priority:
const logLevels = { error: 0, warn: 1, info: 2, http: 3, debug: 4, };
Now, create a logger instance with a custom format:
const logger = winston.createLogger({ levels: logLevels, level: config.logLevel || 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.printf(({ timestamp, level, message, stack }) => `${timestamp} [${level}]: ${stack || message}` ) ), transports: [new winston.transports.Console()], });
Export the logger for use across your application:
export default logger;
Using the Logger in Your Application
To use the logger in a route controller, import it and add log messages:
import logger from '../logger'; const listTasks = (req, res) => { logger.debug('Requesting tasks'); res.send([]); };
Setting Log Levels Dynamically
Log levels control which messages appear in logs. If a message is logged at debug
level but your logger is set to info
, it won’t be displayed. Set the log level in your .env
file:
LOG_LEVEL=debug
Logging to Files with Winston
For production, you may want to log to files. Install the daily rotate file transport:
npm install winston-daily-rotate-file
🚀Boost your career with Full Stack Software Developer Certificate
Then, configure a rotating file transport:
import DailyRotateFile from 'winston-daily-rotate-file'; const fileRotateTransport = new DailyRotateFile({ filename: 'logs/application-%DATE%.log', datePattern: 'YYYY-MM-DD', zippedArchive: true, maxSize: '20m', maxFiles: '14d', format: winston.format.json(), }); logger.add(fileRotateTransport);
Ignoring Logs in Git
Prevent log files from being committed to your repository by adding this to .gitignore
:
logs/
Integrating Winston with Morgan for HTTP Logging
Morgan is commonly used for logging HTTP requests. To integrate it with Winston:
- Create a
morgan-middleware.ts
file. - Configure Morgan to use Winston:
import morgan from 'morgan'; import logger from '../logger'; const morganMiddleware = morgan(':method :url :status :res[content-length] - :response-time ms', { stream: { write: (message) => logger.http(message.trim()), }, }); export default morganMiddleware;
- Replace default Morgan usage in
server.ts
:
import morganMiddleware from './middleware/morgan-middleware'; app.use(morganMiddleware);
Now, HTTP request logs will be formatted consistently with other logs and saved to your log files.
Wrapping Up
By setting up Winston logging in Node.js, you now have a powerful logging system that can:
- Log messages to the console and files.
- Include metadata such as request IDs or user IDs.
- Rotate logs to prevent excessive storage usage.
- Integrate with Morgan for consistent HTTP request logging.
For more advanced logging, you can integrate Winston with external log management tools like AWS CloudWatch, Loggly, or Datadog.
🚀 Next Steps: Learn how to send logs to AWS CloudWatch for centralized monitoring! Check out this guide to get started.