javascript

How Can You Master Log Management in Express.js With Morgan and Rotating File Streams?

Organized Chaos: Streamlining Express.js Logging with Morgan and Rotating-File-Stream

How Can You Master Log Management in Express.js With Morgan and Rotating File Streams?

Logging in a web application built with Express.js is super important for keeping tabs on what’s happening and fixing issues when they pop up. One great way to manage your logs is by combining morgan middleware and rotating-file-stream. This duo helps you store logs in rotating files so they stay organized and don’t grow endlessly.

First off, you’ll need to install both morgan and rotating-file-stream using npm. It’s as simple as running:

npm install morgan rotating-file-stream

Once you’ve got them installed, you can set up your Express app to use these modules.

Here’s a basic setup for logging requests into a file that rotates daily:

const express = require('express');
const morgan = require('morgan');
const rfs = require("rotating-file-stream");

const app = express();
const port = 3000;

// Create a rotating write stream
const accessLogStream = rfs.createStream("access.log", {
  interval: "1d", // rotate daily
  path: __dirname + "/log"
});

// Setup the logger
app.use(morgan("combined", { stream: accessLogStream }));

app.get('/', (req, res) => {
  res.send('hello, world!');
});

app.listen(port, () => {
  console.debug(`App listening on :${port}`);
});

In this example, rotating-file-stream creates a new log file every day, and morgan logs all requests in the Apache combined format to this rotating log stream.

If you want to customize your log format and add more details like the user’s IP or a unique request ID, you can do it this way:

const express = require('express');
const morgan = require('morgan');
const rfs = require("rotating-file-stream");
const uuid = require('node-uuid');

const app = express();
const port = 3000;

// Create a rotating write stream
const accessLogStream = rfs.createStream("access.log", {
  interval: "1d", // rotate daily
  path: __dirname + "/log"
});

// Define custom tokens
morgan.token('id', req => req.id);
morgan.token('ip', req => req.headers['x-forwarded-for'] || req.connection.remoteAddress);

// Assign a unique ID to each request
app.use((req, res, next) => {
  req.id = uuid.v4();
  next();
});

// Setup the logger with custom format
app.use(morgan(':id :ip ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"', { stream: accessLogStream }));

app.get('/', (req, res) => {
  res.send('hello, world!');
});

app.listen(port, () => {
  console.debug(`App listening on :${port}`);
});

In this setup, every log entry includes a unique request ID and the user’s IP address.

Sometimes you might need to rotate logs not just daily, but also based on size. This makes sure no single log file gets too big:

const express = require('express');
const morgan = require('morgan');
const rfs = require("rotating-file-stream");

const app = express();
const port = 3000;

// Create a rotating write stream based on size
const accessLogStream = rfs.createStream("access.log", {
  size: "10M", // rotate every 10MB written
  interval: "1d", // rotate daily
  compress: "gzip" // compress rotated files
});

// Setup the logger
app.use(morgan("combined", { stream: accessLogStream }));

app.get('/', (req, res) => {
  res.send('hello, world!');
});

app.listen(port, () => {
  console.debug(`App listening on :${port}`);
});

This way, logs will rotate daily and whenever the file size exceeds 10MB.

You can also make your logging setup more flexible using environment variables:

require('dotenv').config(); // load variables from .env file

const express = require('express');
const morgan = require('morgan');
const rfs = require("rotating-file-stream");

const app = express();
const port = 3000;

// Create a rotating write stream
const rfsStream = rfs.createStream(process.env.LOG_FILE || 'access.log', {
  size: process.env.LOG_SIZE || '10M',
  interval: process.env.LOG_INTERVAL || '1d',
  compress: 'gzip' // compress rotated files
});

// Setup the logger
const format = process.env.LOG_FORMAT || "dev";
app.use(morgan(format, { stream: rfsStream }));
app.use(morgan(format));

app.get('/', (req, res) => {
  res.send('hello, world!');
});

app.listen(port, () => {
  console.debug(`App listening on :${port}`);
});

This setup lets you control log file names, sizes, intervals, and formats using environment variables defined in a .env file.

Another handy feature is logging errors and successes separately. This way, you can easily track down issues without sifting through all other logs:

const express = require('express');
const morgan = require('morgan');
const rfs = require("rotating-file-stream");

const app = express();
const port = 3000;

// Create rotating write streams
const errorLogStream = rfs.createStream("error.log", {
  interval: "1d", // rotate daily
  path: __dirname + "/log"
});

const successLogStream = rfs.createStream("success.log", {
  interval: "1d", // rotate daily
  path: __dirname + "/log"
});

// Skip logic for error and success logs
const skipSuccess = (req, res) => res.statusCode < 400;
const skipError = (req, res) => res.statusCode >= 400;

// Setup the logger for errors
app.use(morgan("combined", { skip: skipSuccess, stream: errorLogStream }));

// Setup the logger for successes
app.use(morgan("combined", { skip: skipError, stream: successLogStream }));

app.get('/', (req, res) => {
  res.send('hello, world!');
});

app.listen(port, () => {
  console.debug(`App listening on :${port}`);
});

In this config, error responses (4xx and 5xx status codes) go into one file and successful responses into another.

At times, you might run into issues where log rotation doesn’t work as expected. A common fix for daily rotation issues is to ensure the file name generator is set up right:

const express = require('express');
const morgan = require('morgan');
const rfs = require("rotating-file-stream");
const path = require('path');
const { format } = require('date-fns');

const app = express();
const port = 3000;

function logFilename() {
  return `${format(new Date(), 'yyyy-MM-dd')}-access.log`;
}

const accessLogStream = rfs.createStream(logFilename(), {
  interval: "1d", // rotate daily
  path: path.resolve(__dirname, '..', 'log'),
});

// Setup the logger
app.use(morgan(':method :url :status :res[content-length] ":referrer" ":user-agent"', { stream: accessLogStream }));

app.get('/', (req, res) => {
  res.send('hello, world!');
});

app.listen(port, () => {
  console.debug(`App listening on :${port}`);
});

Here, the logFilename function makes sure the log file name includes the current date, which helps in daily rotation.

Combining morgan with rotating-file-stream provides a solid logging solution for your Express.js apps. You can customize your log formats, rotate logs by size or time, and even use environment variables to keep everything in check. This keeps your logs well-organized and easier to analyze, making debugging and monitoring a breeze.

Keywords: logging, Express.js, morgan middleware, rotating-file-stream, npm install, log rotation, daily logs, custom log format, environment variables, Express logging setup



Similar Posts
Blog Image
Unlock the Dark Side: React's Context API Makes Theming a Breeze

React's Context API simplifies dark mode and theming. It allows effortless state management across the app, enabling easy implementation of theme switching, persistence, accessibility options, and smooth transitions between themes.

Blog Image
JavaScript's Time Revolution: Temporal API Simplifies Date Handling and Boosts Accuracy

The Temporal API is a new JavaScript feature that simplifies date and time handling. It introduces intuitive types like PlainDateTime and ZonedDateTime, making it easier to work with dates, times, and time zones. The API also supports different calendar systems and provides better error handling. Overall, Temporal aims to make date-time operations in JavaScript more reliable and user-friendly.

Blog Image
Why Should Express.js APIs Have Their Own Versions?

Navigating the Labyrinth of Express.js API Versioning for Seamless Updates and Compatibility

Blog Image
Unleash React DevTools: Supercharge Your Debugging and Performance Skills Now!

React DevTools: Browser extension for debugging React apps. Offers component hierarchy view, real-time editing, performance profiling, and advanced debugging features. Essential for optimizing React applications.

Blog Image
Building a Full-Featured Chatbot with Node.js and NLP Libraries

Chatbots with Node.js and NLP libraries combine AI and coding skills. Natural library offers tokenization, stemming, and intent recognition. Sentiment analysis adds personality. Continuous improvement and ethical considerations are key for successful chatbot development.

Blog Image
Supercharge Your Node.js: Unleash Multi-Threading Power for Blazing Fast Apps

Node.js leverages multi-threading with worker threads for parallel processing, enhancing performance on multi-core systems. This enables efficient handling of CPU-intensive tasks and I/O operations, maximizing hardware utilization.