When debugging an issue in your applications logs, it helps to be able to follow a specific request up and down your whole stack. This is usually done by including a correlation-id
(aka Request-id
) header in all your requests, and forwarding the same id across all your microservices.
yarn add @evanion/nestjs-correlation-id
npm install @evanion/nestjs-correlation-id
Add the middleware to your AppModule
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import {
CorrelationIdMiddleware,
CorrelationModule,
} from '@evanion/nestjs-correlation-id';
@Module({
imports: [CorrelationModule.forRoot()],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(CorrelationIdMiddleware).forRoutes('*');
}
}
And then just inject the correlation middleware in your HttpService by calling the registerAsync
method with the withCorrelation
function.
import { HttpModule } from '@nestjs/axios';
import { withCorrelation } from '@evanion/nestjs-correlation-id';
@Module({
imports: [HttpModule.registerAsync(withCorrelation())],
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}
You can now use the HttpService
as usual in your UsersService
and UsersController
You can easily customize the header and ID by including a config when you register the module
@Module({
imports: [CorrelationModule.forRoot({
header: string
generator: () => string
})]
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(CorrelationIdMiddleware).forRoutes('*');
}
}
In order to add the correlation ID to your logs, you can use the CorrelationService
service to get the current correlationId.
In the following example, we are using the @ntegral/nestjs-sentry package, but you can use any package or provider you like.
import { CorrelationService } from '@evanion/nestjs-correlation-id';
import { Injectable, NestMiddleware } from '@nestjs/common';
import { InjectSentry, SentryService } from '@ntegral/nestjs-sentry';
import { NextFunction, Request, Response } from 'express';
@Injectable()
export class SentryMiddleware implements NestMiddleware {
constructor(
private readonly correlationService: CorrelationService,
@InjectSentry() private readonly sentryService: SentryService,
) {}
async use(_req: Request, _res: Response, next: NextFunction) {
const correlationId = await this.correlationService.getCorrelationId();
this.sentryService.instance().configureScope((scope) => {
scope.setTag('correlationId', correlationId);
});
next();
}
}
Then add it to your AppModule
import { Module } from '@nestjs-common';
import { SentryModule } from '@ntegral/nestjs-sentry';
import { CorrelationModule } from '@evanion/nestjs-correlation-id';
import { SentryMiddleware } from './middleware/sentry.middleware';
@Module({
imports: [
CorrelationModule.forRoot(),
SentryModule.forRoot({
// ... your config
}),
],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(CorrelationIdMiddleware).forRoutes('*');
consumer.apply(SentryMiddleware).forRoutes('*');
}
}
If you need to manually set the correlationId anywhere in your application. You can use the CorrelationService
service to set the correlationId.
this.correlationService.setCorrelationId('some_correlation_id');
see e2e tests for a fully working example
See Changelog for more information.
Contributions welcome! See Contributing.
Mikael Pettersson (Evanion on Discord)
Licensed under the MIT License - see the LICENSE file for details.