Node.js Logging Guide

Here’s a complete and practical guide on Node.js Logging — covering why logging is important, built-in methods, logging libraries, structured logging, and best practices.


📝 Node.js Logging Guide

Logging is essential for:

  • Debugging errors

  • Monitoring production apps

  • Auditing and compliance

  • Performance analysis

Node.js provides built-in logging with console, but for production-grade apps, specialized logging libraries are recommended.


1️⃣ Basic Logging with console

Node.js provides simple logging functions:

console.log("Info: Server started");
console.info("Info message");
console.warn("Warning message");
console.error("Error message");
console.debug("Debug message"); // works with NODE_DEBUG

Example:

const PORT = 3000;
console.log(Server is running on port ${PORT});

❌ Limitation: console logs are unstructured and not persistent.


2️⃣ File Logging with fs

You can write logs to a file using the Node.js fs module:

const fs = require('fs');

function logToFile(message) {
const timestamp = new Date().toISOString();
fs.appendFileSync('app.log', [${timestamp}] ${message}\n);
}

logToFile("Server started successfully");

❌ Limitation: Manual file rotation and log levels need to be implemented manually.


3️⃣ Using Logging Libraries

For production apps, use logging libraries like:

3.1 Winston (Most Popular)

npm install winston

Example:

const winston = require('winston');

const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'app.log' })
]
});

logger.info("Server started");
logger.warn("This is a warning");
logger.error("Something went wrong");

✅ Features:

  • Multiple transports (console, file, HTTP)

  • Log levels (error, warn, info, debug)

  • JSON formatting for structured logs


3.2 Morgan (HTTP Request Logging for Express)

npm install morgan

Example:

const express = require('express');
const morgan = require('morgan');

const app = express();

// Log HTTP requests to console
app.use(morgan('combined'));

app.get('/', (req, res) => res.send('Hello World'));

app.listen(3000, () => console.log("Server running on port 3000"));

✅ Features:

  • Pre-defined log formats: combined, common, dev

  • Can log to a file using fs.createWriteStream


3.3 Pino (High-performance JSON Logger)

npm install pino

Example:

const pino = require('pino');
const logger = pino({ level: 'info' });

logger.info("Server started successfully");
logger.error("An error occurred");

✅ Features:

  • Extremely fast

  • Structured JSON logging

  • Works well with log aggregators


4️⃣ Log Levels

Common log levels:

Level Description
error Critical issues, app crashes
warn Warnings, non-critical errors
info General information
http HTTP request info
verbose Detailed info for debugging
debug Developer-focused debug info
silly Most granular debug info

Libraries like Winston and Pino support multiple levels.


5️⃣ Structured Logging

Instead of plain text, structured logs (JSON) help with:

  • Searching logs in ELK (Elasticsearch, Logstash, Kibana)

  • Aggregation & monitoring

  • Debugging in production

logger.info({
event: "user_login",
userId: 123,
timestamp: new Date().toISOString()
});

6️⃣ Log Rotation

Prevent log files from growing indefinitely:

npm install winston-daily-rotate-file
const DailyRotateFile = require('winston-daily-rotate-file');

logger.add(new DailyRotateFile({
filename: 'app-%DATE%.log',
datePattern: 'YYYY-MM-DD',
maxFiles: '14d' // keep 14 days logs
}));


7️⃣ Logging Best Practices

  1. Use levels (error, warn, info, debug)

  2. Do not log sensitive data (passwords, tokens)

  3. Use structured logging (JSON) for production

  4. Log HTTP requests (Morgan or Pino HTTP)

  5. Use log rotation to avoid huge files

  6. Centralize logs with ELK, Grafana Loki, or CloudWatch

  7. Separate dev & prod logging


8️⃣ Example: Production-ready Logger

const winston = require('winston');
const DailyRotateFile = require('winston-daily-rotate-file');

const logger = winston.createLogger({
level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new DailyRotateFile({ filename: 'logs/app-%DATE%.log', datePattern: 'YYYY-MM-DD', maxFiles: '14d' })
]
});

module.exports = logger;

Use in your app:

const logger = require('./logger');

logger.info("Server started");
logger.error("Database connection failed");


🎯 Summary

  • console is enough for small apps

  • Use Winston, Pino, or Morgan for production apps

  • Structured logs (JSON) help with monitoring and debugging

  • Use log levels, rotation, and avoid sensitive data

  • Integrate with ELK Stack, CloudWatch, or Grafana for central monitoring

You may also like...