Skip to content

Commit 75dfa6d

Browse files
committed
Pass AWSLambda scope settings for transactions
1 parent 57eaded commit 75dfa6d

File tree

3 files changed

+62
-50
lines changed

3 files changed

+62
-50
lines changed

packages/serverless/src/awslambda.ts

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -125,20 +125,6 @@ function enhanceScopeWithEnvironmentData(scope: Scope, context: Context): void {
125125
});
126126
}
127127

128-
/**
129-
* Capture exception with a a context.
130-
*
131-
* @param e exception to be captured
132-
* @param context Context
133-
*/
134-
function captureExceptionWithContext(e: unknown, context: Context): void {
135-
withScope(scope => {
136-
addServerlessEventProcessor(scope);
137-
enhanceScopeWithEnvironmentData(scope, context);
138-
captureException(e);
139-
});
140-
}
141-
142128
/**
143129
* Wraps a lambda handler adding it error capture and tracing capabilities.
144130
*
@@ -205,8 +191,6 @@ export function wrapHandler<TEvent, TResult>(
205191

206192
timeoutWarningTimer = setTimeout(() => {
207193
withScope(scope => {
208-
addServerlessEventProcessor(scope);
209-
enhanceScopeWithEnvironmentData(scope, context);
210194
scope.setTag('timeout', humanReadableTimeout);
211195
captureMessage(`Possible function timeout: ${context.functionName}`, Severity.Warning);
212196
});
@@ -217,22 +201,25 @@ export function wrapHandler<TEvent, TResult>(
217201
name: context.functionName,
218202
op: 'awslambda.handler',
219203
});
220-
// We put the transaction on the scope so users can attach children to it
221-
getCurrentHub().configureScope(scope => {
222-
scope.setSpan(transaction);
223-
});
224204

205+
const hub = getCurrentHub();
206+
const scope = hub.pushScope();
225207
let rv: TResult | undefined;
226208
try {
209+
addServerlessEventProcessor(scope);
210+
enhanceScopeWithEnvironmentData(scope, context);
211+
// We put the transaction on the scope so users can attach children to it
212+
scope.setSpan(transaction);
227213
rv = await asyncHandler(event, context);
228214
} catch (e) {
229-
captureExceptionWithContext(e, context);
215+
captureException(e);
230216
if (options.rethrowAfterCapture) {
231217
throw e;
232218
}
233219
} finally {
234220
clearTimeout(timeoutWarningTimer);
235221
transaction.finish();
222+
hub.popScope();
236223
await flush(options.flushTimeout);
237224
}
238225
return rv;

packages/serverless/test/__mocks__/@sentry/node.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@ export const SDK_VERSION = '6.6.6';
55
export const Severity = {
66
Warning: 'warning',
77
};
8-
export const fakeParentScope = {
9-
setSpan: jest.fn(),
10-
getTransaction: jest.fn(() => fakeTransaction),
11-
};
128
export const fakeHub = {
13-
configureScope: jest.fn((fn: (arg: any) => any) => fn(fakeParentScope)),
14-
getScope: jest.fn(() => fakeParentScope),
9+
configureScope: jest.fn((fn: (arg: any) => any) => fn(fakeScope)),
10+
pushScope: jest.fn(() => fakeScope),
11+
popScope: jest.fn(),
12+
getScope: jest.fn(() => fakeScope),
1513
};
1614
export const fakeScope = {
1715
addEventProcessor: jest.fn(),
1816
setTransactionName: jest.fn(),
1917
setTag: jest.fn(),
2018
setContext: jest.fn(),
19+
setSpan: jest.fn(),
20+
getTransaction: jest.fn(() => fakeTransaction),
2121
};
2222
export const fakeSpan = {
2323
finish: jest.fn(),
@@ -39,15 +39,17 @@ export const resetMocks = (): void => {
3939
fakeTransaction.finish.mockClear();
4040
fakeTransaction.startChild.mockClear();
4141
fakeSpan.finish.mockClear();
42-
fakeParentScope.setSpan.mockClear();
43-
fakeParentScope.getTransaction.mockClear();
4442
fakeHub.configureScope.mockClear();
43+
fakeHub.pushScope.mockClear();
44+
fakeHub.popScope.mockClear();
4545
fakeHub.getScope.mockClear();
4646

4747
fakeScope.addEventProcessor.mockClear();
4848
fakeScope.setTransactionName.mockClear();
4949
fakeScope.setTag.mockClear();
5050
fakeScope.setContext.mockClear();
51+
fakeScope.setSpan.mockClear();
52+
fakeScope.getTransaction.mockClear();
5153

5254
getCurrentHub.mockClear();
5355
startTransaction.mockClear();

packages/serverless/test/awslambda.test.ts

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,36 @@ const fakeCallback: Callback = (err, result) => {
4141
return err;
4242
};
4343

44+
function expectScopeSettings() {
45+
// @ts-ignore see "Why @ts-ignore" note
46+
expect(Sentry.fakeScope.setSpan).toBeCalledWith(Sentry.fakeTransaction);
47+
// @ts-ignore see "Why @ts-ignore" note
48+
expect(Sentry.fakeScope.setTag).toBeCalledWith('server_name', expect.anything());
49+
// @ts-ignore see "Why @ts-ignore" note
50+
expect(Sentry.fakeScope.setTag).toBeCalledWith('url', 'awslambda:///functionName');
51+
// @ts-ignore see "Why @ts-ignore" note
52+
expect(Sentry.fakeScope.setContext).toBeCalledWith('runtime', { name: 'node', version: expect.anything() });
53+
// @ts-ignore see "Why @ts-ignore" note
54+
expect(Sentry.fakeScope.setContext).toBeCalledWith(
55+
'aws.lambda',
56+
expect.objectContaining({
57+
aws_request_id: 'awsRequestId',
58+
function_name: 'functionName',
59+
function_version: 'functionVersion',
60+
invoked_function_arn: 'invokedFunctionArn',
61+
remaining_time_in_millis: 100,
62+
}),
63+
);
64+
// @ts-ignore see "Why @ts-ignore" note
65+
expect(Sentry.fakeScope.setContext).toBeCalledWith(
66+
'aws.cloudwatch.logs',
67+
expect.objectContaining({
68+
log_group: 'logGroupName',
69+
log_stream: 'logStreamName',
70+
}),
71+
);
72+
}
73+
4474
describe('AWSLambda', () => {
4575
afterEach(() => {
4676
// @ts-ignore see "Why @ts-ignore" note
@@ -140,7 +170,7 @@ describe('AWSLambda', () => {
140170

141171
describe('wrapHandler() on sync handler', () => {
142172
test('successful execution', async () => {
143-
expect.assertions(5);
173+
expect.assertions(10);
144174

145175
const handler: Handler = (_event, _context, callback) => {
146176
callback(null, 42);
@@ -149,15 +179,14 @@ describe('AWSLambda', () => {
149179
const rv = await wrappedHandler(fakeEvent, fakeContext, fakeCallback);
150180
expect(rv).toStrictEqual(42);
151181
expect(Sentry.startTransaction).toBeCalledWith({ name: 'functionName', op: 'awslambda.handler' });
152-
// @ts-ignore see "Why @ts-ignore" note
153-
expect(Sentry.fakeParentScope.setSpan).toBeCalledWith(Sentry.fakeTransaction);
182+
expectScopeSettings();
154183
// @ts-ignore see "Why @ts-ignore" note
155184
expect(Sentry.fakeTransaction.finish).toBeCalled();
156185
expect(Sentry.flush).toBeCalledWith(2000);
157186
});
158187

159188
test('unsuccessful execution', async () => {
160-
expect.assertions(5);
189+
expect.assertions(10);
161190

162191
const error = new Error('sorry');
163192
const handler: Handler = (_event, _context, callback) => {
@@ -169,8 +198,7 @@ describe('AWSLambda', () => {
169198
await wrappedHandler(fakeEvent, fakeContext, fakeCallback);
170199
} catch (e) {
171200
expect(Sentry.startTransaction).toBeCalledWith({ name: 'functionName', op: 'awslambda.handler' });
172-
// @ts-ignore see "Why @ts-ignore" note
173-
expect(Sentry.fakeParentScope.setSpan).toBeCalledWith(Sentry.fakeTransaction);
201+
expectScopeSettings();
174202
expect(Sentry.captureException).toBeCalledWith(error);
175203
// @ts-ignore see "Why @ts-ignore" note
176204
expect(Sentry.fakeTransaction.finish).toBeCalled();
@@ -191,7 +219,7 @@ describe('AWSLambda', () => {
191219
});
192220

193221
test('capture error', async () => {
194-
expect.assertions(5);
222+
expect.assertions(10);
195223

196224
const error = new Error('wat');
197225
const handler: Handler = (_event, _context, _callback) => {
@@ -203,8 +231,7 @@ describe('AWSLambda', () => {
203231
await wrappedHandler(fakeEvent, fakeContext, fakeCallback);
204232
} catch (e) {
205233
expect(Sentry.startTransaction).toBeCalledWith({ name: 'functionName', op: 'awslambda.handler' });
206-
// @ts-ignore see "Why @ts-ignore" note
207-
expect(Sentry.fakeParentScope.setSpan).toBeCalledWith(Sentry.fakeTransaction);
234+
expectScopeSettings();
208235
expect(Sentry.captureException).toBeCalledWith(e);
209236
// @ts-ignore see "Why @ts-ignore" note
210237
expect(Sentry.fakeTransaction.finish).toBeCalled();
@@ -215,7 +242,7 @@ describe('AWSLambda', () => {
215242

216243
describe('wrapHandler() on async handler', () => {
217244
test('successful execution', async () => {
218-
expect.assertions(5);
245+
expect.assertions(10);
219246

220247
const handler: Handler = async (_event, _context) => {
221248
return 42;
@@ -224,8 +251,7 @@ describe('AWSLambda', () => {
224251
const rv = await wrappedHandler(fakeEvent, fakeContext, fakeCallback);
225252
expect(rv).toStrictEqual(42);
226253
expect(Sentry.startTransaction).toBeCalledWith({ name: 'functionName', op: 'awslambda.handler' });
227-
// @ts-ignore see "Why @ts-ignore" note
228-
expect(Sentry.fakeParentScope.setSpan).toBeCalledWith(Sentry.fakeTransaction);
254+
expectScopeSettings();
229255
// @ts-ignore see "Why @ts-ignore" note
230256
expect(Sentry.fakeTransaction.finish).toBeCalled();
231257
expect(Sentry.flush).toBeCalled();
@@ -243,7 +269,7 @@ describe('AWSLambda', () => {
243269
});
244270

245271
test('capture error', async () => {
246-
expect.assertions(5);
272+
expect.assertions(10);
247273

248274
const error = new Error('wat');
249275
const handler: Handler = async (_event, _context) => {
@@ -255,8 +281,7 @@ describe('AWSLambda', () => {
255281
await wrappedHandler(fakeEvent, fakeContext, fakeCallback);
256282
} catch (e) {
257283
expect(Sentry.startTransaction).toBeCalledWith({ name: 'functionName', op: 'awslambda.handler' });
258-
// @ts-ignore see "Why @ts-ignore" note
259-
expect(Sentry.fakeParentScope.setSpan).toBeCalledWith(Sentry.fakeTransaction);
284+
expectScopeSettings();
260285
expect(Sentry.captureException).toBeCalledWith(error);
261286
// @ts-ignore see "Why @ts-ignore" note
262287
expect(Sentry.fakeTransaction.finish).toBeCalled();
@@ -267,7 +292,7 @@ describe('AWSLambda', () => {
267292

268293
describe('wrapHandler() on async handler with a callback method (aka incorrect usage)', () => {
269294
test('successful execution', async () => {
270-
expect.assertions(5);
295+
expect.assertions(10);
271296

272297
const handler: Handler = async (_event, _context, _callback) => {
273298
return 42;
@@ -276,8 +301,7 @@ describe('AWSLambda', () => {
276301
const rv = await wrappedHandler(fakeEvent, fakeContext, fakeCallback);
277302
expect(rv).toStrictEqual(42);
278303
expect(Sentry.startTransaction).toBeCalledWith({ name: 'functionName', op: 'awslambda.handler' });
279-
// @ts-ignore see "Why @ts-ignore" note
280-
expect(Sentry.fakeParentScope.setSpan).toBeCalledWith(Sentry.fakeTransaction);
304+
expectScopeSettings();
281305
// @ts-ignore see "Why @ts-ignore" note
282306
expect(Sentry.fakeTransaction.finish).toBeCalled();
283307
expect(Sentry.flush).toBeCalled();
@@ -295,7 +319,7 @@ describe('AWSLambda', () => {
295319
});
296320

297321
test('capture error', async () => {
298-
expect.assertions(5);
322+
expect.assertions(10);
299323

300324
const error = new Error('wat');
301325
const handler: Handler = async (_event, _context, _callback) => {
@@ -307,8 +331,7 @@ describe('AWSLambda', () => {
307331
await wrappedHandler(fakeEvent, fakeContext, fakeCallback);
308332
} catch (e) {
309333
expect(Sentry.startTransaction).toBeCalledWith({ name: 'functionName', op: 'awslambda.handler' });
310-
// @ts-ignore see "Why @ts-ignore" note
311-
expect(Sentry.fakeParentScope.setSpan).toBeCalledWith(Sentry.fakeTransaction);
334+
expectScopeSettings();
312335
expect(Sentry.captureException).toBeCalledWith(error);
313336
// @ts-ignore see "Why @ts-ignore" note
314337
expect(Sentry.fakeTransaction.finish).toBeCalled();

0 commit comments

Comments
 (0)