diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md index 7b12c8bc95..f80aeec93d 100644 --- a/docs/blog/version-5.0-release-notes.md +++ b/docs/blog/version-5.0-release-notes.md @@ -65,6 +65,10 @@ Version 5.0 of [Foal](https://foalts.org/) is out! - The return value of the social services `getUserInfoFromTokens` method is now typed. +## Logging + +- The `Logger.addLogContext(key, value)` method now accepts a record as argument: `Logger.addLogContext(params)`. This makes the function's signature more consistent with other logging methods (`info`, `warn`, etc.) and allows multiple parameters to be passed at once. + ## Removal of deprecated components - The deprecated hook `@Log` has been removed. Use the `Logger` service in a custom `@Hook` instead. diff --git a/docs/docs/common/logging.md b/docs/docs/common/logging.md index bb2a61d6a1..0f9d08b8db 100644 --- a/docs/docs/common/logging.md +++ b/docs/docs/common/logging.md @@ -260,7 +260,7 @@ This mecanism helps filter logs of a specific request or specific user in a logg If needed, you call also add manually custom parameters to the logger context with this fonction: ```typescript -logger.addLogContext('myKey', 'myValue'); +logger.addLogContext({ myKey: 'myValue' }); ``` ## Transports diff --git a/packages/core/src/core/logging/logger.spec.ts b/packages/core/src/core/logging/logger.spec.ts index bef0ac5cc6..c973a7e2aa 100644 --- a/packages/core/src/core/logging/logger.spec.ts +++ b/packages/core/src/core/logging/logger.spec.ts @@ -22,11 +22,11 @@ describe('Logger', () => { const logger = new Logger(); logger.initLogContext(() => { - logger.addLogContext('foo', 'bar'); + logger.addLogContext({ foo: 'bar', jane: 'doe'}); logger.log('error', 'Hello world', {}); }); logger.initLogContext(() => { - logger.addLogContext('foo2', 'bar2'); + logger.addLogContext({ foo2: 'bar2' }); logger.log('error', 'Hello world 2', {}); }); @@ -36,6 +36,7 @@ describe('Logger', () => { strictEqual(loggedMessage.includes('[ERROR]'), true); strictEqual(loggedMessage.includes('foo: "bar"'), true); + strictEqual(loggedMessage.includes('jane: "doe"'), true); notStrictEqual(loggedMessage.includes('foo2: "bar2"'), true); const loggedMessage2 = consoleMock.calls[1].arguments[0]; @@ -43,6 +44,7 @@ describe('Logger', () => { strictEqual(loggedMessage2.includes('[ERROR]'), true); strictEqual(loggedMessage2.includes('foo2: "bar2"'), true); notStrictEqual(loggedMessage2.includes('foo: "bar"'), true); + notStrictEqual(loggedMessage2.includes('jane: "doe"'), true); }); it('should let given params override the context.', () => { @@ -50,7 +52,7 @@ describe('Logger', () => { const logger = new Logger(); logger.initLogContext(() => { - logger.addLogContext('foo', 'bar'); + logger.addLogContext({ foo: 'bar' }); logger.log('error', 'Hello world', { foo: 'bar2' }); }); @@ -68,7 +70,7 @@ describe('Logger', () => { const consoleMock = mock.method(console, 'log', () => {}).mock; const logger = new Logger(); - logger.addLogContext('foo', 'bar'); + logger.addLogContext({ foo: 'bar' }); strictEqual(consoleMock.callCount(), 1); diff --git a/packages/core/src/core/logging/logger.ts b/packages/core/src/core/logging/logger.ts index 6515dd0a84..d8f8c3830d 100644 --- a/packages/core/src/core/logging/logger.ts +++ b/packages/core/src/core/logging/logger.ts @@ -19,13 +19,13 @@ export class Logger { this.asyncLocalStorage.run({}, callback); } - addLogContext(name: string, value: any): void { + addLogContext(params: Record): void { const store = this.asyncLocalStorage.getStore(); if (!store) { this.log('warn', 'Impossible to add log context information. The logger context has not been initialized.'); return; } - store[name] = value; + Object.assign(store, params); } log( diff --git a/packages/core/src/express/create-app.spec.ts b/packages/core/src/express/create-app.spec.ts index 3411fdbba4..65a91bfb07 100644 --- a/packages/core/src/express/create-app.spec.ts +++ b/packages/core/src/express/create-app.spec.ts @@ -887,7 +887,7 @@ describe('createApp', () => { @Get('/') @Hook((ctx, services) => { const logger = services.get(Logger); - logger.addLogContext('foo', 'bar'); + logger.addLogContext({ foo: 'bar' }); }) getA(ctx: Context) { this.logger.info('Hello world'); @@ -995,9 +995,8 @@ describe('createApp', () => { strictEqual(loggerMock.callCount(), 1); - const [key, value] = loggerMock.calls[0].arguments; + const args = loggerMock.calls[0].arguments; - strictEqual(key, 'requestId'); - strictEqual(value, requestId); + deepStrictEqual(args, [{ requestId }]); }); }); diff --git a/packages/core/src/express/create-app.ts b/packages/core/src/express/create-app.ts index aeac0351f4..59f82bb54f 100644 --- a/packages/core/src/express/create-app.ts +++ b/packages/core/src/express/create-app.ts @@ -116,7 +116,7 @@ export async function createApp( const requestId = req.get('x-request-id') || randomUUID(); req.id = requestId; - logger.addLogContext('requestId', requestId); + logger.addLogContext({ requestId }); next(); }); diff --git a/packages/core/src/sessions/http/use-sessions.hook.spec.ts b/packages/core/src/sessions/http/use-sessions.hook.spec.ts index 28f2d937ce..00f48792ad 100644 --- a/packages/core/src/sessions/http/use-sessions.hook.spec.ts +++ b/packages/core/src/sessions/http/use-sessions.hook.spec.ts @@ -615,7 +615,7 @@ describe('UseSessions', () => { strictEqual(loggerMock.callCount(), 1); - deepStrictEqual(loggerMock.calls[0].arguments, ['userId', null]); + deepStrictEqual(loggerMock.calls[0].arguments, [{ userId: null }]); }); }); @@ -632,7 +632,7 @@ describe('UseSessions', () => { strictEqual(loggerMock.callCount(), 1); - deepStrictEqual(loggerMock.calls[0].arguments, ['userId', userId]); + deepStrictEqual(loggerMock.calls[0].arguments, [{ userId }]); }); context('given options.user is not defined', () => { diff --git a/packages/core/src/sessions/http/use-sessions.hook.ts b/packages/core/src/sessions/http/use-sessions.hook.ts index 7e34e74db2..474708f9b4 100644 --- a/packages/core/src/sessions/http/use-sessions.hook.ts +++ b/packages/core/src/sessions/http/use-sessions.hook.ts @@ -144,7 +144,7 @@ export function UseSessions(options: UseSessionOptions = {}): HookDecorator { /* Set ctx.user */ const logger = services.get(Logger); - logger.addLogContext('userId', session.userId); + logger.addLogContext({ userId: session.userId }); if (session.userId !== null && options.user) { const userId = checkUserIdType(session.userId, options.userIdType); diff --git a/packages/jwt/src/http/jwt.hook.spec.ts b/packages/jwt/src/http/jwt.hook.spec.ts index 366668ef0e..2d83436a17 100644 --- a/packages/jwt/src/http/jwt.hook.spec.ts +++ b/packages/jwt/src/http/jwt.hook.spec.ts @@ -632,7 +632,7 @@ export function testSuite(JWT: typeof JWTOptional|typeof JWTRequired, required: strictEqual(loggerMock.callCount(), 1); deepStrictEqual( loggerMock.calls[0].arguments, - ['userId', 123], + [{ userId: 123 }], ); }) diff --git a/packages/jwt/src/http/jwt.hook.ts b/packages/jwt/src/http/jwt.hook.ts index 44d18db238..9292b8991d 100644 --- a/packages/jwt/src/http/jwt.hook.ts +++ b/packages/jwt/src/http/jwt.hook.ts @@ -201,7 +201,7 @@ export function JWT(required: boolean, options: JWTOptions, verifyOptions: Verif const userId = checkAndConvertUserIdType(payload.sub, options.userIdType); const logger = services.get(Logger); - logger.addLogContext('userId', userId); + logger.addLogContext({ userId }); const user = await options.user(userId as never, services); if (!user) { diff --git a/packages/socket.io/src/socketio-controller.service.spec.ts b/packages/socket.io/src/socketio-controller.service.spec.ts index 6a78a77187..c8c426e9a8 100644 --- a/packages/socket.io/src/socketio-controller.service.spec.ts +++ b/packages/socket.io/src/socketio-controller.service.spec.ts @@ -431,7 +431,7 @@ describe('SocketIOController', () => { @EventName('create user') @WebsocketHook((ctx, services) => { const logger = services.get(Logger); - logger.addLogContext('foo', 'bar'); + logger.addLogContext({ foo: 'bar' }); }) createUser(ctx: WebsocketContext, payload: any) { this.logger.info('Hello world'); @@ -474,12 +474,14 @@ describe('SocketIOController', () => { const payload = {}; await new Promise(resolve => clientSocket.emit('create user', payload, resolve)); - strictEqual(loggerMock.callCount(), 2); + strictEqual(loggerMock.callCount(), 1); const actualParameters = loggerMock.calls.map(call => call.arguments); const expectedParameters = [ - ['socketId', socketId], - ['messageId', messageId] + [{ + socketId, + messageId, + }] ]; deepStrictEqual(actualParameters, expectedParameters); diff --git a/packages/socket.io/src/socketio-controller.service.ts b/packages/socket.io/src/socketio-controller.service.ts index 085c470125..6063ef3006 100644 --- a/packages/socket.io/src/socketio-controller.service.ts +++ b/packages/socket.io/src/socketio-controller.service.ts @@ -72,8 +72,11 @@ export abstract class SocketIOController implements ISocketIOController { socket.on(route.eventName, async (payload, cb) => { this.logger.initLogContext(async () => { const messageId = randomUUID(); - this.logger.addLogContext('socketId', socket.id); - this.logger.addLogContext('messageId', messageId); + + this.logger.addLogContext({ + socketId: socket.id, + messageId, + }); if (typeof payload === 'function') { cb = payload;