IDs de correlación de solicitudes
Rastrea una única solicitud de usuario a través de registros y servicios con x-request-id: acepta IDs entrantes, genera cuando faltan y reenvía a llamadas posteriores.
Busca en todas las páginas de la documentación
Rastrea una única solicitud de usuario a través de registros y servicios con x-request-id: acepta IDs entrantes, genera cuando faltan y reenvía a llamadas posteriores.
Tarjeta de receta de referencia rápida: lista para copiar y pegar.
import { randomUUID } from "node:crypto";
function getRequestId(header: string | string[] | undefined): string {
const raw = Array.isArray(header) ? header[0] : header;
return raw && raw.length <= 128 ? raw : randomUUID();
}
// Middleware
app.use((req, res, next) => {
const requestId = getRequestId(req.headers["x-request-id"]);
req.headers["x-request-id"] = requestId;
res.setHeader("x-request-id", requestId);
req.log = logger.child({ requestId });
next();
});Cuándo usarlo:
import express from "express";
import pino from "pino";
import { randomUUID } from "node:crypto";
const logger = pino({ level: "info" });
const app = express();
app.use(express.json());
app.use((req, res, next) => {
const incoming = req.headers["x-request-id"];
const requestId = typeof incoming === "string" && incoming.length <= 128
? incoming
: randomUUID();
res.setHeader("x-request-id", requestId);
(req as express.Request & { log: pino.Logger; requestId: string }).log =
logger.child({ requestId });
(req as express.Request & { requestId: string }).requestId = requestId;
req.log.info({ event: "request_start", method: req.method, path: req.path });
next();
});
async function fetchBillingProfile(requestId: string, userId: string) {
const res = await fetch(`https://billing.internal/users/${userId}`, {
headers: { "x-request-id": requestId },
signal: AbortSignal.timeout(3_000),
});
return res.json();
}
app.get("/users/:id/summary", async (req, res) => {
const billing = await fetchBillingProfile(req.requestId, req.params.id);
req.log.info({ event: "summary_built", billingStatus: billing.status });
res.json({ userId: req.params.id, billing });
});
app.listen(3000);Lo que esto demuestra:
x-request-id entrante se conserva cuando está presente y limitado (128 caracteres).fetch saliente reenvía el ID a los servicios internos.requestId a través del logger hijo.x-request-id primero.trace_id de OpenTelemetry puede coexistir; muchos equipos mapean x-request-id a la raíz de la traza o al equipaje.| Encabezado | Uso |
|---|---|
x-request-id | Estándar de facto para APIs HTTP |
traceparent | Contexto de traza W3C (OTel) |
x-correlation-id | Sistemas empresariales heredados |
Elige un ID principal en los logs; admite ambos encabezados en el borde durante la migración.
const app = Fastify({
genReqId: (req) => req.headers["x-request-id"] as string ?? randomUUID(),
requestIdHeader: "x-request-id",
requestIdLogLabel: "requestId",
});req.id y req.log incorporados: menos código repetitivo de middleware.await queue.add("send-email", payload, {
headers: { "x-request-id": req.requestId },
});res.setHeader("x-request-id", id).req.log.setImmediate pierde req. Solución: AsyncLocalStorage o captura el ID en el cierre.| Alternativa | Cuándo usar | Cuándo NO usar |
|---|---|---|
| x-request-id | Correlación de logs simple | Necesita el tiempo de padre/hijo de la traza |
| OpenTelemetry trace_id | Trazado distribuido completo | API MVP mínima |
| Encabezado de traza de AWS X-Ray | Pila nativa de AWS | Estándar OTel multi-nube |
| Encabezado personalizado por organización | Mandato empresarial heredado | API pública de campo verde |
Los ULID se pueden ordenar por tiempo, lo que es útil en los índices de logs. UUID v4 es universalmente reconocido. Cualquiera funciona si está documentado.
La puerta de enlace si está presente, consistente en todos los microservicios. La aplicación genera cuando la puerta de enlace no lo hace.
Registra ambos durante la migración de OTel: logger.child({ requestId, trace_id }) desde el contexto de la traza activa.
El mismo middleware: un ID por solicitud HTTP, independientemente del número de consultas.
El mismo x-request-id en todas las recuperaciones paralelas de una solicitud entrante. Las trazas secundarias se diferencian en OTel.
nestjs-pino admite genReqId. O middleware + CLS (almacenamiento local de continuación).
requestId:"abc-123" en Datadog/Loki: el campo debe ser una clave JSON de nivel superior en cada línea.
Todavía está bien generarlos, bajo volumen. O omitir el registro de estado por completo.
Versiones de la pila: Esta página fue escrita para Node.js 24.18.0 (LTS activo), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 y NestJS 11.
Revisado por Chris St. John·Última actualización: 19 jul 2026