Skip to content

Commit 3bb9c93

Browse files
authored
improv(metrics): avoid emitting empty EMF metric (#3044)
1 parent ce9c7f0 commit 3bb9c93

File tree

4 files changed

+86
-20
lines changed

4 files changed

+86
-20
lines changed

packages/metrics/src/Metrics.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -428,17 +428,15 @@ class Metrics extends Utility implements MetricsInterface {
428428
* ```
429429
*/
430430
public publishStoredMetrics(): void {
431-
if (
432-
!this.shouldThrowOnEmptyMetrics &&
433-
Object.keys(this.storedMetrics).length === 0
434-
) {
431+
const hasMetrics = Object.keys(this.storedMetrics).length > 0;
432+
if (!this.shouldThrowOnEmptyMetrics && !hasMetrics) {
435433
console.warn(
436434
'No application metrics to publish. The cold-start metric may be published if enabled. ' +
437435
'If application metrics should never be empty, consider using `throwOnEmptyMetrics`'
438436
);
439437
}
440-
const target = this.serializeMetrics();
441-
this.console.log(JSON.stringify(target));
438+
const emfOutput = this.serializeMetrics();
439+
hasMetrics && this.console.log(JSON.stringify(emfOutput));
442440
this.clearMetrics();
443441
this.clearDimensions();
444442
this.clearMetadata();

packages/metrics/tests/unit/Metrics.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,15 +1256,17 @@ describe('Class: Metrics', () => {
12561256
// Prepare
12571257
const metrics: Metrics = new Metrics({ namespace: TEST_NAMESPACE });
12581258
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();
1259+
const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
12591260

12601261
// Act
12611262
metrics.publishStoredMetrics();
12621263

12631264
// Assess
1264-
expect(consoleWarnSpy).toBeCalledTimes(1);
1265-
expect(consoleWarnSpy).toBeCalledWith(
1265+
expect(consoleWarnSpy).toHaveBeenCalledTimes(1);
1266+
expect(consoleWarnSpy).toHaveBeenCalledWith(
12661267
'No application metrics to publish. The cold-start metric may be published if enabled. If application metrics should never be empty, consider using `throwOnEmptyMetrics`'
12671268
);
1269+
expect(consoleLogSpy).not.toHaveBeenCalled();
12681270
});
12691271

12701272
test('it should call serializeMetrics && log the stringified return value of serializeMetrics', () => {

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

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,19 +107,16 @@ describe('Middy middleware', () => {
107107
await handler(event, context);
108108

109109
// Assess
110-
const loggedData = [
111-
JSON.parse(consoleSpy.mock.calls[0][0]),
112-
JSON.parse(consoleSpy.mock.calls[1][0]),
113-
];
114-
expect(consoleSpy).toBeCalledTimes(2);
115-
expect(loggedData[0]._aws.CloudWatchMetrics[0].Metrics.length).toBe(1);
116-
expect(loggedData[0]._aws.CloudWatchMetrics[0].Metrics[0].Name).toBe(
110+
expect(consoleSpy).toHaveBeenCalledTimes(1);
111+
const loggedData = JSON.parse(consoleSpy.mock.calls[0][0]);
112+
expect(loggedData._aws.CloudWatchMetrics[0].Metrics.length).toBe(1);
113+
expect(loggedData._aws.CloudWatchMetrics[0].Metrics[0].Name).toBe(
117114
'ColdStart'
118115
);
119-
expect(loggedData[0]._aws.CloudWatchMetrics[0].Metrics[0].Unit).toBe(
116+
expect(loggedData._aws.CloudWatchMetrics[0].Metrics[0].Unit).toBe(
120117
'Count'
121118
);
122-
expect(loggedData[0].ColdStart).toBe(1);
119+
expect(loggedData.ColdStart).toBe(1);
123120
});
124121

125122
test('should not capture cold start metrics if set to false', async () => {
@@ -143,9 +140,7 @@ describe('Middy middleware', () => {
143140
await handler(event, context);
144141

145142
// Assess
146-
const loggedData = JSON.parse(consoleSpy.mock.calls[0][0]);
147-
148-
expect(loggedData._aws.CloudWatchMetrics[0].Metrics.length).toBe(0);
143+
expect(consoleSpy).not.toHaveBeenCalled();
149144
});
150145

151146
test('should not throw on empty metrics if not set', async () => {
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import middy from '@middy/core';
2+
import type { Context } from 'aws-lambda';
3+
import { Metrics } from '../../src/Metrics.js';
4+
import { logMetrics } from '../../src/middleware/middy.js';
5+
6+
describe('Metrics', () => {
7+
beforeAll(() => {
8+
jest.spyOn(console, 'warn').mockImplementation();
9+
});
10+
11+
afterEach(() => {
12+
jest.resetAllMocks();
13+
});
14+
15+
it('does not log', () => {
16+
process.env.POWERTOOLS_DEV = 'true';
17+
const metrics = new Metrics({
18+
serviceName: 'foo',
19+
namespace: 'bar',
20+
defaultDimensions: {
21+
aws_account_id: '123456789012',
22+
aws_region: 'us-west-2',
23+
},
24+
});
25+
const logSpy = jest.spyOn(console, 'log').mockImplementation();
26+
27+
metrics.publishStoredMetrics();
28+
29+
expect(logSpy).toHaveBeenCalledTimes(0);
30+
});
31+
32+
it('does log because of captureColdStartMetric enabled', () => {
33+
process.env.POWERTOOLS_DEV = 'true';
34+
const metrics = new Metrics({
35+
serviceName: 'foo',
36+
namespace: 'bar',
37+
defaultDimensions: {
38+
aws_account_id: '123456789012',
39+
aws_region: 'us-west-2',
40+
},
41+
});
42+
const logSpy = jest.spyOn(console, 'log').mockImplementation();
43+
const handler = middy(() => {}).use(
44+
logMetrics(metrics, { captureColdStartMetric: true })
45+
);
46+
47+
handler({}, {} as Context);
48+
49+
expect(logSpy).toHaveBeenCalledTimes(1);
50+
});
51+
52+
it('does not log because of captureColdStartMetric disabled', () => {
53+
process.env.POWERTOOLS_DEV = 'true';
54+
const metrics = new Metrics({
55+
serviceName: 'foo',
56+
namespace: 'bar',
57+
defaultDimensions: {
58+
aws_account_id: '123456789012',
59+
aws_region: 'us-west-2',
60+
},
61+
});
62+
const logSpy = jest.spyOn(console, 'log').mockImplementation();
63+
const handler = middy(() => {}).use(
64+
logMetrics(metrics, { captureColdStartMetric: false })
65+
);
66+
67+
handler({}, {} as Context);
68+
69+
expect(logSpy).toHaveBeenCalledTimes(0);
70+
});
71+
});

0 commit comments

Comments
 (0)