Unreleased changes
These pages document main, which has changes 2.1.1 does not. npm install @evanion/nestjs-correlation-id gives you 2.1.1, documented here. Values on these pages are produced by running the current source on every build.
@evanion/nestjs-correlation-id
To follow one order through Baize, the board game shop these pages use, you
search the logs of storefront, orders and stock.
@evanion/nestjs-correlation-id gives each request one id that every NestJS
service it reaches puts in its own log lines.
How one correlation id crosses services
In @evanion/nestjs-correlation-id, a correlation id is a string that names one
request in every service the request reaches. CorrelationService is the
provider that holds the current id, in Node’s
AsyncLocalStorage.
A correlation context is the scope that CorrelationService.run(id, callback)
opens: the callback and everything it calls or awaits. Inside that scope, the
service’s getCorrelationId() method returns id.
The code below opens two contexts by hand, with a different id in each, and runs one handler in both at once. The handler awaits and then reads the id, and each run gets its own context’s id back:
import { } from '@evanion/nestjs-correlation-id';
// In an application Nest builds the service, and you inject it. Built by hand
// it takes a configuration object. The service calls only its generator, and
// the header is there because the configuration's type requires one.
const = new ({
: 'X-Correlation-Id',
: () => .(),
});
// A handler that awaits before it reads the id, as a database call would.
const = async () => {
await new (() => (, 5));
return .();
};
const [, ] = await .([
.('storefront-4f1c9a', ),
.('storefront-9d2e71', ),
]);
; // -> 'storefront-4f1c9a'
; // -> 'storefront-9d2e71'
.(); // -> undefinedOutside both contexts getCorrelationId() returns undefined, because no
context is open there. In an application CorrelationIdMiddleware opens the
context for each request, so a handler only reads the id.
CorrelationIdMiddleware reads the id from the X-Correlation-Id header and
reuses it when it passes a format check. When the header is missing or fails the
check, the middleware generates a new id. It sets the same header on the
response.
A hop is one call from a service to the next, such as orders asking stock
for a game’s stock level. withCorrelation() configures HttpModule from
@nestjs/axios so that every hop through HttpService carries the id, and the
next service’s middleware reuses it:
What nestjs-correlation-id provides
Every application uses these @evanion/nestjs-correlation-id exports:
| Export | What it does |
|---|---|
CorrelationModule | provides CorrelationService and its configuration (header, generator, format check) to every module |
CorrelationIdMiddleware | opens a correlation context per request and sets the id on the response |
CorrelationService | reads and generates the id, and opens a context for work with no request |
withCorrelation() | HttpModule.registerAsync options that send the id on every call |
DEFAULT_CORRELATION_ID_VALIDATOR | the format check an incoming header passes before the middleware reuses it |
A queue consumer or a cron job has no request behind it, so it opens its own
context with CorrelationService.run().
What nestjs-correlation-id leaves to you
@evanion/nestjs-correlation-id carries the id and stops there:
- It writes no log line. Your logger injects
CorrelationService, callsgetCorrelationId()and adds the value to its own output. - It reads one header,
X-Correlation-Idunless you configure another. There is no list of fallback header names. - It forwards the id on
HttpServicecalls whose module usedwithCorrelation(). Afetchcall or a queue message carries the id only when your code puts it there. - It records no spans and no timings. A tracer such as OpenTelemetry does that, and can run beside it.
Put an id on every request
You have seen @evanion/nestjs-correlation-id carry one id through awaits and
across a hop. Getting started installs it, registers
CorrelationModule and CorrelationIdMiddleware in your application, and has a
handler read the id a caller sent.