Skip to content

Commit a918731

Browse files
committed
fix: deprecate info method and redirect to log method
1 parent cd7633b commit a918731

File tree

3 files changed

+122
-33
lines changed

3 files changed

+122
-33
lines changed

src/context-logger.spec.ts

Lines changed: 78 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,34 @@ describe('ContextLogger', () => {
88
const spyWarn = jest.fn();
99
const spyError = jest.fn();
1010
const MODULE_NAME = 'TestModule';
11-
const contextLogger = new ContextLogger(MODULE_NAME);
1211
const CONTEXT = { someContextField: 'someContextValue' };
1312

14-
jest.spyOn(ContextStore, 'getContext').mockReturnValue(CONTEXT);
15-
const mockLogger = {
16-
log: spyLog,
17-
debug: spyDebug,
18-
info: spyInfo,
19-
warn: spyWarn,
20-
error: spyError,
21-
};
13+
let contextLogger: ContextLogger;
14+
let mockLogger: any;
2215

23-
ContextLogger.init(mockLogger as any);
16+
beforeEach(() => {
17+
jest.clearAllMocks();
18+
19+
jest.spyOn(ContextStore, 'getContext').mockReturnValue(CONTEXT);
20+
21+
mockLogger = {
22+
log: spyLog,
23+
debug: spyDebug,
24+
info: spyInfo,
25+
warn: spyWarn,
26+
error: spyError,
27+
};
28+
29+
// Reset the internal logger for each test to ensure clean state
30+
(ContextLogger as any).internalLogger = null;
31+
ContextLogger.init(mockLogger);
32+
33+
contextLogger = new ContextLogger(MODULE_NAME);
34+
});
2435

2536
afterEach(() => {
2637
jest.clearAllMocks();
38+
jest.restoreAllMocks();
2739
});
2840

2941
describe('log, debug, warn methods', () => {
@@ -47,6 +59,20 @@ describe('ContextLogger', () => {
4759

4860
expect(mockLogger.log).toHaveBeenCalledWith(CONTEXT, message, MODULE_NAME);
4961
});
62+
63+
it('should call log method when info is called', () => {
64+
const message = 'Test message';
65+
const bindings = { someBinding: 'value' };
66+
67+
contextLogger.info(message, bindings);
68+
69+
// Since info method calls log internally
70+
expect(mockLogger.log).toHaveBeenCalledWith(
71+
{ ...bindings, ...CONTEXT },
72+
message,
73+
MODULE_NAME
74+
);
75+
});
5076
});
5177

5278
describe('error method', () => {
@@ -147,7 +173,8 @@ describe('ContextLogger', () => {
147173

148174
afterEach(() => {
149175
fallbackLoggerSpy.mockRestore();
150-
ContextLogger.init(mockLogger as any);
176+
// Restore the internal logger
177+
ContextLogger.init(mockLogger);
151178
});
152179

153180
it('should handle bootstrap component logs with string bindings', () => {
@@ -187,7 +214,7 @@ describe('ContextLogger', () => {
187214
const logger = new ContextLogger(MODULE_NAME);
188215
logger.info('test message', { key: 'value' });
189216

190-
expect(spyInfo).toHaveBeenCalledWith(
217+
expect(spyLog).toHaveBeenCalledWith(
191218
expect.objectContaining({
192219
key: 'value',
193220
}),
@@ -203,7 +230,7 @@ describe('ContextLogger', () => {
203230
jest.spyOn(ContextStore, 'getContext').mockReturnValue(contextData);
204231
logger.info('test message');
205232

206-
expect(spyInfo).toHaveBeenCalledWith(
233+
expect(spyLog).toHaveBeenCalledWith(
207234
expect.objectContaining({
208235
user: 'john',
209236
}),
@@ -214,15 +241,20 @@ describe('ContextLogger', () => {
214241
});
215242

216243
describe('with partial grouping', () => {
244+
beforeEach(() => {
245+
// Reset the internal logger for each test to ensure clean state
246+
(ContextLogger as any).internalLogger = null;
247+
});
248+
217249
it('should group only bindings when bindingsKey provided', () => {
218250
const logger = new ContextLogger(MODULE_NAME);
219-
ContextLogger.init(mockLogger as any, { groupFields: { bindingsKey: 'params' } });
251+
ContextLogger.init(mockLogger, { groupFields: { bindingsKey: 'params' } });
220252
const contextData = { user: 'john' };
221253

222254
jest.spyOn(ContextStore, 'getContext').mockReturnValue(contextData);
223255
logger.info('test message', { key: 'value' });
224256

225-
expect(spyInfo).toHaveBeenCalledWith(
257+
expect(spyLog).toHaveBeenCalledWith(
226258
expect.objectContaining({
227259
params: { key: 'value' },
228260
user: 'john',
@@ -234,13 +266,13 @@ describe('ContextLogger', () => {
234266

235267
it('should not group bindings when bindingsKey provided but bindings object is empty', () => {
236268
const logger = new ContextLogger(MODULE_NAME);
237-
ContextLogger.init(mockLogger as any, { groupFields: { bindingsKey: 'params' } });
269+
ContextLogger.init(mockLogger, { groupFields: { bindingsKey: 'params' } });
238270
const contextData = { user: 'john' };
239271

240272
jest.spyOn(ContextStore, 'getContext').mockReturnValue(contextData);
241273
logger.info('test message');
242274

243-
expect(spyInfo).toHaveBeenCalledWith(
275+
expect(spyLog).toHaveBeenCalledWith(
244276
{ user: 'john', },
245277
'test message',
246278
MODULE_NAME
@@ -249,13 +281,13 @@ describe('ContextLogger', () => {
249281

250282
it('should group only context when contextKey provided', () => {
251283
const logger = new ContextLogger(MODULE_NAME);
252-
ContextLogger.init(mockLogger as any, { groupFields: { contextKey: 'metadata' } });
284+
ContextLogger.init(mockLogger, { groupFields: { contextKey: 'metadata' } });
253285
const contextData = { user: 'john' };
254286

255287
jest.spyOn(ContextStore, 'getContext').mockReturnValue(contextData);
256288
logger.info('test message', { key: 'value' });
257289

258-
expect(spyInfo).toHaveBeenCalledWith(
290+
expect(spyLog).toHaveBeenCalledWith(
259291
expect.objectContaining({
260292
metadata: { user: 'john' },
261293
key: 'value',
@@ -267,13 +299,13 @@ describe('ContextLogger', () => {
267299

268300
it('should not group context when contextKey provided but context object is empty', () => {
269301
const logger = new ContextLogger(MODULE_NAME);
270-
ContextLogger.init(mockLogger as any, { groupFields: { contextKey: 'metadata' } });
302+
ContextLogger.init(mockLogger, { groupFields: { contextKey: 'metadata' } });
271303
const contextData = {};
272304

273305
jest.spyOn(ContextStore, 'getContext').mockReturnValue(contextData);
274306
logger.info('test message', { key: 'value' });
275307

276-
expect(spyInfo).toHaveBeenCalledWith(
308+
expect(spyLog).toHaveBeenCalledWith(
277309
{ key: 'value' },
278310
'test message',
279311
MODULE_NAME
@@ -282,9 +314,14 @@ describe('ContextLogger', () => {
282314
});
283315

284316
describe('with full grouping', () => {
317+
beforeEach(() => {
318+
// Reset the internal logger for each test to ensure clean state
319+
(ContextLogger as any).internalLogger = null;
320+
});
321+
285322
it('should group both bindings and context under specified keys', () => {
286323
const logger = new ContextLogger(MODULE_NAME);
287-
ContextLogger.init(mockLogger as any, {
324+
ContextLogger.init(mockLogger, {
288325
groupFields: {
289326
bindingsKey: 'params',
290327
contextKey: 'metadata'
@@ -295,7 +332,7 @@ describe('ContextLogger', () => {
295332
jest.spyOn(ContextStore, 'getContext').mockReturnValue(contextData);
296333
logger.info('test message', { key: 'value' });
297334

298-
expect(spyInfo).toHaveBeenCalledWith(
335+
expect(spyLog).toHaveBeenCalledWith(
299336
expect.objectContaining({
300337
params: { key: 'value' },
301338
metadata: { user: 'john' },
@@ -307,7 +344,7 @@ describe('ContextLogger', () => {
307344

308345
it('should not add specified keys when both bindings and context are empty', () => {
309346
const logger = new ContextLogger(MODULE_NAME);
310-
ContextLogger.init(mockLogger as any, {
347+
ContextLogger.init(mockLogger, {
311348
groupFields: {
312349
bindingsKey: 'params',
313350
contextKey: 'metadata'
@@ -318,7 +355,7 @@ describe('ContextLogger', () => {
318355
jest.spyOn(ContextStore, 'getContext').mockReturnValue(contextData);
319356
logger.info('test message');
320357

321-
expect(spyInfo).toHaveBeenCalledWith(
358+
expect(spyLog).toHaveBeenCalledWith(
322359
{},
323360
'test message',
324361
MODULE_NAME
@@ -328,9 +365,14 @@ describe('ContextLogger', () => {
328365
});
329366

330367
describe('context adaptation', () => {
368+
beforeEach(() => {
369+
// Reset the internal logger for each test to ensure clean state
370+
(ContextLogger as any).internalLogger = null;
371+
});
372+
331373
it('should adapt context when adapter is provided', () => {
332374
const logger = new ContextLogger(MODULE_NAME);
333-
ContextLogger.init(mockLogger as any, {
375+
ContextLogger.init(mockLogger, {
334376
contextAdapter: (ctx) => ({ user: ctx.user })
335377
});
336378
const contextData = { user: 'john', role: 'admin' };
@@ -339,7 +381,7 @@ describe('ContextLogger', () => {
339381

340382
logger.info('test message');
341383

342-
expect(spyInfo).toHaveBeenCalledWith(
384+
expect(spyLog).toHaveBeenCalledWith(
343385
expect.objectContaining({
344386
user: 'john', // Spread at root level since groupFields is disabled by default
345387
}),
@@ -355,7 +397,7 @@ describe('ContextLogger', () => {
355397
jest.spyOn(ContextStore, 'getContext').mockReturnValue({});
356398
logger.info('test message');
357399

358-
expect(spyInfo).toHaveBeenCalledWith(
400+
expect(spyLog).toHaveBeenCalledWith(
359401
expect.not.objectContaining({
360402
bindings: undefined,
361403
context: undefined,
@@ -367,9 +409,14 @@ describe('ContextLogger', () => {
367409
});
368410

369411
describe('bootstrap logs handling', () => {
412+
beforeEach(() => {
413+
// Reset the internal logger for each test to ensure clean state
414+
(ContextLogger as any).internalLogger = null;
415+
});
416+
370417
it('should ignore bootstrap logs when ignoreBootstrapLogs is true', () => {
371418
const logger = new ContextLogger(MODULE_NAME);
372-
ContextLogger.init(mockLogger as any, { ignoreBootstrapLogs: true });
419+
ContextLogger.init(mockLogger, { ignoreBootstrapLogs: true });
373420

374421
// @ts-expect-error - Simulate bootstrap phase
375422
logger.log('Mapped {/api/users, GET} route', 'RouterExplorer');
@@ -379,7 +426,7 @@ describe('ContextLogger', () => {
379426

380427
it('should handle bootstrap logs when ignoreBootstrapLogs is false', () => {
381428
const logger = new ContextLogger(MODULE_NAME);
382-
ContextLogger.init(mockLogger as any, { ignoreBootstrapLogs: false });
429+
ContextLogger.init(mockLogger, { ignoreBootstrapLogs: false });
383430

384431
// @ts-expect-error - Simulate bootstrap phase
385432
logger.log('Mapped {/api/users, GET} route', 'RouterExplorer');
@@ -393,7 +440,7 @@ describe('ContextLogger', () => {
393440

394441
it('should handle bootstrap logs by default (ignoreBootstrapLogs not set)', () => {
395442
const logger = new ContextLogger(MODULE_NAME);
396-
ContextLogger.init(mockLogger as any, {});
443+
ContextLogger.init(mockLogger, {});
397444

398445
// @ts-expect-error - Simulate bootstrap phase
399446
logger.log('Mapped {/api/users, GET} route', 'RouterExplorer');

src/context-logger.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,14 @@ export class ContextLogger {
3838
this.callInternalLogger('log', message, (bindings ?? {}));
3939
}
4040

41+
/**
42+
* @deprecated This method is deprecated and will be removed in a future version.
43+
* It currently calls the 'log' method internally.
44+
* Please use the 'log' method directly instead.
45+
* https://github.com/AdirD/nestjs-context-logger/issues/5
46+
*/
4147
info(message: string, bindings?: Bindings) {
42-
this.callInternalLogger('info', message, (bindings ?? {}));
48+
this.callInternalLogger('log', message, (bindings ?? {}));
4349
}
4450

4551
debug(message: string, bindings?: Bindings) {

src/test/context-logger.e2e.spec.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,17 @@ class IsolationCTestController {
141141
}
142142
}
143143

144+
@Controller()
145+
class InfoMethodTestController {
146+
private readonly logger = new ContextLogger(InfoMethodTestController.name);
147+
148+
@Get('/info-method-test')
149+
test() {
150+
this.logger.info('info method test endpoint hit', { testBinding: 'test-value' });
151+
return { success: true };
152+
}
153+
}
154+
144155
describe('ContextLogger E2E', () => {
145156
let app: INestApplication;
146157

@@ -164,7 +175,7 @@ describe('ContextLogger E2E', () => {
164175
})
165176
})
166177
],
167-
controllers: [SimpleTestController, ChainTestController, IsolationATestController, IsolationBTestController, IsolationCTestController ],
178+
controllers: [SimpleTestController, ChainTestController, IsolationATestController, IsolationBTestController, IsolationCTestController, InfoMethodTestController],
168179
providers: [ChainTestService]
169180
}).compile();
170181

@@ -311,6 +322,31 @@ describe('ContextLogger E2E', () => {
311322
]);
312323
});
313324

325+
it('should use log method when info method is called', async () => {
326+
const response = await request(app.getHttpServer())
327+
.get('/info-method-test')
328+
.set('X-Trace-ID', 'trace-info-123')
329+
.expect(200);
330+
331+
expect(response.body).toEqual({ success: true });
332+
333+
// Verify that log was called (not info) since info is now deprecated and calls log internally
334+
expect(mockNestJSPinoLogger.log).toHaveBeenCalledWith(
335+
expect.objectContaining({
336+
environment: 'test',
337+
requestMethod: 'GET',
338+
requestUrl: '/info-method-test',
339+
traceId: 'trace-info-123',
340+
testBinding: 'test-value'
341+
}),
342+
'info method test endpoint hit',
343+
InfoMethodTestController.name
344+
);
345+
346+
// We don't need to check if info was called since our mock doesn't have an info method
347+
// The important part is that log was called with the correct parameters
348+
});
349+
314350
describe('ContextLogger Platform Compatibility', () => {
315351
let moduleFixture: TestingModule;
316352

0 commit comments

Comments
 (0)