Skip to content

Commit 1e1fcbc

Browse files
committed
feat(logger): middy middleware
1 parent f92279f commit 1e1fcbc

File tree

16 files changed

+313
-38
lines changed

16 files changed

+313
-38
lines changed

packages/logger/examples/inject-context-decorator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ process.env.POWERTOOLS_SERVICE_NAME = 'hello-world';
77

88
import * as dummyEvent from '../../../tests/resources/events/custom/hello-world.json';
99
import { context as dummyContext } from '../../../tests/resources/contexts/hello-world';
10-
import { LambdaInterface } from './utils/lambda/LambdaInterface';
10+
import { LambdaInterface } from '../types/LambdaInterface';
1111
import { Logger } from '../src';
1212
import { Callback, Context } from 'aws-lambda/handler';
1313

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Populate runtime
2+
require('./../tests/helpers/populateEnvironmentVariables');
3+
4+
// Additional runtime variables
5+
process.env.LOG_LEVEL = 'INFO';
6+
process.env.POWERTOOLS_SERVICE_NAME = 'hello-world';
7+
8+
import { Handler } from 'aws-lambda';
9+
import { Logger } from '../src';
10+
import { injectLambdaContext } from '../src/middleware/middy';
11+
import middy from '@middy/core';
12+
13+
const logger = new Logger();
14+
15+
const lambdaHandler: Handler = async () => {
16+
17+
logger.debug('This is a DEBUG log');
18+
logger.info('This is an INFO log');
19+
logger.warn('This is a WARN log');
20+
logger.error('This is an ERROR log');
21+
22+
return {
23+
foo: 'bar'
24+
};
25+
26+
};
27+
28+
const lambdaHandlerWithMiddleware = middy(lambdaHandler)
29+
.use(injectLambdaContext(logger));
30+

packages/logger/examples/utils/lambda/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

packages/logger/npm-shrinkwrap.json

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

packages/logger/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"example:hello-world": "ts-node examples/hello-world.ts",
2222
"example:inject-context": "ts-node examples/inject-context.ts",
2323
"example:inject-context-decorator": "ts-node examples/inject-context-decorator.ts",
24+
"example:inject-context-middleware": "ts-node examples/inject-context-middleware.ts",
2425
"example:errors": "ts-node examples/errors.ts",
2526
"example:constructor-options": "ts-node examples/constructor-options.ts",
2627
"example:custom-log-formatter": "ts-node examples/custom-log-formatter.ts",
@@ -61,9 +62,10 @@
6162
"url": "https://github.com/awslabs/aws-lambda-powertools-typescript/issues"
6263
},
6364
"dependencies": {
65+
"@middy/core": "^2.5.3",
66+
"@types/aws-lambda": "^8.10.72",
6467
"lodash": "^4.17.21",
6568
"lodash.clonedeep": "^4.5.0",
66-
"lodash.merge": "^4.6.2",
67-
"@types/aws-lambda": "^8.10.72"
69+
"lodash.merge": "^4.6.2"
6870
}
6971
}

packages/logger/src/Logger.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { Context } from 'aws-lambda';
1+
import type { Context } from 'aws-lambda';
22

33
import { cloneDeep, merge } from 'lodash/fp';
4-
import {
4+
import type {
55
Environment,
66
HandlerMethodDecorator,
77
LambdaFunctionContext,
@@ -19,17 +19,8 @@ import { LogFormatterInterface, PowertoolLogFormatter } from './formatter';
1919
import { LogItem } from './log';
2020

2121
class Logger implements ClassThatLogs {
22-
public static coldStart: boolean = true;
2322

24-
public static isColdStart(): boolean {
25-
if (Logger.coldStart === true) {
26-
Logger.coldStart = false;
27-
28-
return true;
29-
}
30-
31-
return false;
32-
}
23+
public static coldStart?: boolean;
3324

3425
private static readonly defaultLogLevel: LogLevel = 'INFO';
3526

@@ -61,9 +52,10 @@ class Logger implements ClassThatLogs {
6152
}
6253

6354
public addContext(context: Context): void {
55+
Logger.evaluateColdStart();
6456
const lambdaContext: Partial<LambdaFunctionContext> = {
6557
invokedFunctionArn: context.invokedFunctionArn,
66-
coldStart: Logger.isColdStart(),
58+
coldStart: Logger.coldStart,
6759
awsRequestId: context.awsRequestId,
6860
memoryLimitInMB: Number(context.memoryLimitInMB),
6961
functionName: context.functionName,
@@ -170,6 +162,26 @@ class Logger implements ClassThatLogs {
170162
return logItem;
171163
}
172164

165+
private static evaluateColdStart = (() => {
166+
let evaluated = false;
167+
return function() {
168+
if (!evaluated) {
169+
evaluated = true;
170+
if(typeof Logger.coldStart === 'undefined') {
171+
Logger.coldStart = true;
172+
return;
173+
}
174+
if(Logger.coldStart === true) {
175+
Logger.coldStart = false;
176+
return;
177+
}
178+
179+
Logger.coldStart = false;
180+
181+
}
182+
};
183+
})()
184+
173185
private getCustomConfigService(): ConfigServiceInterface | undefined {
174186
return this.customConfigService;
175187
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { Logger } from '../Logger';
2+
import middy from '@middy/core';
3+
4+
const injectLambdaContext = (target: Logger | Logger[]): middy.MiddlewareObj => {
5+
const injectLambdaContextBefore = async (request: middy.Request): Promise<void> => {
6+
const loggers = target instanceof Array ? target : [ target ];
7+
loggers.forEach((logger: Logger) => {
8+
logger.addContext(request.context);
9+
console.log('foo', logger);
10+
})
11+
};
12+
return {
13+
before: injectLambdaContextBefore,
14+
};
15+
};
16+
17+
export {
18+
injectLambdaContext,
19+
};

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

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import { Callback, Context } from 'aws-lambda/handler';
1+
import { Callback, Context, Handler } from 'aws-lambda/handler';
22
import { context as dummyContext } from '../../../../tests/resources/contexts/hello-world';
33
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
44
// @ts-ignore
55
import * as dummyEvent from '../../../../tests/resources/events/custom/hello-world.json';
6-
import { LambdaInterface } from '../../examples/utils/lambda';
76
import { createLogger, Logger } from '../../src';
87
import { EnvironmentVariablesService } from '../../src/config';
98
import { PowertoolLogFormatter } from '../../src/formatter';
10-
import { ClassThatLogs } from '../../types';
9+
import { ClassThatLogs, LambdaInterface } from '../../types';
10+
import middy from '@middy/core';
11+
import { injectLambdaContext } from '../../src/middleware/middy';
1112

1213
const mockDate = new Date(1466424490000);
1314
const dateSpy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate as unknown as string);
@@ -17,7 +18,7 @@ const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
1718
describe('Class: Logger', () => {
1819

1920
beforeEach(() => {
20-
Logger.coldStart = true;
21+
jest.resetModules();
2122
consoleSpy.mockClear();
2223
dateSpy.mockClear();
2324
});
@@ -510,13 +511,72 @@ describe('Class: Logger', () => {
510511

511512
describe('Method: isColdStart', () => {
512513

513-
test('when called, it returns false the first time and always true after that', () => {
514+
test('when called during an invocation experiencing a cold start, it returns true', async () => {
515+
516+
// Prepare
517+
const logger = new Logger();
518+
const handler: Handler = (_event, context: Context): void => {
519+
logger.addContext(context);
520+
logger.info('This is an INFO log with some context');
521+
}
522+
const event = { foo: 'bar' };
523+
const context = {
524+
callbackWaitsForEmptyEventLoop: true,
525+
functionVersion: '$LATEST',
526+
functionName: 'foo-bar-function',
527+
memoryLimitInMB: '128',
528+
logGroupName: '/aws/lambda/foo-bar-function-123456abcdef',
529+
logStreamName: '2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456',
530+
invokedFunctionArn: 'arn:aws:lambda:eu-central-1:123456789012:function:Example',
531+
awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e8deadbeef',
532+
getRemainingTimeInMillis: () => 1234,
533+
done: () => console.log('Done!'),
534+
fail: () => console.log('Failed!'),
535+
succeed: () => console.log('Succeeded!'),
536+
};
537+
538+
// Act
539+
await handler(event, context, () => console.log('Lambda invoked!'))
540+
const coldStartValue = Logger.coldStart;
541+
542+
// Assess
543+
expect(coldStartValue).toEqual(true);
544+
545+
});
546+
547+
test.only('when called during an invocation not experiencing a cold start, it returns false', async () => {
548+
549+
// Prepare
550+
Logger.coldStart = true;
551+
const logger = new Logger();
552+
const handler: Handler = (_event, context: Context): void => {
553+
logger.addContext(context);
554+
logger.info('This is an INFO log with some context');
555+
}
556+
557+
const warmStartInvocationEvent = { foo: 'bar' };
558+
559+
const warmStartInvocationContext = {
560+
callbackWaitsForEmptyEventLoop: true,
561+
functionVersion: '$LATEST',
562+
functionName: 'foo-bar-function',
563+
memoryLimitInMB: '128',
564+
logGroupName: '/aws/lambda/foo-bar-function-123456abcdef',
565+
logStreamName: '2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456',
566+
invokedFunctionArn: 'arn:aws:lambda:eu-central-1:123456789012:function:Example',
567+
awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e8deadbeef',
568+
getRemainingTimeInMillis: () => 1234,
569+
done: () => console.log('Done!'),
570+
fail: () => console.log('Failed!'),
571+
succeed: () => console.log('Succeeded!'),
572+
};
573+
574+
// Act
575+
await handler(warmStartInvocationEvent, warmStartInvocationContext, () => console.log('Lambda invoked!'));
576+
const warmStartValue = Logger.coldStart;
514577

515578
// Assess
516-
expect(Logger.isColdStart()).toBe(true);
517-
expect(Logger.isColdStart()).toBe(false);
518-
expect(Logger.isColdStart()).toBe(false);
519-
expect(Logger.isColdStart()).toBe(false);
579+
expect(Logger).toEqual(foo);
520580

521581
});
522582

0 commit comments

Comments
 (0)