Skip to main content

Overview

Request tracking allows you to trace requests through your system using unique request IDs. This is essential for debugging distributed systems, correlating logs across services, and tracking user journeys through your application.

autoGenerateRequestId

autoGenerateRequestId
boolean
default:"false"
Whether to automatically generate a request ID if the X-Request-ID header is not present in the incoming request.

Basic Usage

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

How It Works

When autoGenerateRequestId is enabled:
  1. HTTP Ledger checks for an existing X-Request-ID header in the incoming request
  2. If not found, it generates a UUID v4 request ID
  3. The request ID is added to the response headers as X-Request-ID
  4. The request ID is included in the log output
Implementation (from src/utils/advancedFeatures.ts:18-31):
export const addRequestIdToResponse = (
  req: Request,
  res: Response,
  autoGenerateRequestId: boolean,
): string | undefined => {
  let requestId = req.headers['x-request-id'] as string;

  if (!requestId && autoGenerateRequestId) {
    requestId = generateRequestId();
    res.setHeader('X-Request-ID', requestId);
  }

  return requestId;
};

Request ID Format

Generated request IDs are UUID v4 format:
550e8400-e29b-41d4-a716-446655440000
UUID v4 provides excellent uniqueness guarantees with 122 random bits, making collisions extremely unlikely.

Example Log Output

With autoGenerateRequestId: true:
{
  "method": "POST",
  "url": "/api/users",
  "statusCode": 201,
  "timeTaken": 45.23,
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": {
    "request": "2024-01-01T12:00:00.000Z",
    "response": "2024-01-01T12:00:00.045Z"
  }
}

Using Existing Request IDs

If your API gateway or load balancer already adds request IDs, HTTP Ledger will use them:
# Request with existing X-Request-ID header
curl -H "X-Request-ID: custom-id-12345" https://api.example.com/users
{
  "method": "GET",
  "url": "/users",
  "requestId": "custom-id-12345",
  "timeTaken": 23.45
}
HTTP Ledger respects existing X-Request-ID headers and only generates new IDs when the header is missing and autoGenerateRequestId is enabled.

Distributed Tracing

Request IDs enable tracing across multiple services:
1

API Gateway adds request ID

// API Gateway
app.use((req, res, next) => {
  if (!req.headers['x-request-id']) {
    req.headers['x-request-id'] = generateUUID();
  }
  next();
});
2

Service A logs with request ID

// Service A - User Service
app.use(logger({
  autoGenerateRequestId: false // Use existing ID from gateway
}));
3

Service A forwards request ID to Service B

// Service A makes request to Service B
const response = await fetch('https://service-b/api/data', {
  headers: {
    'X-Request-ID': req.headers['x-request-id']
  }
});
4

Service B logs with same request ID

// Service B - Payment Service
app.use(logger({
  autoGenerateRequestId: false
}));
Now all logs across both services share the same request ID for correlation.

Request Propagation Pattern

Create a utility to propagate request IDs:
// utils/requestId.js
const asyncLocalStorage = require('async_hooks').AsyncLocalStorage;
const storage = new asyncLocalStorage();

// Middleware to store request ID in async context
function requestIdMiddleware(req, res, next) {
  const requestId = req.headers['x-request-id'] || generateUUID();
  res.setHeader('X-Request-ID', requestId);
  
  storage.run({ requestId }, () => {
    next();
  });
}

// Get current request ID anywhere in the request lifecycle
function getCurrentRequestId() {
  const store = storage.getStore();
  return store?.requestId;
}

module.exports = { requestIdMiddleware, getCurrentRequestId };
Use in your application:
const express = require('express');
const logger = require('http-ledger');
const { requestIdMiddleware, getCurrentRequestId } = require('./utils/requestId');

const app = express();

// Add request ID to async context first
app.use(requestIdMiddleware);

// Then add HTTP Ledger
app.use(logger({
  autoGenerateRequestId: false // We're handling it in requestIdMiddleware
}));

// Use request ID anywhere
app.post('/api/orders', async (req, res) => {
  const requestId = getCurrentRequestId();
  
  // Include in external API calls
  await fetch('https://payment-api/charge', {
    headers: {
      'X-Request-ID': requestId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(req.body)
  });
  
  res.json({ success: true });
});

Client-Side Request Tracking

Generate request IDs on the client side for end-to-end tracing:
// Frontend code
function makeApiRequest(url, options = {}) {
  const requestId = crypto.randomUUID();
  
  return fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      'X-Request-ID': requestId
    }
  }).then(response => {
    // Store request ID for debugging
    console.log(`Request ${requestId} completed:`, response.status);
    return response;
  });
}

Integration with APM Tools

Combine request IDs with Application Performance Monitoring:
const newrelic = require('newrelic');

app.use(logger({
  autoGenerateRequestId: true,
  
  customFormatter: (logData) => ({
    ...logData,
    // Add New Relic trace ID
    traceId: newrelic.getTransaction()?.traceId,
    requestId: logData.requestId
  })
}));

Example: Production Configuration

// For microservices: use existing request IDs from gateway
app.use(logger({
  autoGenerateRequestId: false, // Gateway provides IDs
  
  customFormatter: (logData) => ({
    ...logData,
    service: process.env.SERVICE_NAME,
    environment: process.env.NODE_ENV
  })
}));

Querying Logs by Request ID

With request IDs in your logs, you can easily trace complete request flows:
# Query all logs for a specific request
grep "550e8400-e29b-41d4-a716-446655440000" application.log

# In Elasticsearch
GET /logs/_search
{
  "query": {
    "match": {
      "requestId": "550e8400-e29b-41d4-a716-446655440000"
    }
  }
}

# In CloudWatch Logs
filter @requestId = "550e8400-e29b-41d4-a716-446655440000"

Best Practices

Always Use in Production

Enable request ID generation in production for debugging and support

Propagate Across Services

Forward X-Request-ID headers to downstream services

Include in Error Reports

Add request IDs to error messages for easier debugging

Index in Logging Systems

Make requestId a searchable field in your logging platform

External Integrations

Send logs with request IDs to external services

Custom Logging

Add custom fields alongside request IDs

Build docs developers (and LLMs) love