Node.js Logging

Logging records what your app does while it runs. Logs help you find bugs, track errors, and understand user activity. A good log works like the black box of an airplane. After a problem, you read it to learn what happened.

Why console.log Is Not Enough

The console.log function suits quick tests. Production apps need more.

  • Log levels separate important errors from small details.
  • Timestamps show when events occurred.
  • Files and services store logs for later review.
  • Structured data makes searching easy.

Log Levels

A level shows how serious a message is. Levels let you turn detail up or down.

 error   Something failed. Act now.          (most serious)
 warn    Something looks wrong.
 info    Normal events, such as a login.
 http    Request records.
 debug   Detail for developers.               (least serious)

A production server often logs info and above. A developer laptop logs debug and above.

Install Winston

Winston is a popular Node.js logging library.

npm install winston

Create a Logger

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: "logs/error.log", level: "error" }),
    new winston.transports.File({ filename: "logs/combined.log" })
  ]
});

module.exports = logger;

Understand the Pieces

  • level sets the lowest level that the logger records.
  • format shapes each log line.
  • transports name the destinations, such as the screen or a file.
 logger.error("Payment failed")
            |
            v
      +-----------+
      |  Logger   |
      +-----------+
       |    |    |
       v    v    v
  Console  error.log  combined.log

Write Log Messages

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

logger.info("Server started on port 3000");
logger.warn("Disk space is low");
logger.error("Database connection failed", { host: "db1", retry: 3 });

Each line prints as JSON.

{"level":"info","message":"Server started on port 3000","timestamp":"2026-10-07T10:15:30.120Z"}

Log Requests with Morgan

Morgan records every web request.

npm install morgan
const morgan = require("morgan");

app.use(morgan("combined", {
  stream: { write: (line) => logger.http(line.trim()) }
}));

Each request creates a line with the method, path, status code, and response time.

Log Errors in Express

app.use((err, req, res, next) => {
  logger.error(err.message, {
    stack: err.stack,
    path: req.originalUrl,
    method: req.method
  });
  res.status(500).json({ error: "Something went wrong." });
});

The visitor sees a short message. The log holds the full detail.

Rotate Log Files

One file grows without limit. Rotation starts a new file each day and removes old ones.

npm install winston-daily-rotate-file
require("winston-daily-rotate-file");

new winston.transports.DailyRotateFile({
  filename: "logs/app-%DATE%.log",
  datePattern: "YYYY-MM-DD",
  maxFiles: "14d"
});

Add Context to Every Line

Child loggers attach shared details such as a request id.

const requestLogger = logger.child({ requestId: "abc-123" });
requestLogger.info("User loaded cart");
requestLogger.error("Checkout failed");

A search for one request id shows its whole story.

What Never to Log

  • Passwords and password hashes.
  • Credit card numbers.
  • Access tokens and secret keys.
  • Private personal details beyond what you need.

Mask sensitive values before you write them.

Send Logs to a Service

Large systems collect logs from many servers in one place. Tools such as the ELK stack, Grafana Loki, and cloud log services provide search and alerts. JSON lines work well with all of them.

Good Habits

  • Write clear messages that name the event and the object.
  • Choose the right level for each message.
  • Keep one shared logger module for the whole app.
  • Review logs on a regular schedule.

Practice Tasks

  • Create a logger that writes errors to a file and everything to the console.
  • Add Morgan to a small Express app and read the request lines.
  • Log a failed login with the email but without the password.