feat(server): enable cls plugin to store request id (#9758)

POC
This commit is contained in:
fengmk2
2025-01-20 10:00:21 +00:00
parent fa5e6e1f45
commit 2ae05c28b7
7 changed files with 70 additions and 4 deletions
+1
View File
@@ -76,6 +76,7 @@
"nanoid": "^5.0.9", "nanoid": "^5.0.9",
"nest-commander": "^3.15.0", "nest-commander": "^3.15.0",
"nest-winston": "^1.9.7", "nest-winston": "^1.9.7",
"nestjs-cls": "^4.5.0",
"nestjs-throttler-storage-redis": "^0.5.1", "nestjs-throttler-storage-redis": "^0.5.1",
"nodemailer": "^6.9.16", "nodemailer": "^6.9.16",
"on-headers": "^1.0.2", "on-headers": "^1.0.2",
+14
View File
@@ -1,3 +1,5 @@
import { randomUUID } from 'node:crypto';
import { import {
DynamicModule, DynamicModule,
ForwardReference, ForwardReference,
@@ -6,6 +8,7 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule'; import { ScheduleModule } from '@nestjs/schedule';
import { get } from 'lodash-es'; import { get } from 'lodash-es';
import { ClsModule } from 'nestjs-cls';
import { AppController } from './app.controller'; import { AppController } from './app.controller';
import { getOptionalModuleMetadata } from './base'; import { getOptionalModuleMetadata } from './base';
@@ -42,6 +45,17 @@ import { REGISTERED_PLUGINS } from './plugins';
import { ENABLED_PLUGINS } from './plugins/registry'; import { ENABLED_PLUGINS } from './plugins/registry';
export const FunctionalityModules = [ export const FunctionalityModules = [
ClsModule.forRoot({
global: true,
middleware: {
mount: true,
generateId: true,
idGenerator() {
// make every request has a unique id to tracing
return randomUUID();
},
},
}),
ConfigModule.forRoot(), ConfigModule.forRoot(),
RuntimeModule, RuntimeModule,
EventModule, EventModule,
+2
View File
@@ -12,6 +12,7 @@ import {
import { SocketIoAdapter } from './base/websocket'; import { SocketIoAdapter } from './base/websocket';
import { AuthGuard } from './core/auth'; import { AuthGuard } from './core/auth';
import { ENABLED_FEATURES } from './core/config/server-feature'; import { ENABLED_FEATURES } from './core/config/server-feature';
import { responseRequestIdHeader } from './middleware/request-id';
import { serverTimingAndCache } from './middleware/timing'; import { serverTimingAndCache } from './middleware/timing';
export async function createApp() { export async function createApp() {
@@ -31,6 +32,7 @@ export async function createApp() {
} }
app.use(serverTimingAndCache); app.use(serverTimingAndCache);
app.use(responseRequestIdHeader);
app.use( app.use(
graphqlUploadExpress({ graphqlUploadExpress({
@@ -1,6 +1,20 @@
import { ConsoleLogger, Injectable } from '@nestjs/common'; import { ConsoleLogger, Injectable, type LogLevel } from '@nestjs/common';
import { ClsServiceManager } from 'nestjs-cls';
// DO NOT use this Logger directly // DO NOT use this Logger directly
// Use it via this way: `private readonly logger = new Logger(MyService.name)` // Use it via this way: `private readonly logger = new Logger(MyService.name)`
@Injectable() @Injectable()
export class AFFiNELogger extends ConsoleLogger {} export class AFFiNELogger extends ConsoleLogger {
override stringifyMessage(message: unknown, logLevel: LogLevel) {
const messageString = super.stringifyMessage(message, logLevel);
const requestId = AFFiNELogger.getRequestId();
if (!requestId) {
return messageString;
}
return `<${requestId}> ${messageString}`;
}
static getRequestId(): string | undefined {
return ClsServiceManager.getClsService()?.getId();
}
}
@@ -0,0 +1,16 @@
import { NextFunction, Request, Response } from 'express';
import { ClsServiceManager } from 'nestjs-cls';
import onHeaders from 'on-headers';
export const responseRequestIdHeader = (
_req: Request,
res: Response,
next: NextFunction
) => {
onHeaders(res, () => {
const requestId = ClsServiceManager.getClsService().getId();
res.setHeader('X-Request-Id', requestId);
});
next();
};
@@ -1,22 +1,28 @@
import { LoggingWinston } from '@google-cloud/logging-winston'; import { LoggingWinston } from '@google-cloud/logging-winston';
import { LoggerService, Provider } from '@nestjs/common'; import { LoggerService, Provider } from '@nestjs/common';
import { createLogger, transports } from 'winston'; import { createLogger, format, transports } from 'winston';
import { AFFiNELogger as LoggerProvide } from '../../../base/logger'; import { AFFiNELogger as LoggerProvide } from '../../../base/logger';
import { AFFiNELogger } from './logger'; import { AFFiNELogger } from './logger';
const moreMetadata = format(info => {
info.requestId = LoggerProvide.getRequestId();
return info;
});
export const loggerProvider: Provider<LoggerService> = { export const loggerProvider: Provider<LoggerService> = {
provide: LoggerProvide, provide: LoggerProvide,
useFactory: () => { useFactory: () => {
const loggingWinston = new LoggingWinston(); const loggingWinston = new LoggingWinston();
// Create a Winston logger that streams to Cloud Logging // Create a Winston logger that streams to Cloud Logging
const instance = createLogger({ const instance = createLogger({
level: 'log', level: 'info',
transports: [ transports: [
new transports.Console(), new transports.Console(),
// Add Cloud Logging // Add Cloud Logging
loggingWinston, loggingWinston,
], ],
format: format.combine(moreMetadata(), format.json()),
}); });
return new AFFiNELogger(instance); return new AFFiNELogger(instance);
}, },
+13
View File
@@ -838,6 +838,7 @@ __metadata:
nanoid: "npm:^5.0.9" nanoid: "npm:^5.0.9"
nest-commander: "npm:^3.15.0" nest-commander: "npm:^3.15.0"
nest-winston: "npm:^1.9.7" nest-winston: "npm:^1.9.7"
nestjs-cls: "npm:^4.5.0"
nestjs-throttler-storage-redis: "npm:^0.5.1" nestjs-throttler-storage-redis: "npm:^0.5.1"
nodemailer: "npm:^6.9.16" nodemailer: "npm:^6.9.16"
nodemon: "npm:^3.1.7" nodemon: "npm:^3.1.7"
@@ -27239,6 +27240,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"nestjs-cls@npm:^4.5.0":
version: 4.5.0
resolution: "nestjs-cls@npm:4.5.0"
peerDependencies:
"@nestjs/common": "> 7.0.0 < 11"
"@nestjs/core": "> 7.0.0 < 11"
reflect-metadata: "*"
rxjs: ">= 7"
checksum: 10/cbd807244aaf0e89480e5fa7d08415e27953d4f6264246318cd3aa5ec4817564988d5cbed4f700c79090f0ded6f72752887bc842543f7f0af49c515df41e937e
languageName: node
linkType: hard
"nestjs-throttler-storage-redis@npm:^0.5.1": "nestjs-throttler-storage-redis@npm:^0.5.1":
version: 0.5.1 version: 0.5.1
resolution: "nestjs-throttler-storage-redis@npm:0.5.1" resolution: "nestjs-throttler-storage-redis@npm:0.5.1"