Express Request/Response Logger
raw JSON →express-requests-logger is an Express middleware designed for comprehensive logging of incoming HTTP requests and outgoing responses within Node.js applications. The current stable version is 4.0.3, with v4.0.1 released in August 2024, indicating active maintenance though its release cadence can be somewhat irregular. A key differentiator is its extensive configuration options, allowing developers to precisely control what data is logged. This includes masking or excluding sensitive fields from request and response bodies, headers, and query parameters. It also supports integration with custom loggers, although it's primarily tested with Bunyan, and offers a `shouldSkipAuditFunc` for dynamic conditional logging. The `doubleAudit` feature provides flexibility for logging requests both upon arrival and after the response is sent, which can be crucial for debugging systems prone to crashes during request processing.
Common errors
error TypeError: audit is not a function ↓
import audit from 'express-requests-logger';. For CommonJS, use const audit = require('express-requests-logger');. error Error: logger.info is not a function ↓
logger option is correctly initialized and exposes an info method, as demonstrated with bunyan.createLogger() in the quickstart example. error Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client ↓
res.send(), res.json(), or res.end() has already been called. Always return or use next() after sending a response if subsequent middleware should not execute. Warnings
breaking The log message level for HTTP 5xx status codes has been changed from 'info' to 'ERROR'. This means that server-side errors will now be categorized at a higher severity level in your logs. ↓
breaking Official support for Node.js versions 14 and below has been removed. Running `express-requests-logger` on these older Node.js runtimes is no longer officially supported and may lead to unexpected behavior, compatibility issues, or unpatched vulnerabilities. ↓
gotcha The `logger` option expects an object with an `info` method that accepts a single object argument for structured logging. While primarily tested with Bunyan, custom loggers must conform to this interface. ↓
gotcha Enabling `doubleAudit: true` causes each request and its corresponding response to be logged twice: once when the request arrives and again after the response is sent. This can significantly increase log volume. ↓
Install
npm install express-requests-logger yarn add express-requests-logger pnpm add express-requests-logger Imports
- audit wrong
import { audit } from 'express-requests-logger';correctimport audit from 'express-requests-logger'; - audit wrong
const { audit } = require('express-requests-logger');correctconst audit = require('express-requests-logger'); - middleware options wrong
app.use(audit(myLogger, { request: { maskBody: ['password'] } }));correctapp.use(audit({ logger: myLogger, request: { maskBody: ['password'] } }));
Quickstart
import express from 'express';
import audit from 'express-requests-logger';
import bunyan from 'bunyan';
const app = express();
const port = 3000;
// Initialize a Bunyan logger for structured logging
const logger = bunyan.createLogger({
name: 'my-express-app',
level: 'info' // Set default log level
});
// Add express.json() middleware to parse JSON request bodies
app.use(express.json());
// Apply the express-requests-logger middleware
app.use(audit({
logger: logger, // Provide the initialized logger
doubleAudit: true, // Log once on request arrival, and again after response is sent
excludeURLs: ['/health'], // URLs to entirely skip logging for
request: {
maskBody: ['password', 'creditCardNumber'], // Mask sensitive fields in the request body
excludeHeaders: ['authorization'] // Exclude 'Authorization' header from logs
},
response: {
maskBody: ['jwtToken'], // Mask sensitive fields in the response body
maxBodyLength: 200 // Limit the length of logged response body content
},
shouldSkipAuditFunc: (req, res) => {
// Example: Skip logging successful responses to /data
return req.path === '/data' && res.statusCode === 200;
}
}));
// Define a simple root route
app.get('/', (req, res) => {
logger.info('Received request for root path.');
res.status(200).send('Welcome to the API!');
});
// Define a login route to demonstrate body masking
app.post('/login', (req, res) => {
logger.info('Attempting user login.');
const { username, password } = req.body;
if (username === 'test' && password === 'secret') {
res.status(200).json({ message: 'Login successful', jwtToken: 'a.b.c.123' });
} else {
res.status(401).json({ message: 'Invalid credentials' });
}
});
// Define a health check route (will be excluded from logs)
app.get('/health', (req, res) => {
res.status(200).send('API is healthy');
});
// Start the Express server
app.listen(port, () => {
logger.info(`Server listening on port ${port}`);
});