Skip to content

Commit

Permalink
fix(logger|metrics): properly return decorated class (#489)
Browse files Browse the repository at this point in the history
* fix: logger to return decorated class

* fix: metrics to return decorated class

* chore: remove leftover files from logger
  • Loading branch information
dreamorosi authored Jan 24, 2022
1 parent 988578c commit 014c5bd
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 12 deletions.
4 changes: 2 additions & 2 deletions packages/logger/src/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,13 +282,13 @@ class Logger implements ClassThatLogs {
* @returns {HandlerMethodDecorator}
*/
public injectLambdaContext(): HandlerMethodDecorator {
return (target, propertyKey, descriptor) => {
return (target, _propertyKey, descriptor) => {
const originalMethod = descriptor.value;

descriptor.value = (event, context, callback) => {
this.addContext(context);

return originalMethod?.apply(this, [ event, context, callback ]);
return originalMethod?.apply(target, [ event, context, callback ]);
};
};
}
Expand Down
39 changes: 39 additions & 0 deletions packages/logger/tests/unit/Logger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,45 @@ describe('Class: Logger', () => {
jest.spyOn(console, 'log').mockImplementation(() => {});
});

test('when used as decorator, it returns a function with the correct scope of the decorated class', async () => {

// Prepare
const logger = new Logger();
class LambdaFunction implements LambdaInterface {

@logger.injectLambdaContext()
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
public handler<TEvent, TResult>(_event: TEvent, _context: Context, _callback: Callback<TResult>): void | Promise<TResult> {
this.myClassMethod();
}

private myClassMethod (): void {
logger.info('This is an INFO log with some context');
}

}

// Act
await new LambdaFunction().handler(dummyEvent, dummyContext, () => console.log('Lambda invoked!'));

// Assess
expect(console['info']).toBeCalledTimes(1);
expect(console['info']).toHaveBeenNthCalledWith(1, JSON.stringify({
cold_start: true,
function_arn: 'arn:aws:lambda:eu-central-1:123456789012:function:foo-bar-function',
function_memory_size: 128,
function_name: 'foo-bar-function',
function_request_id: 'c6af9ac6-7b61-11e6-9a41-93e812345678',
level: 'INFO',
message: 'This is an INFO log with some context',
service: 'hello-world',
timestamp: '2016-06-20T12:08:10.000Z',
xray_trace_id: 'abcdef123456abcdef123456abcdef123456',
}));

});

test('when used as decorator, it returns a function that captures Lambda\'s context information and adds it in the printed logs', async () => {

// Prepare
Expand Down
9 changes: 0 additions & 9 deletions packages/logger/types/LambdaInterface.ts

This file was deleted.

Empty file removed packages/logger/types/Logger.ts
Empty file.
2 changes: 1 addition & 1 deletion packages/metrics/src/Metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ class Metrics implements MetricsInterface {

let result: unknown;
try {
result = await originalMethod?.apply(this, [ event, context, callback ]);
result = await originalMethod?.apply(target, [ event, context, callback ]);
} catch (error) {
throw error;
} finally {
Expand Down
31 changes: 31 additions & 0 deletions packages/metrics/tests/unit/Metrics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,12 +535,43 @@ describe('Class: Metrics', () => {
expect(loggedData[1]._aws.CloudWatchMetrics[0].Metrics.length).toBe(0);
});

test('Using decorator, it returns a function with the correct scope of the decorated class', async () => {

// Prepare
const metrics = new Metrics({ namespace: 'test' });
class LambdaFunction implements LambdaInterface {
@metrics.logMetrics({ defaultDimensions: { default: 'defaultValue' } })
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
public async handler<TEvent>(
_event: TEvent,
_context: Context): Promise<string> {
this.myMethod();

return 'Lambda invoked!';
}

private myMethod(): void {
metrics.addMetric('test_name', MetricUnits.Seconds, 10);
}
}

// Act
await new LambdaFunction().handler(dummyEvent, dummyContext.helloworldContext);

// Assess
expect(console.log).toBeCalledTimes(1);

});

test('Using decorator on async handler (without callback) should work fine', async () => {
const metrics = new Metrics({ namespace: 'test' });
const additionalDimension = { name: 'metric2', value: 'metric2Value' };

class LambdaFunction implements LambdaInterface {
@metrics.logMetrics({ defaultDimensions: { default: 'defaultValue' } })
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
public async handler<TEvent>(
_event: TEvent,
_context: Context): Promise<string> {
Expand Down

0 comments on commit 014c5bd

Please sign in to comment.