Why I Use Loggers like Winston and Morgan in My Node.js Apps Instead of Console Logs
Unlocking the Power of Professional Logging for Scalable Applications
As a Node.js developer, debugging and monitoring are integral parts of my workflow. While console.log()
might seem like the simplest and most obvious tool for this purpose, it’s far from the best option when building scalable and maintainable applications. This is where professional logging libraries like Winston and Morgan come into play.
In this blog, I’ll dive into why I rely on Winston and Morgan instead of sticking to console logs, showcasing their features with examples and comparisons.
Why Console Logs Are Not Enough
Lack of Log Levels : With
console.log()
, you don’t have a structured way to classify logs likeinfo
,error
,warn
, ordebug
.example :
console.log("This is an info log"); console.error("This is an error log"); // But no way to categorize further or manage verbosity.
Unstructured Outputs: Console logs do not offer formatting or timestamps by default, making it hard to track when or where a log was generated.
No Persistence: Logs created via
console.log()
are ephemeral. They’re printed in the terminal and lost once the application stops running.Performance Issues: Excessive console logs can slow down your application, especially when logging in production.
Inadequate for Production: Console logs aren’t suitable for real-world monitoring and debugging, especially in distributed systems where logs need to be centralized.
Enter Winston and Morgan
Both Winston and Morgan are powerful logging tools, but they serve different purposes:
Winston: A general-purpose logger with advanced features like log levels, transports (e.g., saving to files or sending to monitoring systems), and formatting.
Morgan: A specialized HTTP request logger middleware for Node.js, perfect for tracking incoming requests and responses in your web application.
Key Benefits of Winston
Log Levels: Categorize logs into levels like
error
,warn
,info
,debug
, etc., and filter them based on the environment.import winston from "winston"; import config from "./config.js"; export const logger = winston.createLogger({ level: "info", format: winston.format.combine( winston.format.timestamp({ format: "ddd, MMM D YYYY : h:mm A", }), winston.format.colorize(), winston.format.printf((info) => { return `${info.level}: ${info.message} -> ${info.timestamp}`; }) ), // transports: [ // new winston.transports.File({ filename: "error.log", level: "error" }), // new winston.transports.File({ filename: "combined.log" }), // ], }); logger.info("Application started"); logger.error("Something went wrong");
Transports: Send logs to multiple destinations, such as files, databases, or external monitoring services.
Format Customization: Add timestamps, colors, or custom formats for better readability.
Error Handling: Capture stack traces and structured error information.
Key Benefits of Morgan
Request Logging: Morgan logs HTTP requests, including method, URL, response time, and status code.
const morgan = require("morgan"); const express = require("express"); const {logger} = require("./logger.js"); const app = express(); app.use(morgan("combined")); // Logs detailed HTTP request info app.get("/", (req, res) => res.send("Hello, world!")); app.listen(3000, () => logger.info("Application started"));
Predefined Formats: Use presets like
combined
,common
,short
, anddev
or define your own custom format.Lightweight and Fast: Optimized for HTTP request logging without overhead.
Comparing Winston, Morgan, and Console Logs
Example 1: Basic Logging
With Console Logs:
console.log("User logged in");
console.error("Database connection failed");
With Winston :
logger.info("User logged in");
logger.error("Database connection failed", { code: 500 });
- Winston adds timestamps and allows categorization.
Example 2: HTTP Request Logging
With Console Logs :
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
With Morgan :
app.use(morgan("combined"));
- Morgan provides detailed logs without manual effort.
Visual Comparison
Console Logs vs. Winston Output
Console Logs:
User logged in
Database connection failed
Winston Logs:
info: Server running in DEVELOPMENT mode on port 5000 -> Tue, Jan 28 2025 : 12:36 PM
Morgan Output (Combined Format)
127.0.0.1 - - [28/Jan/2025:12:34:56 +0000] "GET / HTTP/1.1" 200 - "-" "Mozilla/5.0"
When to Use Which
Use Winston for general application logging, error tracking, and debugging.
Use Morgan for HTTP request and response logging in Express applications.
Avoid relying on
console.log()
in production applications.
Final Thoughts
Using logging libraries like Winston and Morgan is a no-brainer for anyone serious about building robust and maintainable Node.js applications. They provide powerful features, better organization, and ensure that your logs are useful for debugging and monitoring both during development and in production.
If you’re still using console.log()
in your apps, it’s time to make the switch. Your future self (and your team) will thank you!