Skip to content

Commit 409dc32

Browse files
committed
fix: moved to stdout, unit tests wip
1 parent d64dc9b commit 409dc32

File tree

4 files changed

+56
-43
lines changed

4 files changed

+56
-43
lines changed

packages/logger/src/Logger.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Console } from 'console';
12
import type { Context } from 'aws-lambda';
23
import { Utility } from '@aws-lambda-powertools/commons';
34
import { LogFormatterInterface, PowertoolLogFormatter } from './formatter';
@@ -107,6 +108,8 @@ import type {
107108
*/
108109
class Logger extends Utility implements ClassThatLogs {
109110

111+
private console = new Console({ stdout: process.stdout, stderr: process.stderr });
112+
110113
private customConfigService?: ConfigServiceInterface;
111114

112115
private static readonly defaultLogLevel: LogLevel = 'INFO';
@@ -448,7 +451,7 @@ class Logger extends Utility implements ClassThatLogs {
448451

449452
const consoleMethod = logLevel.toLowerCase() as keyof ClassThatLogs;
450453

451-
console[consoleMethod](JSON.stringify(log.getAttributes(), this.removeCircularDependencies()));
454+
this.console[consoleMethod](JSON.stringify(log.getAttributes(), this.removeCircularDependencies()));
452455
}
453456

454457
/**

packages/logger/tests/unit/Logger.test.ts

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,16 @@ import { EnvironmentVariablesService } from '../../src/config';
1414
import { PowertoolLogFormatter } from '../../src/formatter';
1515
import { ClassThatLogs } from '../../src/types';
1616
import { Context } from 'aws-lambda';
17+
import { Console } from 'console';
1718

1819
const mockDate = new Date(1466424490000);
1920
const dateSpy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate as unknown as string);
20-
21-
const consoleSpy = {
22-
'debug': jest.spyOn(console, 'debug').mockImplementation(),
23-
'info': jest.spyOn(console, 'info').mockImplementation(),
24-
'warn': jest.spyOn(console, 'warn').mockImplementation(),
25-
'error': jest.spyOn(console, 'error').mockImplementation(),
26-
};
21+
const stdoutSpy = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
2722

2823
describe('Class: Logger', () => {
2924

3025
beforeEach(() => {
31-
consoleSpy['debug'].mockClear();
32-
consoleSpy['info'].mockClear();
33-
consoleSpy['warn'].mockClear();
34-
consoleSpy['error'].mockClear();
26+
stdoutSpy.mockClear();
3527
dateSpy.mockClear();
3628
});
3729

@@ -70,9 +62,9 @@ describe('Class: Logger', () => {
7062
}
7163

7264
// Assess
73-
expect(console[methodOfLogger]).toBeCalledTimes(debugPrints ? 1 : 0);
65+
expect(stdoutSpy).toBeCalledTimes(debugPrints ? 1 : 0);
7466
if (debugPrints) {
75-
expect(console[methodOfLogger]).toHaveBeenNthCalledWith(1, JSON.stringify({
67+
expect(stdoutSpy).toHaveBeenNthCalledWith(1, JSON.stringify({
7668
level: methodOfLogger.toUpperCase(),
7769
message: 'foo',
7870
service: 'hello-world',
@@ -96,9 +88,9 @@ describe('Class: Logger', () => {
9688
}
9789

9890
// Assess
99-
expect(console[methodOfLogger]).toBeCalledTimes(infoPrints ? 1 : 0);
91+
expect(stdoutSpy).toBeCalledTimes(infoPrints ? 1 : 0);
10092
if (infoPrints) {
101-
expect(console[methodOfLogger]).toHaveBeenNthCalledWith(1, JSON.stringify({
93+
expect(stdoutSpy).toHaveBeenNthCalledWith(1, JSON.stringify({
10294
level: methodOfLogger.toUpperCase(),
10395
message: 'foo',
10496
service: 'hello-world',
@@ -122,9 +114,9 @@ describe('Class: Logger', () => {
122114
}
123115

124116
// Assess
125-
expect(console[methodOfLogger]).toBeCalledTimes(warnPrints ? 1 : 0);
117+
expect(stdoutSpy).toBeCalledTimes(warnPrints ? 1 : 0);
126118
if (warnPrints) {
127-
expect(console[methodOfLogger]).toHaveBeenNthCalledWith(1, JSON.stringify({
119+
expect(stdoutSpy).toHaveBeenNthCalledWith(1, JSON.stringify({
128120
level: methodOfLogger.toUpperCase(),
129121
message: 'foo',
130122
service: 'hello-world',
@@ -148,9 +140,9 @@ describe('Class: Logger', () => {
148140
}
149141

150142
// Assess
151-
expect(console[methodOfLogger]).toBeCalledTimes(errorPrints ? 1 : 0);
143+
expect(stdoutSpy).toBeCalledTimes(errorPrints ? 1 : 0);
152144
if (errorPrints) {
153-
expect(console[methodOfLogger]).toHaveBeenNthCalledWith(1, JSON.stringify({
145+
expect(stdoutSpy).toHaveBeenNthCalledWith(1, JSON.stringify({
154146
level: methodOfLogger.toUpperCase(),
155147
message: 'foo',
156148
service: 'hello-world',
@@ -181,7 +173,7 @@ describe('Class: Logger', () => {
181173
}
182174

183175
// Assess
184-
expect(console[methodOfLogger]).toBeCalledTimes(method === 'error' ? 1 : 0);
176+
expect(stdoutSpy).toBeCalledTimes(method === 'error' ? 1 : 0);
185177
});
186178

187179
test('when the Logger\'s log level is higher and the current Lambda invocation IS sampled for logging, it DOES print to stdout', () => {
@@ -198,8 +190,8 @@ describe('Class: Logger', () => {
198190
}
199191

200192
// Assess
201-
expect(console[methodOfLogger]).toBeCalledTimes(1);
202-
expect(console[methodOfLogger]).toHaveBeenNthCalledWith(1, JSON.stringify({
193+
expect(stdoutSpy).toBeCalledTimes(1);
194+
expect(stdoutSpy).toHaveBeenNthCalledWith(1, JSON.stringify({
203195
level: method.toUpperCase(),
204196
message: 'foo',
205197
sampling_rate: 1,
@@ -226,8 +218,8 @@ describe('Class: Logger', () => {
226218
}
227219

228220
// Assess
229-
expect(console[methodOfLogger]).toBeCalledTimes(1);
230-
expect(console[methodOfLogger]).toHaveBeenNthCalledWith(1, JSON.stringify({
221+
expect(stdoutSpy).toBeCalledTimes(1);
222+
expect(stdoutSpy).toHaveBeenNthCalledWith(1, JSON.stringify({
231223
level: method.toUpperCase(),
232224
message: 'foo',
233225
service: 'hello-world',
@@ -250,8 +242,8 @@ describe('Class: Logger', () => {
250242
}
251243

252244
// Assess
253-
expect(console[methodOfLogger]).toBeCalledTimes(1);
254-
expect(console[methodOfLogger]).toHaveBeenNthCalledWith(1, JSON.stringify({
245+
expect(stdoutSpy).toBeCalledTimes(1);
246+
expect(stdoutSpy).toHaveBeenNthCalledWith(1, JSON.stringify({
255247
cold_start: true,
256248
function_arn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function',
257249
function_memory_size: 128,
@@ -292,22 +284,22 @@ describe('Class: Logger', () => {
292284
}
293285

294286
// Assess
295-
expect(console[methodOfConsole]).toHaveBeenNthCalledWith(1, JSON.stringify({
287+
expect(stdoutSpy).toHaveBeenNthCalledWith(1, JSON.stringify({
296288
level: method.toUpperCase(),
297289
message: 'A log item without extra parameters',
298290
service: 'hello-world',
299291
timestamp: '2016-06-20T12:08:10.000Z',
300292
xray_trace_id: 'abcdef123456abcdef123456abcdef123456',
301293
}));
302-
expect(console[methodOfConsole]).toHaveBeenNthCalledWith(2, JSON.stringify({
294+
expect(stdoutSpy).toHaveBeenNthCalledWith(2, JSON.stringify({
303295
level: method.toUpperCase(),
304296
message: 'A log item with a string as first parameter, and an object as second parameter',
305297
service: 'hello-world',
306298
timestamp: '2016-06-20T12:08:10.000Z',
307299
xray_trace_id: 'abcdef123456abcdef123456abcdef123456',
308300
extra: 'parameter',
309301
}));
310-
expect(console[methodOfConsole]).toHaveBeenNthCalledWith(3, JSON.stringify({
302+
expect(stdoutSpy).toHaveBeenNthCalledWith(3, JSON.stringify({
311303
level: method.toUpperCase(),
312304
message: 'A log item with a string as first parameter, and objects as other parameters',
313305
service: 'hello-world',
@@ -316,15 +308,15 @@ describe('Class: Logger', () => {
316308
parameterOne: 'foo',
317309
parameterTwo: 'bar',
318310
}));
319-
expect(console[methodOfConsole]).toHaveBeenNthCalledWith(4, JSON.stringify({
311+
expect(stdoutSpy).toHaveBeenNthCalledWith(4, JSON.stringify({
320312
level: method.toUpperCase(),
321313
message: 'A log item with an object as first parameters',
322314
service: 'hello-world',
323315
timestamp: '2016-06-20T12:08:10.000Z',
324316
xray_trace_id: 'abcdef123456abcdef123456abcdef123456',
325317
extra: 'parameter',
326318
}));
327-
const parameterCallNumber5 = JSON.parse(consoleSpy[methodOfConsole].mock.calls[4][0]);
319+
const parameterCallNumber5 = JSON.parse(stdoutSpy.mock.calls[4][0] as string);
328320
expect(parameterCallNumber5).toEqual(expect.objectContaining( {
329321
level: method.toUpperCase(),
330322
message: 'A log item with a string as first parameter, and an error as second parameter',
@@ -338,7 +330,7 @@ describe('Class: Logger', () => {
338330
stack: expect.stringMatching(/Logger.test.ts:[0-9]+:[0-9]+/),
339331
},
340332
}));
341-
const parameterCallNumber6 = JSON.parse(consoleSpy[methodOfConsole].mock.calls[5][0]);
333+
const parameterCallNumber6 = JSON.parse(stdoutSpy.mock.calls[5][0] as string);
342334
expect(parameterCallNumber6).toEqual(expect.objectContaining({
343335
level: method.toUpperCase(),
344336
message: 'A log item with a string as first parameter, and an error with custom key as second parameter',
@@ -352,7 +344,7 @@ describe('Class: Logger', () => {
352344
stack: expect.stringMatching(/Logger.test.ts:[0-9]+:[0-9]+/),
353345
},
354346
}));
355-
expect(console[methodOfConsole]).toHaveBeenNthCalledWith(7, JSON.stringify({
347+
expect(stdoutSpy).toHaveBeenNthCalledWith(7, JSON.stringify({
356348
level: method.toUpperCase(),
357349
message: 'A log item with a string as first parameter, and a string as second parameter',
358350
service: 'hello-world',
@@ -385,8 +377,8 @@ describe('Class: Logger', () => {
385377
}
386378

387379
// Assess
388-
expect(console[methodOfConsole]).toBeCalledTimes(1);
389-
expect(console[methodOfConsole]).toHaveBeenNthCalledWith(1, JSON.stringify({
380+
expect(stdoutSpy).toBeCalledTimes(1);
381+
expect(stdoutSpy).toHaveBeenNthCalledWith(1, JSON.stringify({
390382
level: method.toUpperCase(),
391383
message: 'foo',
392384
service: 'hello-world',
@@ -428,7 +420,7 @@ describe('Class: Logger', () => {
428420

429421
// Assess
430422
expect(result).toBe('All good!');
431-
expect(console[methodOfConsole]).toHaveBeenNthCalledWith(1, JSON.stringify({
423+
expect(stdoutSpy).toHaveBeenNthCalledWith(1, JSON.stringify({
432424
level: method.toUpperCase(),
433425
message: 'A log with a circular reference',
434426
service: 'hello-world',
@@ -471,6 +463,7 @@ describe('Class: Logger', () => {
471463

472464
// Assess
473465
expect(logger).toEqual({
466+
console: expect.any(Console),
474467
coldStart: false, // This is now false because the `coldStart` attribute has been already accessed once by the `addContext` method
475468
customConfigService: undefined,
476469
envVarsService: expect.any(EnvironmentVariablesService),
@@ -723,15 +716,17 @@ describe('Class: Logger', () => {
723716
// Assess
724717

725718
expect(actualResult).toEqual(expectedReturnValue);
726-
expect(console['info']).toBeCalledTimes(2);
727-
expect(console['info']).toHaveBeenNthCalledWith(1, JSON.stringify({
719+
expect(stdoutSpy).toBeCalledTimes(2);
720+
const actualCall1 = stdoutSpy.mock.calls[0][0];
721+
expect(actualCall1).toEqual(JSON.stringify({
728722
level: 'INFO',
729723
message: 'An INFO log without context!',
730724
service: 'hello-world',
731725
timestamp: '2016-06-20T12:08:10.000Z',
732726
xray_trace_id: 'abcdef123456abcdef123456abcdef123456',
733727
}));
734-
expect(console['info']).toHaveBeenNthCalledWith(2, JSON.stringify({
728+
const actualCall2 = stdoutSpy.mock.calls[0][1];
729+
expect(actualCall2).toEqual(JSON.stringify({
735730
cold_start: true,
736731
function_arn: 'arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function',
737732
function_memory_size: 128,
@@ -804,6 +799,7 @@ describe('Class: Logger', () => {
804799
expect(parentLogger === childLoggerWithErrorLogLevel).toBe(false);
805800

806801
expect(parentLogger).toEqual({
802+
console: expect.any(Console),
807803
coldStart: true,
808804
customConfigService: undefined,
809805
envVarsService: expect.any(EnvironmentVariablesService),
@@ -827,6 +823,7 @@ describe('Class: Logger', () => {
827823
});
828824

829825
expect(childLoggerWithPermanentAttributes).toEqual({
826+
console: expect.any(Console),
830827
coldStart: true,
831828
customConfigService: undefined,
832829
envVarsService: expect.any(EnvironmentVariablesService),
@@ -852,6 +849,7 @@ describe('Class: Logger', () => {
852849
});
853850

854851
expect(childLoggerWithSampleRateEnabled).toEqual({
852+
console: expect.any(Console),
855853
coldStart: true,
856854
customConfigService: undefined,
857855
envVarsService: expect.any(EnvironmentVariablesService),
@@ -875,6 +873,7 @@ describe('Class: Logger', () => {
875873
});
876874

877875
expect(childLoggerWithErrorLogLevel).toEqual({
876+
console: expect.any(Console),
878877
coldStart: true,
879878
customConfigService: undefined,
880879
envVarsService: expect.any(EnvironmentVariablesService),

packages/logger/tests/unit/helpers.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* @group unit/logger/all
55
*/
66

7+
import { Console } from 'console';
78
import { ConfigServiceInterface, EnvironmentVariablesService } from '../../src/config';
89
import { LogFormatter, PowertoolLogFormatter } from '../../src/formatter';
910
import { LoggerOptions } from '../../src/types';
@@ -78,6 +79,7 @@ describe('Helper: createLogger function', () => {
7879
envVarsService: expect.any(EnvironmentVariablesService),
7980
logFormatter: expect.any(PowertoolLogFormatter),
8081
logLevel: 'WARN',
82+
console: expect.any(Console),
8183
logLevelThresholds: {
8284
DEBUG: 8,
8385
ERROR: 20,
@@ -117,6 +119,7 @@ describe('Helper: createLogger function', () => {
117119
envVarsService: expect.any(EnvironmentVariablesService),
118120
logFormatter: expect.any(PowertoolLogFormatter),
119121
logLevel: 'INFO',
122+
console: expect.any(Console),
120123
logLevelThresholds: {
121124
DEBUG: 8,
122125
ERROR: 20,
@@ -240,6 +243,7 @@ describe('Helper: createLogger function', () => {
240243
envVarsService: expect.any(EnvironmentVariablesService),
241244
logFormatter: expect.any(PowertoolLogFormatter),
242245
logLevel: 'INFO',
246+
console: expect.any(Console),
243247
logLevelThresholds: {
244248
DEBUG: 8,
245249
ERROR: 20,

packages/logger/tests/unit/middleware/middy.test.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ import { injectLambdaContext } from '../../../src/middleware/middy';
99
import { Logger } from './../../../src';
1010
import middy from '@middy/core';
1111
import { PowertoolLogFormatter } from '../../../src/formatter';
12+
import { Console } from 'console';
1213

1314
describe('Middy middleware', () => {
1415

1516
const ENVIRONMENT_VARIABLES = process.env;
1617

1718
beforeEach(() => {
1819
jest.resetModules();
19-
// eslint-disable-next-line @typescript-eslint/no-empty-function
20-
jest.spyOn(console, 'log').mockImplementation(() => {});
20+
jest.spyOn(process.stdout, 'write').mockImplementation(() => null as unknown as boolean);
2121
process.env = { ...ENVIRONMENT_VARIABLES };
2222
});
2323

@@ -120,6 +120,8 @@ describe('Middy middleware', () => {
120120

121121
// Assess
122122
const expectation = expect.objectContaining({
123+
logsSampled: false,
124+
persistentLogAttributes: {},
123125
powertoolLogData: {
124126
sampleRateValue: undefined,
125127
awsRegion: 'eu-west-1',
@@ -135,8 +137,13 @@ describe('Middy middleware', () => {
135137
serviceName: 'hello-world',
136138
xRayTraceId: 'abcdef123456abcdef123456abcdef123456',
137139
},
140+
envVarsService: expect.any(EnvironmentVariablesService),
141+
customConfigService: undefined,
142+
logLevel: 'DEBUG',
143+
logFormatter: expect.any(PowertoolLogFormatter),
144+
console: expect.any(Console),
138145
});
139-
expect(logger).toEqual(anotherLogger);
146+
expect(logger).toEqual(expectation);
140147
expect(anotherLogger).toEqual(expectation);
141148

142149
});

0 commit comments

Comments
 (0)