Skip to main content

correlation-id-tracking

Manages correlation-id in Node.js/TypeScript applications using AsyncLocalStorage for async context isolation. Use when implementing correlation-id tracking, HTTP request/response correlation, logging integration, or when working with distributed tracing in Node.js applications.

Zur Installation springen

Quellinformationen

Repository
whitebeardit/.cursor
Letzte Quellaktivität
31. Januar 2026 um 23:09
Erkannte Sprache von SKILL.md
Englisch
Sterne
12
Forks
6

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
correlation-id-tracking
description
Manages correlation-id in Node.js/TypeScript applications using AsyncLocalStorage for async context isolation. Use when implementing correlation-id tracking, HTTP request/response correlation, logging integration, or when working with distributed tracing in Node.js applications.
# Correlation-ID Tracking for Node.js This skill helps you implement correlation-id tracking in Node.js/TypeScript applications using AsyncLocalStorage for async context preservation. ## Installation ```bash npm install async-local-storage # or yarn add async-local-storage ``` ## Quick Setup ### Express.js - Zero Configuration **Minimal setup:** ```typescript import express from 'express'; import { correlationIdMiddleware } from './middleware/correlation-id'; const app = express(); // Add correlation-ID middleware (must be first) app.use(correlationIdMiddleware); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.get('/api/test', (req, res) => { const correlationId = getCorrelationId(); res.json({ correlationId }); }); app.listen(3000); ``` ### Correlation-ID Middleware ```typescript import { Request, Response, NextFunction } from 'express'; import { AsyncLocalStorage } from 'async_hooks'; const correlationStorage = new AsyncLocalStorage<string>(); export function getCorrelationId(): string { return correlationStorage.getStore() || generateCorrelationId(); } export function setCorrelationId(id: string): void { correlationStorage.enterWith(id); } function generateCorrelationId(): string { return crypto.randomUUID().replace(/-/g, ''); } export function correlationIdMiddleware( req: Request, res: Response, next: NextFunction ): void { const correlationId = req.headers['x-correlation-id'] as string || generateCorrelationId(); correlationStorage.run(correlationId, () => { res.setHeader('X-Correlation-Id', correlationId); next(); }); } ``` ## Using Correlation-ID in Code ### In Controllers ```typescript import { Request, Response } from 'express'; import { getCorrelationId } from '../middleware/correlation-id'; export async function getOrder(req: Request, res: Response) { const correlationId = getCorrelationId(); try { const order = await orderService.getById(req.params.id); res.json({ order, correlationId }); } catch (error) { res.status(500).json({ error: 'Failed to get order', correlationId }); } } ``` ### In Services ```typescript import { getCorrelationId } from '../middleware/correlation-id'; import logger from '../logger'; export class OrderService { async getById(id: string) { const correlationId = getCorrelationId(); logger.info('Getting order', { orderId: id, correlationId }); // Your business logic here return order; } } ``` ## HTTP Client Integration ### Axios Interceptor ```typescript import axios from 'axios'; import { getCorrelationId } from './middleware/correlation-id'; // Add request interceptor axios.interceptors.request.use((config) => { const correlationId = getCorrelationId(); if (correlationId) { config.headers['X-Correlation-Id'] = correlationId; } return config; }); ``` ### Fetch Wrapper ```typescript import { getCorrelationId } from './middleware/correlation-id'; export async function fetchWithCorrelationId( url: string, options?: RequestInit ): Promise<Response> { const correlationId = getCorrelationId(); const headers = { ...options?.headers, 'X-Correlation-Id': correlationId || '', }; return fetch(url, { ...options, headers }); } ``` ## Logging Integration ### Winston Logger ```typescript import winston from 'winston'; import { getCorrelationId } from './middleware/correlation-id'; const logger = winston.createLogger({ format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json() ), defaultMeta: { get correlationId() { return getCorrelationId(); }, }, transports: [ new winston.transports.Console({ format: winston.format.simple(), }), ], }); // Usage logger.info('Processing order', { orderId: '123' }); // Automatically includes correlationId in metadata ``` ### Pino Logger ```typescript import pino from 'pino'; import { getCorrelationId } from './middleware/correlation-id'; const logger = pino({ mixin() { return { correlationId: getCorrelationId(), }; }, }); // Usage logger.info({ orderId: '123' }, 'Processing order'); // Automatically includes correlationId ``` ## Logging Best Practices ### Log Levels: When to Use Each **DEBUG** - Development and troubleshooting only: - Detailed execution flow - Variable values and intermediate states - Step-by-step process information - **Not visible in production** (typically filtered out) **INFO** - Production-ready, important events: - Request start/completion - Business operations (create, update, delete) - External API calls (start/end) - Important state changes - **Visible in production** **WARNING** - Potential issues that don't break functionality: - Retry attempts - Fallback to default values - Deprecated API usage - Performance degradation **ERROR** - Failures that need attention: - Exceptions and errors - Failed operations - External service failures ### What to Log (and What NOT to Log) **✅ DO Log:** - Request identifiers (correlation-ID, user ID, request ID) - Business operations (what happened) - External service calls (start, end, duration) - Important state changes - Errors with context (correlation-ID, user, operation) **❌ DON'T Log:** - Sensitive data (passwords, tokens, PII, credit cards) - Large payloads (use summaries instead) - Every iteration in loops (log once per operation) - Redundant information (correlation-ID is already in context) - Excessive detail in production (use DEBUG for that) ### Structured Logging with Correlation-ID Always include correlation-ID in logs for traceability: ```typescript // ✅ Good: Structured logging with correlation-ID logger.info('Processing order', { orderId: orderId, userId: userId, correlationId: getCorrelationId(), }); // ✅ Good: Using structured properties logger.info('External API call completed', { endpoint: endpoint, duration: duration, statusCode: statusCode, correlationId: getCorrelationId(), }); // ❌ Bad: Logging without correlation-ID context logger.info(`Processing order ${orderId}`); // Missing correlation-ID! // ❌ Bad: Logging sensitive data logger.info(`User password: ${password}`); // NEVER log passwords! ``` ### Logging Patterns for Debugging **Pattern 1: Request Lifecycle** ```typescript export async function getOrder(req: Request, res: Response) { const correlationId = getCorrelationId(); // ✅ INFO: Request start (production-visible) logger.info('Getting order', { orderId: req.params.id, correlationId }); try { // ✅ DEBUG: Detailed steps (development only) logger.debug('Querying database for order', { orderId: req.params.id, correlationId }); const order = await orderRepository.findById(req.params.id); if (!order) { // ✅ WARNING: Expected but notable condition logger.warn('Order not found', { orderId: req.params.id, correlationId }); return res.status(404).json({ error: 'Order not found' }); } // ✅ INFO: Successful completion (production-visible) logger.info('Order retrieved successfully', { orderId: req.params.id, correlationId }); res.json(order); } catch (error) { // ✅ ERROR: Always log exceptions with correlation-ID logger.error(error, 'Error retrieving order', { orderId: req.params.id, correlationId }); res.status(500).json({ error: 'Internal server error' }); } } ``` **Pattern 2: External Service Calls** ```typescript export async function processPayment(request: PaymentRequest) { const correlationId = getCorrelationId(); // ✅ INFO: External call start (production-visible) logger.info('Calling payment service', { amount: request.amount, currency: request.currency, correlationId, }); const startTime = Date.now(); try { const response = await paymentClient.process(request); const duration = Date.now() - startTime; // ✅ INFO: Success with duration (production-visible) logger.info('Payment service call completed', { status: response.status, duration, correlationId, }); return response; } catch (error) { const duration = Date.now() - startTime; // ✅ ERROR: Failure with context (production-visible) logger.error(error, 'Payment service call failed', { duration, correlationId, }); throw error; } } ``` **Pattern 3: Conditional Debug Logging** ```typescript export async function processItems(items: Item[]) { const correlationId = getCorrelationId(); // ✅ INFO: Operation start (production-visible) logger.info('Processing items', { count: items.length, correlationId, }); for (let i = 0; i < items.length; i++) { // ✅ DEBUG: Detailed per-item info (development only) logger.debug('Processing item', { index: i + 1, total: items.length, itemId: items[i].id, correlationId, }); await processItem(items[i]); } // ✅ INFO: Operation completion (production-visible) logger.info('Processed items successfully', { count: items.length, correlationId, }); } ``` ## Key Features 1. **AsyncLocalStorage**: Uses Node.js `async_hooks` AsyncLocalStorage for context preservation 2. **Automatic Propagation**: HTTP clients automatically include correlation-ID in headers 3. **Logging Integration**: Works with Winston, Pino, and other loggers 4. **Framework Support**: Works with Express, Fastify, NestJS, and other frameworks 5. **Header-Based**: Uses `X-Correlation-Id` header for HTTP propagation ## Important Notes - **UUID Format**: Correlation-IDs are typically 32-character UUIDs without hyphens - **Never Overwrites**: If correlation-ID exists (from headers), it's preserved - **Independent from OpenTelemetry**: Correlation-ID is separate from trace context - both can coexist - **Thread-Safe**: AsyncLocalStorage is safe for concurrent async operations ## Common Patterns ### Pattern 1: Reading Correlation-ID from Request The middleware automatically: 1. Reads `X-Correlation-Id` from incoming request headers 2. If present, uses that value 3. If missing, generates new UUID (32 chars, no hyphens) 4. Sets AsyncLocalStorage context 5. Adds to response headers ### Pattern 2: Preserving Across Async Operations ```typescript const correlationId = getCorrelationId(); // "abc123" await someAsyncMethod(); const sameId = getCorrelationId(); // Still "abc123" - preserved! ``` ### Pattern 3: Manual Propagation ```typescript // Set correlation-ID from external source setCorrelationId(externalCorrelationId); // Now all operations use this correlation-ID await processRequest(); ``` ## Key Principles 1. **Correlation-ID Always**: Every log should include correlation-ID 2. **Structured Properties**: Use structured logging with named properties, not string interpolation 3. **Context Matters**: Include relevant context (user ID, operation, IDs) but not sensitive data 4. **Level Appropriately**: Use DEBUG for detailed troubleshooting, INFO for production visibility 5. **Performance Aware**: Don't log in tight loops; summarize instead 6. **Error Context**: Always include correlation-ID and relevant context in error logs
Auf GitHub ansehen