Skip to content

Commit

Permalink
feat(tracer): add try/catch logic to decorator and middleware close (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
dreamorosi authored Sep 28, 2023
1 parent 793f12f commit be16b59
Show file tree
Hide file tree
Showing 5 changed files with 284 additions and 131 deletions.
20 changes: 16 additions & 4 deletions packages/tracer/src/Tracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,14 @@ class Tracer extends Utility implements TracerInterface {
tracerRef.addErrorAsMetadata(error as Error);
throw error;
} finally {
subsegment?.close();
subsegment?.flush();
try {
subsegment?.close();
} catch (error) {
console.warn(
`Failed to close or serialize segment, ${subsegment?.name}. We are catching the error but data might be lost.`,
error
);
}
}

return result;
Expand Down Expand Up @@ -489,8 +495,14 @@ class Tracer extends Utility implements TracerInterface {

throw error;
} finally {
subsegment?.close();
subsegment?.flush();
try {
subsegment?.close();
} catch (error) {
console.warn(
`Failed to close or serialize segment, ${subsegment?.name}. We are catching the error but data might be lost.`,
error
);
}
}

return result;
Expand Down
9 changes: 8 additions & 1 deletion packages/tracer/src/middleware/middy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ const captureLambdaHandler = (
if (handlerSegment === undefined || lambdaSegment === null) {
return;
}
handlerSegment.close();
try {
handlerSegment.close();
} catch (error) {
console.warn(
`Failed to close or serialize segment, ${handlerSegment.name}. We are catching the error but data might be lost.`,
error
);
}
target.setSegment(lambdaSegment);
};

Expand Down
1 change: 1 addition & 0 deletions packages/tracer/src/provider/ProviderService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class ProviderService implements ProviderServiceInterface {

return;
}

segment.addMetadata(key, value, namespace);
}

Expand Down
90 changes: 90 additions & 0 deletions packages/tracer/tests/unit/Tracer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,49 @@ describe('Class: Tracer', () => {
otherDummyMethodSpy.mock.invocationCallOrder[0];
expect(otherDummyCallOrder).toBeLessThan(dummyCallOrder);
});

it('catches the error and logs a warning when a segment fails to close/serialize', async () => {
// Prepare
const tracer: Tracer = new Tracer();
const handlerSubsegment: Segment | Subsegment | undefined =
new Subsegment('### dummyMethod');
jest
.spyOn(tracer.provider, 'getSegment')
.mockImplementation(() => handlerSubsegment);
setContextMissingStrategy(() => null);
jest
.spyOn(tracer.provider, 'captureAsyncFunc')
.mockImplementation(async (methodName, callBackFn) => {
await callBackFn(handlerSubsegment);
});
const logWarningSpy = jest.spyOn(console, 'warn');
const closeSpy = jest
.spyOn(handlerSubsegment, 'close')
.mockImplementation(() => {
throw new Error('dummy error');
});

class Lambda implements LambdaInterface {
@tracer.captureLambdaHandler()
public async handler(
_event: unknown,
_context: Context
): Promise<string> {
return 'foo bar';
}
}

// Act
await new Lambda().handler(event, context);

// Assess
expect(closeSpy).toHaveBeenCalledTimes(1);
expect(logWarningSpy).toHaveBeenNthCalledWith(
1,
`Failed to close or serialize segment, ${handlerSubsegment.name}. We are catching the error but data might be lost.`,
new Error('dummy error')
);
});
});

describe('Method: captureMethod', () => {
Expand Down Expand Up @@ -1328,6 +1371,53 @@ describe('Class: Tracer', () => {
expect.anything()
);
});

it('catches the error and logs a warning when a segment fails to close/serialize', async () => {
// Prepare
const tracer: Tracer = new Tracer();
const handlerSubsegment: Segment | Subsegment | undefined =
new Subsegment('### dummyMethod');
jest
.spyOn(tracer.provider, 'getSegment')
.mockImplementation(() => handlerSubsegment);
setContextMissingStrategy(() => null);
jest
.spyOn(tracer.provider, 'captureAsyncFunc')
.mockImplementation(async (methodName, callBackFn) => {
await callBackFn(handlerSubsegment);
});
const logWarningSpy = jest.spyOn(console, 'warn');
const closeSpy = jest
.spyOn(handlerSubsegment, 'close')
.mockImplementation(() => {
throw new Error('dummy error');
});

class Lambda implements LambdaInterface {
@tracer.captureMethod()
public async dummyMethod(some: string): Promise<string> {
return some;
}

public async handler(
_event: unknown,
_context: Context
): Promise<string> {
return await this.dummyMethod('foo bar');
}
}

// Act
await new Lambda().handler(event, context);

// Assess
expect(closeSpy).toHaveBeenCalledTimes(1);
expect(logWarningSpy).toHaveBeenNthCalledWith(
1,
`Failed to close or serialize segment, ${handlerSubsegment.name}. We are catching the error but data might be lost.`,
new Error('dummy error')
);
});
});

describe('Method: captureAWS', () => {
Expand Down
Loading

0 comments on commit be16b59

Please sign in to comment.