Skip to content

Commit

Permalink
feat(metrics): publish metrics when other middlewares return early (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
dreamorosi authored Jun 22, 2023
1 parent 74ddb09 commit 58b0877
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 21 deletions.
15 changes: 15 additions & 0 deletions packages/metrics/src/middleware/middy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { METRICS_KEY } from '@aws-lambda-powertools/commons/lib/middleware';
import type { Metrics } from '../Metrics';
import type { ExtraOptions } from '../types';
import type {
Expand Down Expand Up @@ -38,6 +39,18 @@ const logMetrics = (
): MiddlewareLikeObj => {
const metricsInstances = target instanceof Array ? target : [target];

/**
* Set the cleanup function to be called in case other middlewares return early.
*
* @param request - The request object
*/
const setCleanupFunction = (request: MiddyLikeRequest): void => {
request.internal = {
...request.internal,
[METRICS_KEY]: logMetricsAfterOrError,
};
};

const logMetricsBefore = async (request: MiddyLikeRequest): Promise<void> => {
metricsInstances.forEach((metrics: Metrics) => {
metrics.setFunctionName(request.context.functionName);
Expand All @@ -53,6 +66,8 @@ const logMetrics = (
metrics.captureColdStartMetric();
}
});

setCleanupFunction(request);
};

const logMetricsAfterOrError = async (): Promise<void> => {
Expand Down
68 changes: 47 additions & 21 deletions packages/metrics/tests/unit/middleware/middy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,16 @@ import {
} from '../../../../metrics/src';
import middy from '@middy/core';
import { ExtraOptions } from '../../../src/types';
import { cleanupMiddlewares } from '@aws-lambda-powertools/commons/lib/middleware';
import { helloworldContext as dummyContext } from '../../../../commons/src/samples/resources/contexts/hello-world';
import { CustomEvent as dummyEvent } from '../../../../commons/src/samples/resources/events/custom/index';

const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();
const mockDate = new Date(1466424490000);
jest.spyOn(global, 'Date').mockImplementation(() => mockDate);

describe('Middy middleware', () => {
const dummyEvent = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
};
const dummyContext = {
callbackWaitsForEmptyEventLoop: true,
functionVersion: '$LATEST',
functionName: 'foo-bar-function',
memoryLimitInMB: '128',
logGroupName: '/aws/lambda/foo-bar-function-123456abcdef',
logStreamName: '2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456',
invokedFunctionArn:
'arn:aws:lambda:eu-west-1:123456789012:function:Example',
awsRequestId: 'c6af9ac6-7b61-11e6-9a41-93e812345678',
getRemainingTimeInMillis: () => 1234,
done: () => console.log('Done!'),
fail: () => console.log('Failed!'),
succeed: () => console.log('Succeeded!'),
};

beforeEach(() => {
jest.resetModules();
jest.clearAllMocks();
Expand Down Expand Up @@ -399,6 +381,50 @@ describe('Middy middleware', () => {
})
);
});

test('when enabled, and another middleware returns early, it still publishes the metrics at the end of the execution', async () => {
// Prepare
const metrics = new Metrics({
namespace: 'serverlessAirline',
serviceName: 'orders',
});
const publishStoredMetricsSpy = jest.spyOn(
metrics,
'publishStoredMetrics'
);
const myCustomMiddleware = (): middy.MiddlewareObj => {
const before = async (
request: middy.Request
): Promise<undefined | string> => {
// Return early on the second invocation
if (request.event.idx === 1) {
// Cleanup Powertools resources
await cleanupMiddlewares(request);

// Then return early
return 'foo';
}
};

return {
before,
};
};
const handler = middy(
(_event: typeof dummyEvent & { idx: number }): void => {
metrics.addMetric('successfulBooking', MetricUnits.Count, 1);
}
)
.use(logMetrics(metrics))
.use(myCustomMiddleware());

// Act
await handler({ ...dummyEvent, idx: 0 }, dummyContext);
await handler({ ...dummyEvent, idx: 1 }, dummyContext);

// Assess
expect(publishStoredMetricsSpy).toBeCalledTimes(2);
});
});
describe('Metrics resolution', () => {
test('serialized metrics in EMF format should not contain `StorageResolution` as key if `60` is set', async () => {
Expand Down

0 comments on commit 58b0877

Please sign in to comment.