diff --git a/docs/core/tracer.md b/docs/core/tracer.md index 21c3bf2cf4..7fc1ab031e 100644 --- a/docs/core/tracer.md +++ b/docs/core/tracer.md @@ -42,17 +42,16 @@ You can quickly start by importing the `Tracer` class, initialize it outside the === "Middleware" - ```typescript hl_lines="1 3 6" + ```typescript hl_lines="1-2 4 7 9" import { Tracer } from '@aws-lambda-powertools/tracer'; + import middy from '@middy/core'; const tracer = Tracer(); // Sets service via env var // OR tracer = Tracer({ service: 'example' }); - // TODO: update example once middleware has been implemented. - - export const handler = async (_event: any, _context: any) => { + export const handler = middy(async (_event: any, _context: any) => { ... - } + }).use(captureLambdaHandler(tracer)); ``` === "Decorator" @@ -76,7 +75,7 @@ You can quickly start by importing the `Tracer` class, initialize it outside the === "Manual" - ```typescript hl_lines="1-2 4 8-9 11 17 20 24" + ```typescript hl_lines="1-2 4 9-10 12 18 21 25" import { Tracer } from '@aws-lambda-powertools/tracer'; import { Segment } from 'aws-xray-sdk-core'; @@ -107,8 +106,7 @@ You can quickly start by importing the `Tracer` class, initialize it outside the } ``` - -When using thes `captureLambdaHanlder` decorator or the `TBD` middleware, Tracer performs these additional tasks to ease operations: +When using the `captureLambdaHandler` decorator or middleware, Tracer performs these additional tasks to ease operations: * Handles the lifecycle of the subsegment * Creates a `ColdStart` annotation to easily filter traces that have had an initialization overhead @@ -148,23 +146,10 @@ When using thes `captureLambdaHanlder` decorator or the `TBD` middleware, Tracer ### Methods -You can trace other methods using the `captureMethod` decorator. - -=== "Middleware" - - ```typescript hl_lines="1 3 6" - import { Tracer } from '@aws-lambda-powertools/tracer'; - - const tracer = Tracer(); +You can trace other methods using the `captureMethod` decorator or manual instrumentation. - // TODO: update example once middleware has been implemented. - - - - export const handler = async (_event: any, _context: any) => { - ... - } - ``` +!!! info + We currently support a middleware for tracing methods, [let us know](https://github.com/awslabs/aws-lambda-powertools-typescript/issues/new?assignees=&labels=feature-request%2C+triage&template=feature_request.md&title=) if you'd like to see one! === "Decorator" diff --git a/packages/tracing/npm-shrinkwrap.json b/packages/tracing/npm-shrinkwrap.json index 6d72eb5437..cf38edaeb6 100644 --- a/packages/tracing/npm-shrinkwrap.json +++ b/packages/tracing/npm-shrinkwrap.json @@ -9,6 +9,7 @@ "version": "0.0.0", "license": "MIT", "dependencies": { + "@middy/core": "^2.5.3", "@aws-lambda-powertools/commons": "^0.0.2", "aws-xray-sdk-core": "^3.3.3" }, @@ -980,6 +981,14 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/@middy/core": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@middy/core/-/core-2.5.3.tgz", + "integrity": "sha512-hCXlRglDu48sl03IjDGjcJwfwElIPAf0fwBu08kqE80qpnouZ1hGH1lZbkbJjAhz6DkSR+79YArUQKUYaM2k1g==", + "engines": { + "node": ">=12" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2321,7 +2330,8 @@ "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2", - "optionator": "^0.8.1" + "optionator": "^0.8.1", + "source-map": "~0.6.1" }, "bin": { "escodegen": "bin/escodegen.js", @@ -3956,6 +3966,7 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", "graceful-fs": "^4.2.4", "jest-regex-util": "^27.4.0", "jest-serializer": "^27.4.0", @@ -6712,6 +6723,11 @@ "chalk": "^4.0.0" } }, + "@middy/core": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@middy/core/-/core-2.5.3.tgz", + "integrity": "sha512-hCXlRglDu48sl03IjDGjcJwfwElIPAf0fwBu08kqE80qpnouZ1hGH1lZbkbJjAhz6DkSR+79YArUQKUYaM2k1g==" + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", diff --git a/packages/tracing/package.json b/packages/tracing/package.json index 321d93a922..7ffb7ace01 100644 --- a/packages/tracing/package.json +++ b/packages/tracing/package.json @@ -54,6 +54,7 @@ "url": "https://github.com/awslabs/aws-lambda-powertools-typescript/issues" }, "dependencies": { + "@middy/core": "^2.5.3", "@aws-lambda-powertools/commons": "^0.0.2", "aws-xray-sdk-core": "^3.3.3" } diff --git a/packages/tracing/src/Tracer.ts b/packages/tracing/src/Tracer.ts index 391aa21008..6a36efbe18 100644 --- a/packages/tracing/src/Tracer.ts +++ b/packages/tracing/src/Tracer.ts @@ -20,11 +20,28 @@ import { Segment, Subsegment } from 'aws-xray-sdk-core'; * ## Usage * * ### Functions usage with middlewares - * TBD + * + * If you use function-based Lambda handlers you can use the [captureLambdaHanlder()](./_aws_lambda_powertools_tracer.Tracer.html) middy middleware to automatically: + * * handle the subsegment lifecycle + * * add the `ColdStart` annotation + * * add the function response as metadata + * * add the function error as metadata (if any) + * + * @example + * ```typescript + * import { Tracer, captureLambdaHandler } from '@aws-lambda-powertools/tracer'; + * import middy from '@middy/core'; + * + * const tracer = new Tracer({ serviceName: 'my-service' }); + * + * export const handler = middy(async (_event: any, _context: any) => { + * ... + * }).use(captureLambdaHandler(tracer)); + * ``` * * ### Object oriented usage with decorators * - * If you use TypeScript Classes to wrap your Lambda handler you can use the [@tracer.captureLambdaHanlder()](./_aws_lambda_powertools_tracer.Tracer.html#captureLambdaHanlder) decorator to automatically: + * If instead you use TypeScript Classes to wrap your Lambda handler you can use the [@tracer.captureLambdaHanlder()](./_aws_lambda_powertools_tracer.Tracer.html#captureLambdaHanlder) decorator to automatically: * * handle the subsegment lifecycle * * add the `ColdStart` annotation * * add the function response as metadata @@ -65,7 +82,7 @@ import { Segment, Subsegment } from 'aws-xray-sdk-core'; * const subsegment = new Subsegment(`## ${context.functionName}`); * tracer.setSegment(subsegment); * // Add the ColdStart annotation - * this.putAnnotation('ColdStart', tracer.coldStart); + * this.putAnnotation('ColdStart', tracer.isColdStart()); * * let res; * try { @@ -242,8 +259,7 @@ class Tracer implements TracerInterface { this.addResponseAsMetadata(result, context.functionName); } catch (error) { this.addErrorAsMetadata(error as Error); - // TODO: should this error be thrown?? If thrown we get a ERR_UNHANDLED_REJECTION. If not aren't we are basically catching a Customer error? - // throw error; + throw error; } finally { subsegment?.close(); } @@ -351,6 +367,30 @@ class Tracer implements TracerInterface { return segment; } + + /** + * Get the current value of the `captureError` property. + * + * You can use this method during manual instrumentation to determine + * if tracer should be capturing errors. + * + * @returns captureError - `true` if errors should be captured, `false` otherwise. + */ + public isCaptureErrorEnabled(): boolean { + return this.captureError; + } + + /** + * Get the current value of the `captureResponse` property. + * + * You can use this method during manual instrumentation to determine + * if tracer should be capturing function responses. + * + * @returns captureResponse - `true` if responses should be captured, `false` otherwise. + */ + public isCaptureResponseEnabled(): boolean { + return this.captureResponse; + } /** * Retrieve the current value of `ColdStart`. @@ -361,7 +401,7 @@ class Tracer implements TracerInterface { * * @see https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html * - * @returns boolean - true if is cold start otherwise false + * @returns boolean - `true` if is cold start, otherwise `false` */ public static isColdStart(): boolean { if (Tracer.coldStart === true) { @@ -373,6 +413,18 @@ class Tracer implements TracerInterface { return false; } + /** + * Get the current value of the `tracingEnabled` property. + * + * You can use this method during manual instrumentation to determine + * if tracer is currently enabled. + * + * @returns tracingEnabled - `true` if tracing is enabled, `false` otherwise. + */ + public isTracingEnabled(): boolean { + return this.tracingEnabled; + } + /** * Adds annotation to existing segment or subsegment. * diff --git a/packages/tracing/src/index.ts b/packages/tracing/src/index.ts index 0412c64c09..4e2259de59 100644 --- a/packages/tracing/src/index.ts +++ b/packages/tracing/src/index.ts @@ -1,3 +1,4 @@ export * from './helpers'; export * from './Tracer'; -export * from './TracerInterface'; \ No newline at end of file +export * from './TracerInterface'; +export * from './middleware/middy'; \ No newline at end of file diff --git a/packages/tracing/src/middleware/middy.ts b/packages/tracing/src/middleware/middy.ts new file mode 100644 index 0000000000..79a37b18d0 --- /dev/null +++ b/packages/tracing/src/middleware/middy.ts @@ -0,0 +1,76 @@ +import middy from '@middy/core'; +import { Subsegment } from 'aws-xray-sdk-core'; +import { Tracer } from '../Tracer'; + +/** + * A middy middleware automating capture of metadata and annotations on segments or subsegments ofr a Lambda Handler. + * + * Using this middleware on your handler function will automatically: + * * handle the subsegment lifecycle + * * add the `ColdStart` annotation + * * add the function response as metadata + * * add the function error as metadata (if any) + * + * @example + * ```typescript + * import { Tracer, captureLambdaHandler } from '@aws-lambda-powertools/tracer'; + * import middy from '@middy/core'; + * + * const tracer = new Tracer({ serviceName: 'my-service' }); + * + * export const handler = middy(async (_event: any, _context: any) => { + * ... + * }).use(captureLambdaHandler(tracer)); + * ``` + * + * @param tracer - The Tracer instance to use for tracing + * @returns middleware object - The middy middleware object + */ +const captureLambdaHandler = (target: Tracer): middy.MiddlewareObj => { + const captureLambdaHandlerBefore = async (request: middy.Request): Promise => { + if (target.isTracingEnabled()) { + const subsegment = new Subsegment(`## ${request.context.functionName}`); + target.setSegment(subsegment); + + if (Tracer.isColdStart()) { + target.putAnnotation('ColdStart', true); + } + } + }; + + const captureLambdaHandlerAfter = async (request: middy.Request): Promise => { + if (target.isTracingEnabled()) { + const subsegment = target.getSegment(); + if (request.response !== undefined && target.isCaptureResponseEnabled() === true) { + target.putMetadata(`${request.context.functionName} response`, request.response); + } + + subsegment?.close(); + } + }; + + const captureLambdaHandlerError = async (request: middy.Request): Promise => { + if (target.isTracingEnabled()) { + const subsegment = target.getSegment(); + if (target.isCaptureErrorEnabled() === false) { + subsegment?.addErrorFlag(); + } else { + subsegment?.addError(request.error as Error, false); + } + // TODO: should this error be thrown?? I.e. should we stop the event flow & return? + // throw request.error; + + subsegment?.close(); + } + }; + + return { + before: captureLambdaHandlerBefore, + after: captureLambdaHandlerAfter, + onError: captureLambdaHandlerError + }; +}; + +export { + captureLambdaHandler, +}; \ No newline at end of file diff --git a/packages/tracing/tests/unit/Tracer.test.ts b/packages/tracing/tests/unit/Tracer.test.ts index 8bcd1142b8..157cda7412 100644 --- a/packages/tracing/tests/unit/Tracer.test.ts +++ b/packages/tracing/tests/unit/Tracer.test.ts @@ -451,10 +451,8 @@ describe('Class: Tracer', () => { } - // Act - await new Lambda().handler(dummyEvent, dummyContext, () => console.log('Lambda invoked!')); - - // Assess + // Act & Assess + await expect(new Lambda().handler({}, dummyContext, () => console.log('Lambda invoked!'))).rejects.toThrowError(Error); expect(captureAsyncFuncSpy).toHaveBeenCalledTimes(1); expect(newSubsegment).toEqual(expect.objectContaining({ name: '## foo-bar-function', @@ -462,8 +460,10 @@ describe('Class: Tracer', () => { expect('cause' in newSubsegment).toBe(false); expect(addErrorFlagSpy).toHaveBeenCalledTimes(1); expect(addErrorSpy).toHaveBeenCalledTimes(0); + expect.assertions(6); delete process.env.POWERTOOLS_TRACER_CAPTURE_ERROR; + }); test('when used as decorator and with standard config, it captures the exception correctly', async () => { @@ -487,10 +487,8 @@ describe('Class: Tracer', () => { } - // Act - await new Lambda().handler(dummyEvent, dummyContext, () => console.log('Lambda invoked!')); - - // Assess + // Act & Assess + await expect(new Lambda().handler({}, dummyContext, () => console.log('Lambda invoked!'))).rejects.toThrowError(Error); expect(captureAsyncFuncSpy).toHaveBeenCalledTimes(1); expect(newSubsegment).toEqual(expect.objectContaining({ name: '## foo-bar-function', @@ -498,6 +496,7 @@ describe('Class: Tracer', () => { expect('cause' in newSubsegment).toBe(true); expect(addErrorSpy).toHaveBeenCalledTimes(1); expect(addErrorSpy).toHaveBeenCalledWith(new Error('Exception thrown!'), false); + expect.assertions(6); }); diff --git a/packages/tracing/tests/unit/middy.test.ts b/packages/tracing/tests/unit/middy.test.ts new file mode 100644 index 0000000000..adef075f66 --- /dev/null +++ b/packages/tracing/tests/unit/middy.test.ts @@ -0,0 +1,249 @@ +import { captureLambdaHandler } from '../../src/middleware/middy'; +import middy from '@middy/core'; +import { Tracer } from './../../src'; +import type { Context, Handler } from 'aws-lambda/handler'; +import { Segment, setContextMissingStrategy, Subsegment } from 'aws-xray-sdk-core'; + +jest.spyOn(console, 'debug').mockImplementation(() => null); +jest.spyOn(console, 'warn').mockImplementation(() => null); +jest.spyOn(console, 'error').mockImplementation(() => null); + +describe('Middy middlewares', () => { + const ENVIRONMENT_VARIABLES = process.env; + + const mockContext: Context = { + 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-central-1:123456789012:function:Example', + awsRequestId: Math.floor(Math.random() * 1000000000).toString(), + getRemainingTimeInMillis: () => 1234, + done: () => console.log('Done!'), + fail: () => console.log('Failed!'), + succeed: () => console.log('Succeeded!'), + }; + + beforeEach(() => { + Tracer.coldStart = true; + jest.clearAllMocks(); + jest.resetModules(); + process.env = { ...ENVIRONMENT_VARIABLES }; + }); + + afterAll(() => { + process.env = ENVIRONMENT_VARIABLES; + }); + describe('Middleware: captureLambdaHandler', () => { + + test('when used while tracing is disabled, it does nothing', async () => { + + // Prepare + const tracer: Tracer = new Tracer({ enabled: false }); + const setSegmentSpy = jest.spyOn(tracer.provider, 'setSegment').mockImplementation(); + const getSegmentSpy = jest.spyOn(tracer.provider, 'getSegment') + .mockImplementationOnce(() => new Segment('facade', process.env._X_AMZN_TRACE_ID || null)) + .mockImplementationOnce(() => new Subsegment('## foo-bar-function')); + const lambdaHandler: Handler = async (_event: unknown, _context: Context) => ({ + foo: 'bar' + }); + const handler = middy(lambdaHandler).use(captureLambdaHandler(tracer)); + const context = Object.assign({}, mockContext); + + // Act + await handler({}, context, () => console.log('Lambda invoked!')); + + // Assess + expect(setSegmentSpy).toHaveBeenCalledTimes(0); + expect(getSegmentSpy).toHaveBeenCalledTimes(0); + + }); + + test('when used while tracing is disabled, even if the handler throws an error, it does nothing', async () => { + + // Prepare + const tracer: Tracer = new Tracer({ enabled: false }); + const setSegmentSpy = jest.spyOn(tracer.provider, 'setSegment').mockImplementation(); + const getSegmentSpy = jest.spyOn(tracer.provider, 'getSegment') + .mockImplementationOnce(() => new Segment('facade', process.env._X_AMZN_TRACE_ID || null)) + .mockImplementationOnce(() => new Subsegment('## foo-bar-function')); + const lambdaHandler: Handler = async (_event: unknown, _context: Context) => { + throw new Error('Exception thrown!'); + }; + const handler = middy(lambdaHandler).use(captureLambdaHandler(tracer)); + const context = Object.assign({}, mockContext); + + // Act & Assess + await expect(handler({}, context, () => console.log('Lambda invoked!'))).rejects.toThrowError(Error); + expect(setSegmentSpy).toHaveBeenCalledTimes(0); + expect(getSegmentSpy).toHaveBeenCalledTimes(0); + expect.assertions(3); + + }); + + test('when used while POWERTOOLS_TRACER_CAPTURE_RESPONSE is set to false, it does not capture the response as metadata', async () => { + + // Prepare + process.env.POWERTOOLS_TRACER_CAPTURE_RESPONSE = 'false'; + const tracer: Tracer = new Tracer(); + const newSubsegment: Segment | Subsegment | undefined = new Subsegment('## foo-bar-function'); + const setSegmentSpy = jest.spyOn(tracer.provider, 'setSegment').mockImplementation(); + jest.spyOn(tracer.provider, 'getSegment').mockImplementation(() => newSubsegment); + setContextMissingStrategy(() => null); + const lambdaHandler: Handler = async (_event: unknown, _context: Context) => ({ + foo: 'bar' + }); + const handler = middy(lambdaHandler).use(captureLambdaHandler(tracer)); + const context = Object.assign({}, mockContext); + + // Act + await handler({}, context, () => console.log('Lambda invoked!')); + + // Assess + expect(setSegmentSpy).toHaveBeenCalledTimes(1); + expect('metadata' in newSubsegment).toBe(false); + delete process.env.POWERTOOLS_TRACER_CAPTURE_RESPONSE; + + }); + + test('when used with standard config, it captures the response as metadata', async () => { + + // Prepare + const tracer: Tracer = new Tracer(); + const newSubsegment: Segment | Subsegment | undefined = new Subsegment('## foo-bar-function'); + const setSegmentSpy = jest.spyOn(tracer.provider, 'setSegment').mockImplementation(); + jest.spyOn(tracer.provider, 'getSegment').mockImplementation(() => newSubsegment); + setContextMissingStrategy(() => null); + const lambdaHandler: Handler = async (_event: unknown, _context: Context) => ({ + foo: 'bar' + }); + const handler = middy(lambdaHandler).use(captureLambdaHandler(tracer)); + const context = Object.assign({}, mockContext); + + // Act + await handler({}, context, () => console.log('Lambda invoked!')); + + // Assess + expect(setSegmentSpy).toHaveBeenCalledTimes(1); + expect(setSegmentSpy).toHaveBeenCalledWith(expect.objectContaining({ + name: '## foo-bar-function', + })); + expect(newSubsegment).toEqual(expect.objectContaining({ + name: '## foo-bar-function', + metadata: { + 'hello-world': { + 'foo-bar-function response': { + foo: 'bar', + }, + }, + } + })); + + }); + + test('when used while POWERTOOLS_TRACER_CAPTURE_ERROR is set to false, it does not capture the exceptions', async () => { + + // Prepare + process.env.POWERTOOLS_TRACER_CAPTURE_ERROR = 'false'; + const tracer: Tracer = new Tracer(); + const newSubsegment: Segment | Subsegment | undefined = new Subsegment('## foo-bar-function'); + const setSegmentSpy = jest.spyOn(tracer.provider, 'setSegment').mockImplementation(); + jest.spyOn(tracer.provider, 'getSegment').mockImplementation(() => newSubsegment); + setContextMissingStrategy(() => null); + const addErrorSpy = jest.spyOn(newSubsegment, 'addError'); + const addErrorFlagSpy = jest.spyOn(newSubsegment, 'addErrorFlag'); + const lambdaHandler: Handler = async (_event: unknown, _context: Context) => { + throw new Error('Exception thrown!'); + }; + const handler = middy(lambdaHandler).use(captureLambdaHandler(tracer)); + const context = Object.assign({}, mockContext); + + // Act & Assess + await expect(handler({}, context, () => console.log('Lambda invoked!'))).rejects.toThrowError(Error); + expect(setSegmentSpy).toHaveBeenCalledTimes(1); + expect(setSegmentSpy).toHaveBeenCalledWith(expect.objectContaining({ + name: '## foo-bar-function', + })); + expect('cause' in newSubsegment).toBe(false); + expect(addErrorFlagSpy).toHaveBeenCalledTimes(1); + expect(addErrorSpy).toHaveBeenCalledTimes(0); + expect.assertions(6); + + delete process.env.POWERTOOLS_TRACER_CAPTURE_ERROR; + + }); + + }); + + test('when used with standard config, it captures the exception correctly', async () => { + + // Prepare + const tracer: Tracer = new Tracer(); + const newSubsegment: Segment | Subsegment | undefined = new Subsegment('## foo-bar-function'); + const setSegmentSpy = jest.spyOn(tracer.provider, 'setSegment').mockImplementation(); + jest.spyOn(tracer.provider, 'getSegment').mockImplementation(() => newSubsegment); + setContextMissingStrategy(() => null); + const addErrorSpy = jest.spyOn(newSubsegment, 'addError'); + const lambdaHandler: Handler = async (_event: unknown, _context: Context) => { + throw new Error('Exception thrown!'); + }; + const handler = middy(lambdaHandler).use(captureLambdaHandler(tracer)); + const context = Object.assign({}, mockContext); + + // Act & Assess + await expect(handler({}, context, () => console.log('Lambda invoked!'))).rejects.toThrowError(Error); + expect(setSegmentSpy).toHaveBeenCalledTimes(1); + expect(setSegmentSpy).toHaveBeenCalledWith(expect.objectContaining({ + name: '## foo-bar-function', + })); + expect('cause' in newSubsegment).toBe(true); + expect(addErrorSpy).toHaveBeenCalledTimes(1); + expect(addErrorSpy).toHaveBeenCalledWith(new Error('Exception thrown!'), false); + expect.assertions(6); + + }); + + test('when used with standard config, it annotates ColdStart correctly', async () => { + + // Prepare + const tracer: Tracer = new Tracer(); + const newSubsegmentFirstInvocation: Segment | Subsegment | undefined = new Subsegment('## foo-bar-function'); + const newSubsegmentSecondInvocation: Segment | Subsegment | undefined = new Subsegment('## foo-bar-function'); + const setSegmentSpy = jest.spyOn(tracer.provider, 'setSegment').mockImplementation(); + jest.spyOn(tracer.provider, 'getSegment') + .mockImplementationOnce(() => newSubsegmentFirstInvocation) + .mockImplementation(() => newSubsegmentSecondInvocation); + setContextMissingStrategy(() => null); + const addAnnotationSpy = jest.spyOn(tracer, 'putAnnotation'); + const lambdaHandler: Handler = async (_event: unknown, _context: Context) => ({ + foo: 'bar' + }); + const handler = middy(lambdaHandler).use(captureLambdaHandler(tracer)); + const context = Object.assign({}, mockContext); + + // Act + await handler({}, context, () => console.log('Lambda invoked!')); + await handler({}, context, () => console.log('Lambda invoked!')); + + // Assess + expect(setSegmentSpy).toHaveBeenCalledTimes(2); + expect(setSegmentSpy).toHaveBeenCalledWith(expect.objectContaining({ + name: '## foo-bar-function', + })); + expect(addAnnotationSpy).toHaveBeenCalledTimes(1); + expect(addAnnotationSpy).toHaveBeenCalledWith('ColdStart', true); + expect(newSubsegmentFirstInvocation).toEqual(expect.objectContaining({ + name: '## foo-bar-function', + annotations: { + 'ColdStart': true, + } + })); + expect(newSubsegmentSecondInvocation).toEqual(expect.objectContaining({ + name: '## foo-bar-function' + })); + + }); + +}); \ No newline at end of file diff --git a/packages/tracing/tsconfig.json b/packages/tracing/tsconfig.json index cbd9922f32..8b93f8c299 100644 --- a/packages/tracing/tsconfig.json +++ b/packages/tracing/tsconfig.json @@ -14,7 +14,8 @@ "resolveJsonModule": true, "pretty": true, "baseUrl": "src/", - "rootDirs": [ "src/" ] + "rootDirs": [ "src/" ], + "esModuleInterop": true }, "include": [ "src/**/*" ], "exclude": [ "./node_modules"],