Skip to content

Commit be16b59

Browse files
authored
feat(tracer): add try/catch logic to decorator and middleware close (#1716)
1 parent 793f12f commit be16b59

File tree

5 files changed

+284
-131
lines changed

5 files changed

+284
-131
lines changed

Diff for: packages/tracer/src/Tracer.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -406,8 +406,14 @@ class Tracer extends Utility implements TracerInterface {
406406
tracerRef.addErrorAsMetadata(error as Error);
407407
throw error;
408408
} finally {
409-
subsegment?.close();
410-
subsegment?.flush();
409+
try {
410+
subsegment?.close();
411+
} catch (error) {
412+
console.warn(
413+
`Failed to close or serialize segment, ${subsegment?.name}. We are catching the error but data might be lost.`,
414+
error
415+
);
416+
}
411417
}
412418

413419
return result;
@@ -489,8 +495,14 @@ class Tracer extends Utility implements TracerInterface {
489495

490496
throw error;
491497
} finally {
492-
subsegment?.close();
493-
subsegment?.flush();
498+
try {
499+
subsegment?.close();
500+
} catch (error) {
501+
console.warn(
502+
`Failed to close or serialize segment, ${subsegment?.name}. We are catching the error but data might be lost.`,
503+
error
504+
);
505+
}
494506
}
495507

496508
return result;

Diff for: packages/tracer/src/middleware/middy.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,14 @@ const captureLambdaHandler = (
7070
if (handlerSegment === undefined || lambdaSegment === null) {
7171
return;
7272
}
73-
handlerSegment.close();
73+
try {
74+
handlerSegment.close();
75+
} catch (error) {
76+
console.warn(
77+
`Failed to close or serialize segment, ${handlerSegment.name}. We are catching the error but data might be lost.`,
78+
error
79+
);
80+
}
7481
target.setSegment(lambdaSegment);
7582
};
7683

Diff for: packages/tracer/src/provider/ProviderService.ts

+1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ class ProviderService implements ProviderServiceInterface {
103103

104104
return;
105105
}
106+
106107
segment.addMetadata(key, value, namespace);
107108
}
108109

Diff for: packages/tracer/tests/unit/Tracer.test.ts

+90
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,49 @@ describe('Class: Tracer', () => {
914914
otherDummyMethodSpy.mock.invocationCallOrder[0];
915915
expect(otherDummyCallOrder).toBeLessThan(dummyCallOrder);
916916
});
917+
918+
it('catches the error and logs a warning when a segment fails to close/serialize', async () => {
919+
// Prepare
920+
const tracer: Tracer = new Tracer();
921+
const handlerSubsegment: Segment | Subsegment | undefined =
922+
new Subsegment('### dummyMethod');
923+
jest
924+
.spyOn(tracer.provider, 'getSegment')
925+
.mockImplementation(() => handlerSubsegment);
926+
setContextMissingStrategy(() => null);
927+
jest
928+
.spyOn(tracer.provider, 'captureAsyncFunc')
929+
.mockImplementation(async (methodName, callBackFn) => {
930+
await callBackFn(handlerSubsegment);
931+
});
932+
const logWarningSpy = jest.spyOn(console, 'warn');
933+
const closeSpy = jest
934+
.spyOn(handlerSubsegment, 'close')
935+
.mockImplementation(() => {
936+
throw new Error('dummy error');
937+
});
938+
939+
class Lambda implements LambdaInterface {
940+
@tracer.captureLambdaHandler()
941+
public async handler(
942+
_event: unknown,
943+
_context: Context
944+
): Promise<string> {
945+
return 'foo bar';
946+
}
947+
}
948+
949+
// Act
950+
await new Lambda().handler(event, context);
951+
952+
// Assess
953+
expect(closeSpy).toHaveBeenCalledTimes(1);
954+
expect(logWarningSpy).toHaveBeenNthCalledWith(
955+
1,
956+
`Failed to close or serialize segment, ${handlerSubsegment.name}. We are catching the error but data might be lost.`,
957+
new Error('dummy error')
958+
);
959+
});
917960
});
918961

919962
describe('Method: captureMethod', () => {
@@ -1328,6 +1371,53 @@ describe('Class: Tracer', () => {
13281371
expect.anything()
13291372
);
13301373
});
1374+
1375+
it('catches the error and logs a warning when a segment fails to close/serialize', async () => {
1376+
// Prepare
1377+
const tracer: Tracer = new Tracer();
1378+
const handlerSubsegment: Segment | Subsegment | undefined =
1379+
new Subsegment('### dummyMethod');
1380+
jest
1381+
.spyOn(tracer.provider, 'getSegment')
1382+
.mockImplementation(() => handlerSubsegment);
1383+
setContextMissingStrategy(() => null);
1384+
jest
1385+
.spyOn(tracer.provider, 'captureAsyncFunc')
1386+
.mockImplementation(async (methodName, callBackFn) => {
1387+
await callBackFn(handlerSubsegment);
1388+
});
1389+
const logWarningSpy = jest.spyOn(console, 'warn');
1390+
const closeSpy = jest
1391+
.spyOn(handlerSubsegment, 'close')
1392+
.mockImplementation(() => {
1393+
throw new Error('dummy error');
1394+
});
1395+
1396+
class Lambda implements LambdaInterface {
1397+
@tracer.captureMethod()
1398+
public async dummyMethod(some: string): Promise<string> {
1399+
return some;
1400+
}
1401+
1402+
public async handler(
1403+
_event: unknown,
1404+
_context: Context
1405+
): Promise<string> {
1406+
return await this.dummyMethod('foo bar');
1407+
}
1408+
}
1409+
1410+
// Act
1411+
await new Lambda().handler(event, context);
1412+
1413+
// Assess
1414+
expect(closeSpy).toHaveBeenCalledTimes(1);
1415+
expect(logWarningSpy).toHaveBeenNthCalledWith(
1416+
1,
1417+
`Failed to close or serialize segment, ${handlerSubsegment.name}. We are catching the error but data might be lost.`,
1418+
new Error('dummy error')
1419+
);
1420+
});
13311421
});
13321422

13331423
describe('Method: captureAWS', () => {

0 commit comments

Comments
 (0)