Skip to content

Commit 31ae936

Browse files
authored
feat(metrics): log warning on empty metrics (#1397)
1 parent 9d53942 commit 31ae936

File tree

3 files changed

+79
-13
lines changed

3 files changed

+79
-13
lines changed

Diff for: packages/metrics/src/Metrics.ts

+6
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,12 @@ class Metrics extends Utility implements MetricsInterface {
330330
* ```
331331
*/
332332
public publishStoredMetrics(): void {
333+
if (!this.shouldThrowOnEmptyMetrics && Object.keys(this.storedMetrics).length === 0) {
334+
console.warn(
335+
'No application metrics to publish. The cold-start metric may be published if enabled. ' +
336+
'If application metrics should never be empty, consider using \'throwOnEmptyMetrics\'',
337+
);
338+
}
333339
const target = this.serializeMetrics();
334340
console.log(JSON.stringify(target));
335341
this.clearMetrics();

Diff for: packages/metrics/tests/unit/Metrics.test.ts

+60-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ describe('Class: Metrics', () => {
2525
const event = dummyEvent.Custom.CustomEvent;
2626

2727
beforeEach(() => {
28-
consoleSpy.mockClear();
28+
jest.clearAllMocks();
2929
});
3030

3131
beforeAll(() => {
@@ -464,6 +464,65 @@ describe('Class: Metrics', () => {
464464
expect((<Error>e).message).toBe('The number of metrics recorded must be higher than zero');
465465
}
466466
});
467+
468+
test('when decorator is used with throwOnEmptyMetrics set to false, a warning should be logged', async () => {
469+
470+
// Prepare
471+
const metrics = new Metrics({ namespace: 'test' });
472+
class LambdaFunction implements LambdaInterface {
473+
@metrics.logMetrics({ throwOnEmptyMetrics: false })
474+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
475+
// @ts-ignore
476+
public async handler<TEvent, TResult>(
477+
_event: TEvent,
478+
_context: Context,
479+
): Promise<void | TResult> {
480+
return;
481+
}
482+
}
483+
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();
484+
485+
// Act
486+
await new LambdaFunction().handler(event, context);
487+
488+
// Assess
489+
expect(consoleWarnSpy).toBeCalledTimes(1);
490+
expect(consoleWarnSpy).toBeCalledWith(
491+
'No application metrics to publish. The cold-start metric may be published if enabled. If application metrics should never be empty, consider using \'throwOnEmptyMetrics\'',
492+
);
493+
494+
});
495+
496+
test('when decorator is used with throwOnEmptyMetrics set to false & captureColdStartMetric set to true, a warning should be logged', async () => {
497+
498+
// Prepare
499+
const metrics = new Metrics({ namespace: 'test' });
500+
class LambdaFunction implements LambdaInterface {
501+
@metrics.logMetrics({
502+
throwOnEmptyMetrics: false,
503+
captureColdStartMetric: true
504+
})
505+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
506+
// @ts-ignore
507+
public async handler<TEvent, TResult>(
508+
_event: TEvent,
509+
_context: Context,
510+
): Promise<void | TResult> {
511+
return;
512+
}
513+
}
514+
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();
515+
516+
// Act
517+
await new LambdaFunction().handler(event, context);
518+
519+
// Assess
520+
expect(consoleWarnSpy).toBeCalledTimes(1);
521+
expect(consoleWarnSpy).toBeCalledWith(
522+
'No application metrics to publish. The cold-start metric may be published if enabled. If application metrics should never be empty, consider using \'throwOnEmptyMetrics\'',
523+
);
524+
525+
});
467526
});
468527

469528
describe('Feature: Auto log at limit', () => {

Diff for: packages/metrics/tests/unit/middleware/middy.test.ts

+13-12
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ import {
1313
import { ExtraOptions } from '../../../src/types';
1414

1515
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
16+
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();
1617
const mockDate = new Date(1466424490000);
17-
const dateSpy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate);
18+
jest.spyOn(global, 'Date').mockImplementation(() => mockDate);
1819

1920
describe('Middy middleware', () => {
2021

@@ -40,8 +41,7 @@ describe('Middy middleware', () => {
4041

4142
beforeEach(() => {
4243
jest.resetModules();
43-
consoleSpy.mockClear();
44-
dateSpy.mockClear();
44+
jest.clearAllMocks();
4545
});
4646

4747
describe('throwOnEmptyMetrics', () => {
@@ -80,21 +80,22 @@ describe('Middy middleware', () => {
8080
}
8181
});
8282

83-
test('should not throw on empty metrics if not set', async () => {
83+
test('should not throw on empty metrics if not set, but should log a warning', async () => {
84+
8485
// Prepare
8586
const metrics = new Metrics({ namespace: 'serverlessAirline', serviceName: 'orders' });
86-
87-
const lambdaHandler = (): void => {
87+
const lambdaHandler = async (): Promise<void> => {
8888
console.log('do nothing');
8989
};
90-
9190
const handler = middy(lambdaHandler).use(logMetrics(metrics));
9291

93-
try {
94-
await handler(dummyEvent, dummyContext, () => console.log('Lambda invoked!'));
95-
} catch (e) {
96-
fail(`Should not throw but got the following Error: ${e}`);
97-
}
92+
// Act & Assess
93+
await expect(handler(dummyEvent, dummyContext)).resolves.not.toThrowError();
94+
expect(consoleWarnSpy).toBeCalledTimes(1);
95+
expect(consoleWarnSpy).toBeCalledWith(
96+
'No application metrics to publish. The cold-start metric may be published if enabled. If application metrics should never be empty, consider using \'throwOnEmptyMetrics\'',
97+
);
98+
9899
});
99100
});
100101

0 commit comments

Comments
 (0)