Skip to main content

Function Signature

const logger = (options?: ApiLoggerOptions) => (req: Request, res: Response, next: NextFunction) => void

Description

The logger function is the main Express middleware for comprehensive API request and response logging. It captures detailed information about HTTP requests and responses including method, URL, status code, response time, request/response sizes, headers, query parameters, bodies, and IP information.

Parameters

options
ApiLoggerOptions
default:"{}"
Configuration options for the logger middleware. See ApiLoggerOptions for detailed documentation of all available options.

Returns

middleware
(req: Request, res: Response, next: NextFunction) => void
An Express middleware function that can be used with app.use() or route-specific handlers.

Basic Usage

import express from 'express';
import logger from 'http-ledger-express';

const app = express();

// Use with default options
app.use(logger());

// Your routes
app.get('/api/users', (req, res) => {
  res.json({ users: [] });
});

app.listen(3000);

Advanced Usage

Custom Logging Options

import logger from 'http-ledger-express';

app.use(logger({
  logBody: true,
  logResponse: true,
  logQueryParams: true,
  excludedHeaders: ['authorization', 'cookie'],
  maskFields: ['password', 'token', 'apiKey']
}));

With IP Geolocation

import logger from 'http-ledger-express';
import geoip from 'geoip-lite';

app.use(logger({
  getIpInfo: async (ip: string) => {
    const geo = geoip.lookup(ip);
    return {
      ip,
      country: geo?.country,
      region: geo?.region,
      city: geo?.city,
      timezone: geo?.timezone
    };
  }
}));

Custom Log Handling

import logger from 'http-ledger-express';
import { sendToAnalytics } from './analytics';

app.use(logger({
  onLog: async (logData) => {
    // Send to external analytics service
    await sendToAnalytics(logData);
    
    // Store in database
    await db.logs.insert(logData);
  }
}));

Conditional Logging

import logger from 'http-ledger-express';

app.use(logger({
  // Only log errors and slow requests
  shouldLog: (req, res) => {
    return res.statusCode >= 400 || res.getHeader('X-Response-Time') > 1000;
  },
  
  // Sample 10% of requests
  logSampling: 0.1
}));

Custom Log Levels and Formatting

import logger from 'http-ledger-express';

app.use(logger({
  customLogLevel: (logData) => {
    if (logData.error) return 'error';
    if (logData.statusCode >= 400) return 'warn';
    return 'info';
  },
  
  customFormatter: (logData) => {
    return {
      ...logData,
      environment: process.env.NODE_ENV,
      appVersion: process.env.APP_VERSION,
      timestamp: new Date().toISOString()
    };
  }
}));

Auto-Generate Request IDs

import logger from 'http-ledger-express';

app.use(logger({
  autoGenerateRequestId: true
}));

// Request ID will be added to response headers as 'X-Request-ID'
// and included in log data

Default Options

When no options are provided, the logger uses these defaults:
{
  logBody: true,
  logResponse: true,
  logQueryParams: true,
  excludedHeaders: []
}

Output Format

The middleware logs data in JSON format with the following structure. See LogData for complete documentation:
{
  "method": "GET",
  "url": "/api/users",
  "statusCode": 200,
  "timeTaken": 45.23,
  "requestSize": 0,
  "responseSize": 1024,
  "timestamp": {
    "request": "2024-03-20T10:30:00.000Z",
    "response": "2024-03-20T10:30:00.045Z"
  },
  "headers": {
    "user-agent": "Mozilla/5.0...",
    "accept": "application/json"
  },
  "queryParams": {},
  "responseBody": { "users": [] },
  "userAgent": "Mozilla/5.0...",
  "httpVersion": "1.1",
  "hostname": "localhost",
  "logLevel": "info"
}

Behavior

Response Capture

The middleware intercepts res.send() and res.end() to capture response bodies and timing information without interfering with normal response flow.

Event Listeners

Logs are emitted on these response events:
  • finish - Normal completion
  • close - Connection closed
  • error - Response error occurred
Logs are only emitted once, even if multiple events fire.

Error Handling

The middleware is designed to never break your application:
  • Errors in custom functions (getIpInfo, onLog, customFormatter, etc.) are caught and logged as warnings
  • If the main logging fails, a fallback error log is emitted with basic request information
  • The middleware always calls next() to continue the request chain

Header Normalization

Excluded headers are normalized to lowercase for case-insensitive matching:
logger({
  excludedHeaders: ['Authorization', 'COOKIE', 'X-Api-Key']
})
// Matches: 'authorization', 'cookie', 'x-api-key' (case-insensitive)

Performance Considerations

Sampling

For high-traffic applications, use sampling to reduce overhead:
logger({ logSampling: 0.1 }) // Log 10% of requests

Conditional Logging

Skip logging for health checks and static assets:
logger({
  shouldLog: (req, res) => {
    return !req.url.startsWith('/health') && 
           !req.url.startsWith('/static');
  }
})

Disable Body Logging

For large payloads, consider disabling body logging:
logger({
  logBody: false,
  logResponse: false
})

See Also

Build docs developers (and LLMs) love