From 01aa035a2b367d5972c5b8569396c164ccec1021 Mon Sep 17 00:00:00 2001 From: Seb Aebischer Date: Wed, 11 Oct 2023 12:59:06 +0100 Subject: [PATCH 01/11] Replace Epsagon with Lumigo --- package.json | 2 +- src/core/LambdaWrapper.ts | 17 +- src/services/LoggerService.ts | 33 +- yarn.lock | 802 ++-------------------------------- 4 files changed, 63 insertions(+), 791 deletions(-) diff --git a/package.json b/package.json index c8fd6e3c..8ebc2c59 100644 --- a/package.json +++ b/package.json @@ -47,12 +47,12 @@ "aws-sdk": "^2.831.0" }, "dependencies": { + "@lumigo/tracer": "^1.87.0", "@sentry/node": "^6.0.1", "@types/aws-lambda": "^8.10.120", "alai": "1.0.3", "async": "^3.2.4", "axios": "^0.27.2", - "epsagon": "^1.123.3", "useragent": "2.3.0", "uuid": "^9.0.1", "validate.js": "0.13.1", diff --git a/src/core/LambdaWrapper.ts b/src/core/LambdaWrapper.ts index 397a058b..a4be6d36 100644 --- a/src/core/LambdaWrapper.ts +++ b/src/core/LambdaWrapper.ts @@ -1,6 +1,6 @@ -import Epsagon from 'epsagon'; +import * as lumigo from '@lumigo/tracer'; -import { Context } from '../index'; +import { Context, Handler } from '../index'; import ResponseModel from '../models/ResponseModel'; import LoggerService from '../services/LoggerService'; import RequestService from '../services/RequestService'; @@ -39,7 +39,7 @@ export default class LambdaWrapper { + let wrapper: Handler = async (event: any, context: Context) => { const di = new DependencyInjection(this.config, event, context); const request = di.get(RequestService); const logger = di.get(LoggerService); @@ -83,14 +83,11 @@ export default class LambdaWrapper Date: Fri, 13 Oct 2023 16:35:14 +0100 Subject: [PATCH 02/11] Use `lumigo.error` to flag errors --- src/services/LoggerService.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/services/LoggerService.ts b/src/services/LoggerService.ts index a9121105..e3455cfd 100644 --- a/src/services/LoggerService.ts +++ b/src/services/LoggerService.ts @@ -171,8 +171,7 @@ export default class LoggerService extends DependencyAwareClass { } if (process.env.LUMIGO_TOKEN && error instanceof Error) { - // todo: find out what the equivalent is in Lumigo - // Epsagon.setError(error); + lumigo.error(message || error.message, { err: error }); } this.logger.log('error', message, { error: LoggerService.processMessage(error) }); From cda96f2747c52687b260b97a8e7de85f21d05815 Mon Sep 17 00:00:00 2001 From: Seb Aebischer Date: Fri, 13 Oct 2023 16:39:14 +0100 Subject: [PATCH 03/11] Remove todo comments Lumigo confirmed that the global `addExecutionTag` works in both manually-traced and auto-traced functions. --- src/services/LoggerService.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/services/LoggerService.ts b/src/services/LoggerService.ts index e3455cfd..2ea6e68e 100644 --- a/src/services/LoggerService.ts +++ b/src/services/LoggerService.ts @@ -216,7 +216,6 @@ export default class LoggerService extends DependencyAwareClass { */ label(descriptor: string, silent = false) { if (process.env.LUMIGO_TOKEN) { - // todo: do we need to use our `tracer` instance here? lumigo.addExecutionTag(descriptor, true); } @@ -234,7 +233,6 @@ export default class LoggerService extends DependencyAwareClass { */ metric(descriptor: string, stat: number | string, silent = false) { if (process.env.LUMIGO_TOKEN) { - // todo: do we need to use our `tracer` instance here? lumigo.addExecutionTag(descriptor, stat); } From 4ad8ad0a8e178f3774b6b29b0ea07a5ec8a0ea11 Mon Sep 17 00:00:00 2001 From: Seb Aebischer Date: Fri, 13 Oct 2023 16:43:10 +0100 Subject: [PATCH 04/11] Change env var name to `LUMIGO_TRACER_TOKEN` This matches what Lumigo uses internally, and will allow `LoggerService` to work with auto-traced functions without having to manually add the token to the service. --- src/core/LambdaWrapper.ts | 4 ++-- src/services/LoggerService.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/LambdaWrapper.ts b/src/core/LambdaWrapper.ts index a4be6d36..5ef5877d 100644 --- a/src/core/LambdaWrapper.ts +++ b/src/core/LambdaWrapper.ts @@ -84,8 +84,8 @@ export default class LambdaWrapper Date: Mon, 16 Oct 2023 09:38:10 +0100 Subject: [PATCH 05/11] Restore `wrap` return type Coerce the Lumigo wrapper to our handler type instead of broadening the handler type. Fixes failing tests. --- src/core/LambdaWrapper.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/core/LambdaWrapper.ts b/src/core/LambdaWrapper.ts index 5ef5877d..9ab2aaec 100644 --- a/src/core/LambdaWrapper.ts +++ b/src/core/LambdaWrapper.ts @@ -1,6 +1,6 @@ import * as lumigo from '@lumigo/tracer'; -import { Context, Handler } from '../index'; +import { Context } from '../index'; import ResponseModel from '../models/ResponseModel'; import LoggerService from '../services/LoggerService'; import RequestService from '../services/RequestService'; @@ -39,7 +39,7 @@ export default class LambdaWrapper { + let wrapper = async (event: any, context: Context) => { const di = new DependencyInjection(this.config, event, context); const request = di.get(RequestService); const logger = di.get(LoggerService); @@ -87,7 +87,10 @@ export default class LambdaWrapper Promise; } return wrapper; From 8168790b9f1368513e98047826a6fa0551d7eef1 Mon Sep 17 00:00:00 2001 From: Seb Aebischer Date: Mon, 16 Oct 2023 10:09:47 +0100 Subject: [PATCH 06/11] Update refs to Epsagon in comments --- src/core/LambdaWrapper.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/LambdaWrapper.ts b/src/core/LambdaWrapper.ts index 9ab2aaec..0fa95405 100644 --- a/src/core/LambdaWrapper.ts +++ b/src/core/LambdaWrapper.ts @@ -112,11 +112,10 @@ export default class LambdaWrapper Date: Tue, 17 Oct 2023 16:29:54 +0100 Subject: [PATCH 07/11] Mention Lumigo in the docs --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index b7036fe6..35b9d704 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,14 @@ lambdaWrapper.configure({ }); ``` +## Monitoring + +At Comic Relief we use [Lumigo](https://lumigo.io/) for monitoring and observability of our deployed services. Lambda Wrapper includes the Lumigo tracer to allow us to tag traces with custom labels and metrics ([execution tags](https://docs.lumigo.io/docs/execution-tags)). + +Lumigo integration works out-of-the-box with Lumigo's [auto-trace feature](https://docs.lumigo.io/docs/serverless-applications#automatic-instrumentation). If you prefer manual tracing, enable it by setting `LUMIGO_TRACER_TOKEN` in your Lambda environment variables. + +And if you don't use Lumigo, don't worry, their tracer will not be instantiated in your functions and no calls will be made to their servers unless `LUMIGO_TRACER_TOKEN` is set. + ## Notes Lambda Wrapper's dependency injection relies on class names being preserved. If your build process includes minifying or uglifying your code, you'll need to disable these transformations. From 7b2949945cf1f900d58814d91b620575237127fa Mon Sep 17 00:00:00 2001 From: Seb Aebischer Date: Wed, 18 Oct 2023 09:43:50 +0100 Subject: [PATCH 08/11] Clarify in-code comment about enabling Lumigo --- src/core/LambdaWrapper.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/LambdaWrapper.ts b/src/core/LambdaWrapper.ts index 5c1c4629..7b64137b 100644 --- a/src/core/LambdaWrapper.ts +++ b/src/core/LambdaWrapper.ts @@ -87,6 +87,8 @@ export default class LambdaWrapper Date: Wed, 18 Oct 2023 16:14:46 +0100 Subject: [PATCH 09/11] Refactor token check into a shared function --- src/core/LambdaWrapper.ts | 14 +++++++++++--- src/services/LoggerService.ts | 7 ++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/core/LambdaWrapper.ts b/src/core/LambdaWrapper.ts index 7b64137b..c0e9d77b 100644 --- a/src/core/LambdaWrapper.ts +++ b/src/core/LambdaWrapper.ts @@ -87,9 +87,7 @@ export default class LambdaWrapper Date: Wed, 18 Oct 2023 16:16:33 +0100 Subject: [PATCH 10/11] Don't double-wrap in auto-traced functions --- src/core/LambdaWrapper.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/core/LambdaWrapper.ts b/src/core/LambdaWrapper.ts index c0e9d77b..15c2238d 100644 --- a/src/core/LambdaWrapper.ts +++ b/src/core/LambdaWrapper.ts @@ -87,7 +87,7 @@ export default class LambdaWrapper Date: Wed, 18 Oct 2023 16:28:19 +0100 Subject: [PATCH 11/11] Test Lumigo flags --- tests/unit/core/LambdaWrapper.spec.ts | 89 +++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/tests/unit/core/LambdaWrapper.spec.ts b/tests/unit/core/LambdaWrapper.spec.ts index fe4542ea..d3595f28 100644 --- a/tests/unit/core/LambdaWrapper.spec.ts +++ b/tests/unit/core/LambdaWrapper.spec.ts @@ -256,6 +256,95 @@ describe('unit.core.LambdaWrapper', () => { }); }); + describe('isLumigoEnabled', () => { + describe('when a Lumigo token is present', () => { + beforeAll(() => { + process.env.LUMIGO_TRACER_TOKEN = 'test'; + }); + + afterAll(() => { + delete process.env.LUMIGO_TRACER_TOKEN; + }); + + it('should return true', () => { + expect(LambdaWrapper.isLumigoEnabled).toBe(true); + }); + }); + + describe('when there is no Lumigo token', () => { + beforeAll(() => { + delete process.env.LUMIGO_TRACER_TOKEN; + }); + + it('should return false', () => { + expect(LambdaWrapper.isLumigoEnabled).toBe(false); + }); + }); + }); + + describe('isLumigoWrappingUs', () => { + describe('when using the runtime wrapper (e.g. auto-trace)', () => { + beforeAll(() => { + process.env.AWS_LAMBDA_EXEC_WRAPPER = '/opt/lumigo_wrapper'; + delete process.env.LUMIGO_ORIGINAL_HANDLER; + process.env.LUMIGO_TRACER_TOKEN = 'test'; + }); + + afterAll(() => { + delete process.env.AWS_LAMBDA_EXEC_WRAPPER; + delete process.env.LUMIGO_TRACER_TOKEN; + }); + + it('should return true', () => { + expect(LambdaWrapper.isLumigoWrappingUs).toBe(true); + }); + }); + + describe('when using handler redirection', () => { + beforeAll(() => { + delete process.env.AWS_LAMBDA_EXEC_WRAPPER; + process.env.LUMIGO_ORIGINAL_HANDLER = 'handler.js'; + process.env.LUMIGO_TRACER_TOKEN = 'test'; + }); + + afterAll(() => { + delete process.env.LUMIGO_ORIGINAL_HANDLER; + delete process.env.LUMIGO_TRACER_TOKEN; + }); + + it('should return true', () => { + expect(LambdaWrapper.isLumigoWrappingUs).toBe(true); + }); + }); + + describe('when there is only a Lumigo token', () => { + beforeAll(() => { + delete process.env.AWS_LAMBDA_EXEC_WRAPPER; + delete process.env.LUMIGO_ORIGINAL_HANDLER; + process.env.LUMIGO_TRACER_TOKEN = 'test'; + }); + + afterAll(() => { + delete process.env.LUMIGO_TRACER_TOKEN; + }); + + it('should return false', () => { + expect(LambdaWrapper.isLumigoWrappingUs).toBe(false); + }); + }); + + describe('when there is no Lumigo token', () => { + beforeAll(() => { + delete process.env.AWS_LAMBDA_EXEC_WRAPPER; + delete process.env.LUMIGO_TRACER_TOKEN; + }); + + it('should return false', () => { + expect(LambdaWrapper.isLumigoWrappingUs).toBe(false); + }); + }); + }); + describe('handleError', () => { ([ [undefined, 400, 0],