From 07e9374e2cf1e0cd71d40641e179f76db737dc96 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 8 Nov 2023 10:27:22 +0000 Subject: [PATCH 1/4] chore(commons): move isDevMode to commons --- packages/commons/src/config/ConfigService.ts | 7 +++ .../src/config/EnvironmentVariablesService.ts | 12 ++++- .../EnvironmentVariablesService.test.ts | 50 +++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/packages/commons/src/config/ConfigService.ts b/packages/commons/src/config/ConfigService.ts index e149c27229..df2d69bd81 100644 --- a/packages/commons/src/config/ConfigService.ts +++ b/packages/commons/src/config/ConfigService.ts @@ -35,6 +35,13 @@ abstract class ConfigService { */ public abstract getXrayTraceId(): string | undefined; + /** + * It returns true if the `POWERTOOLS_DEV` environment variable is set to truthy value. + * + * @returns {boolean} + */ + public abstract isDevMode(): boolean; + /** * It returns true if the string value represents a boolean true value. * diff --git a/packages/commons/src/config/EnvironmentVariablesService.ts b/packages/commons/src/config/EnvironmentVariablesService.ts index 59183a15d4..f222fccfb8 100644 --- a/packages/commons/src/config/EnvironmentVariablesService.ts +++ b/packages/commons/src/config/EnvironmentVariablesService.ts @@ -13,11 +13,12 @@ import { ConfigService } from './ConfigService'; * @see https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime * @see https://docs.powertools.aws.dev/lambda/typescript/latest/#environment-variables */ -class EnvironmentVariablesService extends ConfigService { +class EnvironmentVariablesService implements ConfigService { /** * @see https://docs.powertools.aws.dev/lambda/typescript/latest/#environment-variables * @protected */ + protected devModeVariable = 'POWERTOOLS_DEV'; protected serviceNameVariable = 'POWERTOOLS_SERVICE_NAME'; // Reserved environment variables private xRayTraceIdVariable = '_X_AMZN_TRACE_ID'; @@ -71,6 +72,15 @@ class EnvironmentVariablesService extends ConfigService { return xRayTraceData?.Sampled === '1'; } + /** + * It returns true if the `POWERTOOLS_DEV` environment variable is set to truthy value. + * + * @returns {boolean} + */ + public isDevMode(): boolean { + return this.isValueTrue(this.get(this.devModeVariable)); + } + /** * It returns true if the string value represents a boolean true value. * diff --git a/packages/commons/tests/unit/config/EnvironmentVariablesService.test.ts b/packages/commons/tests/unit/config/EnvironmentVariablesService.test.ts index 055a57ac61..b1e90b6b08 100644 --- a/packages/commons/tests/unit/config/EnvironmentVariablesService.test.ts +++ b/packages/commons/tests/unit/config/EnvironmentVariablesService.test.ts @@ -163,4 +163,54 @@ describe('Class: EnvironmentVariablesService', () => { } ); }); + + describe('Method: isDevMode', () => { + test('it returns true if the environment variable POWERTOOLS_DEV is "true"', () => { + // Prepare + process.env.POWERTOOLS_DEV = 'true'; + const service = new EnvironmentVariablesService(); + + // Act + const value = service.isDevMode(); + + // Assess + expect(value).toEqual(true); + }); + + test('it returns false if the environment variable POWERTOOLS_DEV is "false"', () => { + // Prepare + process.env.POWERTOOLS_DEV = 'false'; + const service = new EnvironmentVariablesService(); + + // Act + const value = service.isDevMode(); + + // Assess + expect(value).toEqual(false); + }); + + test('it returns false if the environment variable POWERTOOLS_DEV is NOT set', () => { + // Prepare + process.env.POWERTOOLS_DEV = 'somethingsilly'; + const service = new EnvironmentVariablesService(); + + // Act + const value = service.isDevMode(); + + // Assess + expect(value).toEqual(false); + }); + + test('it returns false if the environment variable POWERTOOLS_DEV is "somethingsilly"', () => { + // Prepare + process.env.POWERTOOLS_DEV = 'somethingsilly'; + const service = new EnvironmentVariablesService(); + + // Act + const value = service.isDevMode(); + + // Assess + expect(value).toEqual(false); + }); + }); }); From c586625935471cbd28e02031ce0bb4cb633ea8a8 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 8 Nov 2023 17:34:51 +0000 Subject: [PATCH 2/4] chore(logger): move isDev config out of logger to commons --- .../src/config/EnvironmentVariablesService.ts | 12 ----- .../EnvironmentVariablesService.test.ts | 50 ------------------- 2 files changed, 62 deletions(-) diff --git a/packages/logger/src/config/EnvironmentVariablesService.ts b/packages/logger/src/config/EnvironmentVariablesService.ts index d2eae54972..edace97de3 100644 --- a/packages/logger/src/config/EnvironmentVariablesService.ts +++ b/packages/logger/src/config/EnvironmentVariablesService.ts @@ -22,7 +22,6 @@ class EnvironmentVariablesService // Reserved environment variables private awsRegionVariable = 'AWS_REGION'; private currentEnvironmentVariable = 'ENVIRONMENT'; - private devModeVariable = 'POWERTOOLS_DEV'; private functionNameVariable = 'AWS_LAMBDA_FUNCTION_NAME'; private functionVersionVariable = 'AWS_LAMBDA_FUNCTION_VERSION'; private logEventVariable = 'POWERTOOLS_LOGGER_LOG_EVENT'; @@ -107,17 +106,6 @@ class EnvironmentVariablesService return value && value.length > 0 ? Number(value) : undefined; } - - /** - * It returns true if the POWERTOOLS_DEV environment variable is set to truthy value. - * - * @returns {boolean} - */ - public isDevMode(): boolean { - const value = this.get(this.devModeVariable); - - return this.isValueTrue(value); - } } export { EnvironmentVariablesService }; diff --git a/packages/logger/tests/unit/config/EnvironmentVariablesService.test.ts b/packages/logger/tests/unit/config/EnvironmentVariablesService.test.ts index fb6b7ed232..b5a212ab1a 100644 --- a/packages/logger/tests/unit/config/EnvironmentVariablesService.test.ts +++ b/packages/logger/tests/unit/config/EnvironmentVariablesService.test.ts @@ -152,54 +152,4 @@ describe('Class: EnvironmentVariablesService', () => { expect(value).toEqual(0.01); }); }); - - describe('Method: isDevMode', () => { - test('it returns true if the environment variable POWERTOOLS_DEV is "true"', () => { - // Prepare - process.env.POWERTOOLS_DEV = 'true'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.isDevMode(); - - // Assess - expect(value).toEqual(true); - }); - - test('it returns false if the environment variable POWERTOOLS_DEV is "false"', () => { - // Prepare - process.env.POWERTOOLS_DEV = 'false'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.isDevMode(); - - // Assess - expect(value).toEqual(false); - }); - - test('it returns false if the environment variable POWERTOOLS_DEV is NOT set', () => { - // Prepare - process.env.POWERTOOLS_DEV = 'somethingsilly'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.isDevMode(); - - // Assess - expect(value).toEqual(false); - }); - - test('it returns false if the environment variable POWERTOOLS_DEV is "somethingsilly"', () => { - // Prepare - process.env.POWERTOOLS_DEV = 'somethingsilly'; - const service = new EnvironmentVariablesService(); - - // Act - const value = service.isDevMode(); - - // Assess - expect(value).toEqual(false); - }); - }); }); From ad0f4e7c9d858786bd7efc3e4dd9a9a696f385f5 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 8 Nov 2023 17:35:22 +0000 Subject: [PATCH 3/4] feat(metrics): use own console object by default --- packages/metrics/src/Metrics.ts | 34 +- .../src/config/ConfigServiceInterface.ts | 6 + packages/metrics/tests/unit/Metrics.test.ts | 27 +- .../tests/unit/middleware/middy.test.ts | 327 +++++------------- 4 files changed, 143 insertions(+), 251 deletions(-) diff --git a/packages/metrics/src/Metrics.ts b/packages/metrics/src/Metrics.ts index 5bf9fba97f..f968d9d70b 100644 --- a/packages/metrics/src/Metrics.ts +++ b/packages/metrics/src/Metrics.ts @@ -1,4 +1,5 @@ import type { Callback, Context, Handler } from 'aws-lambda'; +import { Console } from 'node:console'; import { Utility } from '@aws-lambda-powertools/commons'; import type { MetricsInterface } from './MetricsInterface'; import { @@ -109,6 +110,18 @@ import { * ``` */ class Metrics extends Utility implements MetricsInterface { + /** + * Console instance used to print logs. + * + * In AWS Lambda, we create a new instance of the Console class so that we can have + * full control over the output of the logs. In testing environments, we use the + * default console instance. + * + * This property is initialized in the constructor in setOptions(). + * + * @private + */ + private console!: Console; private customConfigService?: ConfigServiceInterface; private defaultDimensions: Dimensions = {}; private dimensions: Dimensions = {}; @@ -388,7 +401,7 @@ class Metrics extends Utility implements MetricsInterface { ); } const target = this.serializeMetrics(); - console.log(JSON.stringify(target)); + this.console.log(JSON.stringify(target)); this.clearMetrics(); this.clearDimensions(); this.clearMetadata(); @@ -591,6 +604,24 @@ class Metrics extends Utility implements MetricsInterface { } } + /** + * It initializes console property as an instance of the internal version of Console() class (PR #748) + * or as the global node console if the `POWERTOOLS_DEV' env variable is set and has truthy value. + * + * @private + * @returns {void} + */ + private setConsole(): void { + if (!this.getEnvVarsService().isDevMode()) { + this.console = new Console({ + stdout: process.stdout, + stderr: process.stderr, + }); + } else { + this.console = console; + } + } + /** * Sets the custom config service to be used. * @@ -640,6 +671,7 @@ class Metrics extends Utility implements MetricsInterface { } = options; this.setEnvVarsService(); + this.setConsole(); this.setCustomConfigService(customConfigService); this.setNamespace(namespace); this.setService(serviceName); diff --git a/packages/metrics/src/config/ConfigServiceInterface.ts b/packages/metrics/src/config/ConfigServiceInterface.ts index ea1c127db6..72ddf7c4f4 100644 --- a/packages/metrics/src/config/ConfigServiceInterface.ts +++ b/packages/metrics/src/config/ConfigServiceInterface.ts @@ -2,6 +2,12 @@ interface ConfigServiceInterface { get?(name: string): string; getNamespace(): string; getServiceName(): string; + /** + * It returns the value of the POWERTOOLS_DEV environment variable. + * + * @returns {boolean} + */ + isDevMode(): boolean; } export { ConfigServiceInterface }; diff --git a/packages/metrics/tests/unit/Metrics.test.ts b/packages/metrics/tests/unit/Metrics.test.ts index 936ea142eb..c613b0535d 100644 --- a/packages/metrics/tests/unit/Metrics.test.ts +++ b/packages/metrics/tests/unit/Metrics.test.ts @@ -24,6 +24,13 @@ import { EnvironmentVariablesService, } from '../../src/config'; +jest.mock('node:console', () => ({ + ...jest.requireActual('node:console'), + Console: jest.fn().mockImplementation(() => ({ + log: jest.fn(), + })), +})); +jest.spyOn(console, 'warn').mockImplementation(() => ({})); const mockDate = new Date(1466424490000); const dateSpy = jest.spyOn(global, 'Date').mockImplementation(() => mockDate); jest.spyOn(console, 'log').mockImplementation(); @@ -234,6 +241,9 @@ describe('Class: Metrics', () => { getServiceName(): string { return 'test-service'; }, + isDevMode(): boolean { + return false; + }, }; const metricsOptions: MetricsOptions = { customConfigService: configService, @@ -703,7 +713,7 @@ describe('Class: Metrics', () => { test('it should publish metrics when the array of values reaches the maximum size', () => { // Prepare const metrics: Metrics = new Metrics({ namespace: TEST_NAMESPACE }); - const consoleSpy = jest.spyOn(console, 'log'); + const consoleSpy = jest.spyOn(metrics['console'], 'log'); const metricName = 'test-metric'; // Act @@ -1246,7 +1256,9 @@ describe('Class: Metrics', () => { // Prepare const metrics: Metrics = new Metrics({ namespace: TEST_NAMESPACE }); metrics.addMetric('test-metric', MetricUnits.Count, 10); - const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(); + const consoleLogSpy = jest + .spyOn(metrics['console'], 'log') + .mockImplementation(); const mockData: EmfOutput = { _aws: { Timestamp: mockDate.getTime(), @@ -2183,4 +2195,15 @@ describe('Class: Metrics', () => { ); }); }); + + describe('Feature: POWERTOOLS_DEV', () => { + it('uses the global console object when the environment variable is set', () => { + // Prepare + process.env.POWERTOOLS_DEV = 'true'; + const metrics: Metrics = new Metrics({ namespace: TEST_NAMESPACE }); + + // Act & Assess + expect(metrics['console']).toEqual(console); + }); + }); }); diff --git a/packages/metrics/tests/unit/middleware/middy.test.ts b/packages/metrics/tests/unit/middleware/middy.test.ts index 5713bcbe9c..5c1e22af48 100644 --- a/packages/metrics/tests/unit/middleware/middy.test.ts +++ b/packages/metrics/tests/unit/middleware/middy.test.ts @@ -3,27 +3,29 @@ * * @group unit/metrics/middleware */ -import { - Metrics, - MetricUnits, - logMetrics, - MetricResolution, -} from '../../../../metrics/src'; +import { Metrics, MetricUnits, logMetrics } 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 '@aws-lambda-powertools/commons/lib/samples/resources/contexts/hello-world'; import { CustomEvent as dummyEvent } from '@aws-lambda-powertools/commons/lib/samples/resources/events/custom/index'; -const consoleSpy = jest.spyOn(console, 'log').mockImplementation(); -const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(); +jest.mock('node:console', () => ({ + ...jest.requireActual('node:console'), + Console: jest.fn().mockImplementation(() => ({ + log: jest.fn(), + })), +})); +jest.spyOn(console, 'warn').mockImplementation(() => ({})); const mockDate = new Date(1466424490000); jest.spyOn(global, 'Date').mockImplementation(() => mockDate); describe('Middy middleware', () => { + const ENVIRONMENT_VARIABLES = process.env; + beforeEach(() => { - jest.resetModules(); jest.clearAllMocks(); + process.env = { ...ENVIRONMENT_VARIABLES }; }); describe('throwOnEmptyMetrics', () => { @@ -33,24 +35,13 @@ describe('Middy middleware', () => { namespace: 'serverlessAirline', serviceName: 'orders', }); - - const lambdaHandler = (): void => { - console.log('do nothing'); - }; - - const handler = middy(lambdaHandler).use( + const handler = middy(async (): Promise => undefined).use( logMetrics(metrics, { throwOnEmptyMetrics: true }) ); - try { - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked!') - ); - } catch (e) { - expect((e).message).toBe( - 'The number of metrics recorded must be higher than zero' - ); - } + await expect(handler(dummyEvent, dummyContext)).rejects.toThrowError( + 'The number of metrics recorded must be higher than zero' + ); }); test('should not throw on empty metrics if set to false', async () => { @@ -59,22 +50,14 @@ describe('Middy middleware', () => { namespace: 'serverlessAirline', serviceName: 'orders', }); - - const lambdaHandler = (): void => { - console.log('do nothing'); - }; - - const handler = middy(lambdaHandler).use( + const handler = middy(async (): Promise => undefined).use( logMetrics(metrics, { throwOnEmptyMetrics: false }) ); - try { - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked!') - ); - } catch (e) { - fail(`Should not throw but got the following Error: ${e}`); - } + // Act & Assess + await expect( + handler(dummyEvent, dummyContext) + ).resolves.not.toThrowError(); }); test('should not throw on empty metrics if not set, but should log a warning', async () => { @@ -83,10 +66,10 @@ describe('Middy middleware', () => { namespace: 'serverlessAirline', serviceName: 'orders', }); - const lambdaHandler = async (): Promise => { - console.log('do nothing'); - }; - const handler = middy(lambdaHandler).use(logMetrics(metrics)); + const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(); + const handler = middy(async (): Promise => undefined).use( + logMetrics([metrics]) + ); // Act & Assess await expect( @@ -106,27 +89,27 @@ describe('Middy middleware', () => { namespace: 'serverlessAirline', serviceName: 'orders', }); - - const lambdaHandler = (): void => { - console.log('{"message": "do nothing"}'); - }; - - const handler = middy(lambdaHandler).use( + const consoleSpy = jest + .spyOn(metrics['console'], 'log') + .mockImplementation(); + // Monkey patch the singleMetric method to return the metrics instance + // so that we can assert on the console output + jest.spyOn(metrics, 'singleMetric').mockImplementation(() => metrics); + + const handler = middy(async (): Promise => undefined).use( logMetrics(metrics, { captureColdStartMetric: true }) ); - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked!') - ); - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked! again') - ); + // Act + await handler(dummyEvent, dummyContext); + await handler(dummyEvent, dummyContext); + + // Assess const loggedData = [ JSON.parse(consoleSpy.mock.calls[0][0]), JSON.parse(consoleSpy.mock.calls[1][0]), ]; - - expect(console.log).toBeCalledTimes(5); + expect(consoleSpy).toBeCalledTimes(2); expect(loggedData[0]._aws.CloudWatchMetrics[0].Metrics.length).toBe(1); expect(loggedData[0]._aws.CloudWatchMetrics[0].Metrics[0].Name).toBe( 'ColdStart' @@ -143,27 +126,23 @@ describe('Middy middleware', () => { namespace: 'serverlessAirline', serviceName: 'orders', }); - - const lambdaHandler = (): void => { - console.log('{"message": "do nothing"}'); - }; - - const handler = middy(lambdaHandler).use( + const consoleSpy = jest + .spyOn(metrics['console'], 'log') + .mockImplementation(); + // Monkey patch the singleMetric method to return the metrics instance + // so that we can assert on the console output + jest.spyOn(metrics, 'singleMetric').mockImplementation(() => metrics); + const handler = middy(async (): Promise => undefined).use( logMetrics(metrics, { captureColdStartMetric: false }) ); - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked!') - ); - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked! again') - ); - const loggedData = [ - JSON.parse(consoleSpy.mock.calls[0][0]), - JSON.parse(consoleSpy.mock.calls[1][0]), - ]; + // Act + await handler(dummyEvent, dummyContext); + + // Assess + const loggedData = JSON.parse(consoleSpy.mock.calls[0][0]); - expect(loggedData[0]._aws).toBe(undefined); + expect(loggedData._aws.CloudWatchMetrics[0].Metrics.length).toBe(0); }); test('should not throw on empty metrics if not set', async () => { @@ -172,25 +151,12 @@ describe('Middy middleware', () => { namespace: 'serverlessAirline', serviceName: 'orders', }); - - const lambdaHandler = (): void => { - console.log('{"message": "do nothing"}'); - }; - - const handler = middy(lambdaHandler).use(logMetrics(metrics)); - - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked!') - ); - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked! again') + const handler = middy(async (): Promise => undefined).use( + logMetrics(metrics) ); - const loggedData = [ - JSON.parse(consoleSpy.mock.calls[0][0]), - JSON.parse(consoleSpy.mock.calls[1][0]), - ]; - expect(loggedData[0]._aws).toBe(undefined); + // Act & Assess + await expect(handler(dummyEvent, dummyContext)).resolves.not.toThrow(); }); }); @@ -201,21 +167,17 @@ describe('Middy middleware', () => { namespace: 'serverlessAirline', serviceName: 'orders', }); - - const lambdaHandler = (): void => { + const cosoleSpy = jest.spyOn(metrics['console'], 'log'); + const handler = middy(async (): Promise => { metrics.addMetric('successfulBooking', MetricUnits.Count, 2); metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - }; - - const handler = middy(lambdaHandler).use(logMetrics(metrics)); + }).use(logMetrics(metrics)); // Act - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked!') - ); + await handler(dummyEvent, dummyContext); // Assess - expect(console.log).toHaveBeenNthCalledWith( + expect(cosoleSpy).toHaveBeenNthCalledWith( 1, JSON.stringify({ _aws: { @@ -240,49 +202,22 @@ describe('Middy middleware', () => { namespace: 'serverlessAirline', serviceName: 'orders', }); - - const lambdaHandler = (): void => { - metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - }; + const consoleSpy = jest.spyOn(metrics['console'], 'log'); const metricsOptions: ExtraOptions = { throwOnEmptyMetrics: true, defaultDimensions: { environment: 'prod', aws_region: 'eu-west-1' }, captureColdStartMetric: true, }; - const handler = middy(lambdaHandler).use( - logMetrics(metrics, metricsOptions) - ); + const handler = middy(async (): Promise => { + metrics.addMetric('successfulBooking', MetricUnits.Count, 1); + }).use(logMetrics(metrics, metricsOptions)); // Act - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked!') - ); + await handler(dummyEvent, dummyContext); // Assess - expect(console.log).toHaveBeenNthCalledWith( + expect(consoleSpy).toHaveBeenNthCalledWith( 1, - JSON.stringify({ - _aws: { - Timestamp: 1466424490000, - CloudWatchMetrics: [ - { - Namespace: 'serverlessAirline', - Dimensions: [ - ['service', 'environment', 'aws_region', 'function_name'], - ], - Metrics: [{ Name: 'ColdStart', Unit: 'Count' }], - }, - ], - }, - service: 'orders', - environment: 'prod', - aws_region: 'eu-west-1', - function_name: 'foo-bar-function', - ColdStart: 1, - }) - ); - expect(console.log).toHaveBeenNthCalledWith( - 2, JSON.stringify({ _aws: { Timestamp: 1466424490000, @@ -308,20 +243,16 @@ describe('Middy middleware', () => { namespace: 'serverlessAirline', serviceName: 'orders', }); - - const lambdaHandler = (): void => { + const consoleSpy = jest.spyOn(metrics['console'], 'log'); + const handler = middy(async (): Promise => { metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - }; - - const handler = middy(lambdaHandler).use(logMetrics(metrics)); + }).use(logMetrics(metrics)); // Act - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked!') - ); + await handler(dummyEvent, dummyContext); // Assess - expect(console.log).toHaveBeenNthCalledWith( + expect(consoleSpy).toHaveBeenNthCalledWith( 1, JSON.stringify({ _aws: { @@ -346,24 +277,20 @@ describe('Middy middleware', () => { namespace: 'serverlessAirline', serviceName: 'orders', }); - - const lambdaHandler = (): void => { + const consoleSpy = jest.spyOn(metrics['console'], 'log'); + const handler = middy(async (): Promise => { metrics.addMetric('successfulBooking', MetricUnits.Count, 1); - }; - const metricsOptions: ExtraOptions = { - throwOnEmptyMetrics: true, - }; - const handler = middy(lambdaHandler).use( - logMetrics([metrics], metricsOptions) + }).use( + logMetrics(metrics, { + throwOnEmptyMetrics: true, + }) ); // Act - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked!') - ); + await handler(dummyEvent, dummyContext); // Assess - expect(console.log).toHaveBeenNthCalledWith( + expect(consoleSpy).toHaveBeenNthCalledWith( 1, JSON.stringify({ _aws: { @@ -426,100 +353,4 @@ describe('Middy middleware', () => { expect(publishStoredMetricsSpy).toBeCalledTimes(2); }); }); - describe('Metrics resolution', () => { - test('serialized metrics in EMF format should not contain `StorageResolution` as key if `60` is set', async () => { - // Prepare - const metrics = new Metrics({ - namespace: 'serverlessAirline', - serviceName: 'orders', - }); - - const lambdaHandler = (): void => { - metrics.addMetric( - 'successfulBooking', - MetricUnits.Count, - 1, - MetricResolution.Standard - ); - }; - - const handler = middy(lambdaHandler).use(logMetrics(metrics)); - - // Act - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked!') - ); - - // Assess - expect(console.log).toHaveBeenCalledWith( - JSON.stringify({ - _aws: { - Timestamp: 1466424490000, - CloudWatchMetrics: [ - { - Namespace: 'serverlessAirline', - Dimensions: [['service']], - Metrics: [ - { - Name: 'successfulBooking', - Unit: 'Count', - }, - ], - }, - ], - }, - service: 'orders', - successfulBooking: 1, - }) - ); - }); - - test('Should be StorageResolution `1` if MetricResolution is set to `High`', async () => { - // Prepare - const metrics = new Metrics({ - namespace: 'serverlessAirline', - serviceName: 'orders', - }); - - const lambdaHandler = (): void => { - metrics.addMetric( - 'successfulBooking', - MetricUnits.Count, - 1, - MetricResolution.High - ); - }; - - const handler = middy(lambdaHandler).use(logMetrics(metrics)); - - // Act - await handler(dummyEvent, dummyContext, () => - console.log('Lambda invoked!') - ); - - // Assess - expect(console.log).toHaveBeenCalledWith( - JSON.stringify({ - _aws: { - Timestamp: 1466424490000, - CloudWatchMetrics: [ - { - Namespace: 'serverlessAirline', - Dimensions: [['service']], - Metrics: [ - { - Name: 'successfulBooking', - Unit: 'Count', - StorageResolution: 1, - }, - ], - }, - ], - }, - service: 'orders', - successfulBooking: 1, - }) - ); - }); - }); }); From 0c55dab6eba9ffcd45fe87a16127de726967d944 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 9 Nov 2023 21:15:05 +0100 Subject: [PATCH 4/4] tests(layers): fix unit tests --- layers/tests/e2e/layerPublisher.test.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/layers/tests/e2e/layerPublisher.test.ts b/layers/tests/e2e/layerPublisher.test.ts index 09aebc671d..6772da71a6 100644 --- a/layers/tests/e2e/layerPublisher.test.ts +++ b/layers/tests/e2e/layerPublisher.test.ts @@ -145,10 +145,14 @@ describe(`Layers E2E tests, publisher stack`, () => { it( 'should have one info log related to coldstart metric', () => { - const logs = invocationLogs.getFunctionLogs('INFO'); + const logs = invocationLogs.getFunctionLogs(); + const emfLogEntry = logs.find((log) => + log.match( + /{"_aws":{"Timestamp":\d+,"CloudWatchMetrics":\[\{"Namespace":"\S+","Dimensions":\[\["service"\]\],"Metrics":\[\{"Name":"ColdStart","Unit":"Count"\}\]\}\]},"service":"\S+","ColdStart":1}/ + ) + ); - expect(logs.length).toBe(1); - expect(logs[0]).toContain('ColdStart'); + expect(emfLogEntry).toBeDefined(); }, TEST_CASE_TIMEOUT );