Skip to content

Commit 6d982fe

Browse files
committed
Add request id to the app logs for easy log tracking
1 parent 35899be commit 6d982fe

File tree

6 files changed

+91
-1
lines changed

6 files changed

+91
-1
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"jsonwebtoken": "^9.0.2",
3737
"jwks-rsa": "^3.2.0",
3838
"lodash": "^4.17.21",
39+
"nanoid": "^5.1.5",
3940
"reflect-metadata": "^0.2.2",
4041
"rxjs": "^7.8.1",
4142
"trolleyhq": "^1.1.0",

pnpm-lock.yaml

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/api/api.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { HealthCheckController } from './health-check/healthCheck.controller';
33
import { GlobalProvidersModule } from 'src/shared/global/globalProviders.module';
44
import { APP_GUARD } from '@nestjs/core';
55
import { TokenValidatorMiddleware } from 'src/core/auth/middleware/tokenValidator.middleware';
6+
import { CreateRequestStoreMiddleware } from 'src/core/request/createRequestStore.middleware';
67
import { AuthGuard, RolesGuard } from 'src/core/auth/guards';
78
import { TopcoderModule } from 'src/shared/topcoder/topcoder.module';
89
import { OriginRepository } from './repository/origin.repo';
@@ -48,5 +49,6 @@ import { WithdrawalModule } from './withdrawal/withdrawal.module';
4849
export class ApiModule implements NestModule {
4950
configure(consumer: MiddlewareConsumer) {
5051
consumer.apply(TokenValidatorMiddleware).forRoutes('*');
52+
consumer.apply(CreateRequestStoreMiddleware).forRoutes('*');
5153
}
5254
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Injectable, NestMiddleware } from '@nestjs/common';
2+
import { Response, NextFunction } from 'express';
3+
import { RequestMetadata, saveStore } from './requestStore';
4+
5+
@Injectable()
6+
export class CreateRequestStoreMiddleware implements NestMiddleware {
7+
constructor() {}
8+
9+
use(req: any, res: Response, next: NextFunction) {
10+
const requestMetaData = new RequestMetadata({});
11+
12+
saveStore(requestMetaData, next);
13+
}
14+
}

src/core/request/requestStore.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { AsyncLocalStorage } from 'async_hooks';
2+
import { NextFunction } from 'express';
3+
import { nanoid } from 'nanoid';
4+
5+
// Class for storing request specific metadata
6+
export class RequestMetadata {
7+
requestId: string;
8+
9+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-object-type
10+
constructor(params: { requestId?: string }) {
11+
this.requestId = params.requestId ?? nanoid(11);
12+
}
13+
}
14+
15+
// Create a AsyncLocalStorage of type RequestMetaData for storing request specific data
16+
const asyncStorage = new AsyncLocalStorage<RequestMetadata>();
17+
18+
// Gets the RequestMetadada object associated with the current request
19+
export function getStore(): RequestMetadata {
20+
let store = asyncStorage.getStore();
21+
if (store === undefined) {
22+
store = new RequestMetadata({
23+
requestId: '',
24+
});
25+
}
26+
27+
return store;
28+
}
29+
30+
// For use in middleware
31+
// Saves RequestMetadata for the current request
32+
export function saveStore(
33+
requestMetaData: RequestMetadata,
34+
next: NextFunction,
35+
) {
36+
asyncStorage.run(requestMetaData, () => {
37+
next();
38+
});
39+
}

src/shared/global/logger.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { Logger as NestLogger } from '@nestjs/common';
22
import stringify from 'json-stringify-safe';
3+
import { getStore } from 'src/core/request/requestStore';
34

45
export class Logger extends NestLogger {
6+
private get store() {
7+
return getStore();
8+
}
9+
510
log(...messages: any[]): void {
611
super.log(this.formatMessages(messages));
712
}
@@ -19,7 +24,10 @@ export class Logger extends NestLogger {
1924
}
2025

2126
private formatMessages(messages: any[]): string {
22-
return messages
27+
const requestIdPrefix = this.store.requestId
28+
? [`{${this.store.requestId}}`]
29+
: [];
30+
return [...requestIdPrefix, ...messages]
2331
.map((msg) =>
2432
typeof msg === 'object' ? stringify(msg, null, 2) : String(msg),
2533
)

0 commit comments

Comments
 (0)