In this tutorial, we'll learn use Winston Logger in web applications.
Winston is a versatile and highly customizable logging library for Node.js, widely used in web applications for its flexibility and ability to handle various log formats, transports, and levels. In this tutorial, we will explore how to use Winston in a web application, from basic setup to advanced features like custom log formats, file-based logging, and error handling.
Why Logging Is Important
Logging is essential for:
- Debugging issues during development.
- Monitoring application behavior in production.
- Auditing user actions and system events.
- Maintaining historical records for post-incident analysis.
Winston excels as a logger due to its support for multiple transports (where logs are saved), log levels, and extensibility.
Key Concepts in Winston
- Transports: Winston can log to multiple destinations like the console, files, HTTP endpoints, and more.
- Log Levels: Winston uses predefined severity levels (error, warn, info, http, verbose, debug, and silly) or custom levels.
- Formats: Winston supports formatting log messages using the format module, enabling timestamped, JSON-formatted, or colorized logs.
- Error Handling: Winston integrates well with Node.js for logging errors, making it easy to troubleshoot application issues.
Use Winston Logger in Web Applications
Step 1: Install Winston
To begin, install Winston via npm in your Node.js project:
npm install winston
Step 2: Setting Up Winston in a Web Application
Create a logging utility module to centralize Winston configuration.
Create a logger.js
file and following code:
const { createLogger, format, transports } = require('winston');
// Define custom log format
const customFormat = format.combine(
format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
format.printf(({ timestamp, level, message, stack }) => {
return stack
? `[${timestamp}] ${level}: ${message}\nStack: ${stack}`
: `[${timestamp}] ${level}: ${message}`;
})
);
// Create logger instance
const logger = createLogger({
level: 'info', // Default log level
format: customFormat,
transports: [
new transports.Console({ level: 'debug', format: format.colorize() }),
new transports.File({ filename: 'logs/app.log', level: 'info' }),
new transports.File({ filename: 'logs/error.log', level: 'error' }),
],
exceptionHandlers: [
new transports.File({ filename: 'logs/exceptions.log' })
],
rejectionHandlers: [
new transports.File({ filename: 'logs/rejections.log' })
]
});
module.exports = logger;
Step 3: Using the Logger in an Express Application
Integrate the logger into an Express.js application for capturing requests, responses, and errors.
Create a app.js
file and following code:
const express = require('express');
const morgan = require('morgan'); // HTTP request logging
const logger = require('./logger'); // Import logger module
const app = express();
const PORT = 3000;
// Middleware for HTTP logging using morgan and Winston
app.use(
morgan('combined', {
stream: {
write: (message) => logger.http(message.trim()), // Use 'http' log level
},
})
);
// Sample route
app.get('/', (req, res) => {
logger.info('Home route accessed');
res.send('Welcome to Winston Logger tutorial!');
});
// Middleware for handling errors
app.use((err, req, res, next) => {
logger.error(err.message, { stack: err.stack });
res.status(500).send('Something went wrong!');
});
// Start server
app.listen(PORT, () => {
logger.info(`Server running on http://localhost:${PORT}`);
});
Step 4: Advanced Features
Logging Metadata
Metadata provides additional context, like user IDs or request IDs, to log entries.
logger.info('User logged in', { userId: '12345' });
Dynamic Log Levels
Set log levels dynamically based on the environment.
logger.level = process.env.LOG_LEVEL || 'info';
Conditional Logging
Avoid verbose logs in production:
if (process.env.NODE_ENV !== 'production') {
logger.debug('This is a debug message');
}
Step 5: Rotating Logs with winston-daily-rotate-file
To prevent log files from growing indefinitely, use the winston-daily-rotate-file package.
Install the Package
npm install winston-daily-rotate-file
Update logger.js
const DailyRotateFile = require('winston-daily-rotate-file');
logger.add(
new DailyRotateFile({
filename: 'logs/application-%DATE%.log',
datePattern: 'YYYY-MM-DD',
maxSize: '20m',
maxFiles: '14d'
})
);
Step 6: Testing and Validating Logs
Run the application and observe log outputs in the console and log files. Test different scenarios:
- Normal operations (successful requests).
- HTTP errors (e.g., 404).
- Uncaught exceptions or promise rejections.
Best Practices
1. Use Appropriate Log Levels:
error
: Critical errors.warn
: Non-critical warnings.info
: General information.debug
: Detailed debugging information.
2. Protect Sensitive Data: Avoid logging sensitive user information like passwords or personal details.
3. Centralized Logging: Use external services like ELK Stack (Elasticsearch, Logstash, Kibana) or Grafana Loki for centralized log management.
4. Monitor Logs: Continuously monitor logs for error patterns or unusual activity using automated tools.
Conclusion
Winston is a robust logging library that simplifies managing logs in Node.js applications. By understanding its key concepts and using best practices, you can effectively capture and analyze logs to ensure your application's reliability and performance.
With this production-ready setup, you are well-equipped to handle logging needs for any web application.
Checkout our instant dedicated servers and Instant KVM VPS plans.