8000 feat(node-experimental): Add `withActiveSpan` (#10194) · GingerAdonis/sentry-javascript@b397b39 · GitHub
[go: up one dir, main page]

Skip to content

Commit b397b39

Browse files
authored
feat(node-experimental): Add withActiveSpan (getsentry#10194)
1 parent 56206f5 commit b397b39

File tree

3 files changed

+71
-1
lines changed

3 files changed

+71
-1
lines changed

packages/node-experimental/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export {
3232
setUser,
3333
withScope,
3434
withIsolationScope,
35+
withActiveSpan,
3536
// eslint-disable-next-line deprecation/deprecation
3637
configureScope,
3738
getCurrentScope,

packages/node-experimental/src/sdk/api.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// PUBLIC APIS
22

3-
import { context } from '@opentelemetry/api';
3+
import type { Span } from '@opentelemetry/api';
4+
import { context, trace } from '@opentelemetry/api';
45
import type {
56
Breadcrumb,
67
BreadcrumbHint,
@@ -63,6 +64,18 @@ export function withScope<T>(
6364
return context.with(context.active(), () => callback(getCurrentScope()));
6465
}
6566

67+
/**
68+
* Forks the current scope and sets the provided span as active span in the context of the provided callback.
69+
*
70+
* @param span Spans started in the context of the provided callback will be children of this span.
71+
* @param callback Execution context in which the provided span will be active. Is passed the newly forked scope.
72+
* @returns the value returned from the provided callback function.
73+
*/
74+
export function withActiveSpan<T>(span: Span, callback: (scope: Scope) => T): T {
75+
const newContextWithActiveSpan = trace.setSpan(context.active(), span);
76+
return context.with(newContextWithActiveSpan, () => callback(getCurrentScope()));
77+
}
78+
6679
/**
6780
* For a new isolation scope from the current isolation scope,
6881
* and make it the current isolation scope in the given callback.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { getActiveSpan, getClient, startInactiveSpan, startSpan, withActiveSpan } from '../../src';
2+
import { cleanupOtel, mockSdkInit } from '../helpers/mockSdkInit';
3+
4+
afterEach(() => {
5+
jest.restoreAllMocks();
6+
cleanupOtel();
7+
});
8+
9+
describe('withActiveSpan()', () => {
10+
it('should set the active span within the callback', () => {
11+
mockSdkInit();
12+
13+
const inactiveSpan = startInactiveSpan({ name: 'inactive-span' });
14+
15+
expect(getActiveSpan()).not.toBe(inactiveSpan);
16+
17+
withActiveSpan(inactiveSpan, () => {
18+
expect(getActiveSpan()).toBe(inactiveSpan);
19+
});
20+
});
21+
22+
it('should create child spans when calling startSpan within the callback', async () => {
23+
const beforeSendTransaction = jest.fn(() => null);
24+
mockSdkInit({ enableTracing: true, beforeSendTransaction });
25+
const client = getClient();
26+
27+
const inactiveSpan = startInactiveSpan({ name: 'inactive-span' });
28+
29+
withActiveSpan(inactiveSpan, () => {
30+
startSpan({ name: 'child-span' }, () => {});
31+
});
32+
33+
startSpan({ name: 'floating-span' }, () => {});
34+
35+
inactiveSpan.end();
36+
37+
await client.flush();
38+
39+
// The child span should be a child of the inactive span
40+
expect(beforeSendTransaction).toHaveBeenCalledWith(
41+
expect.objectContaining({
42+
transaction: 'inactive-span',
43+
spans: expect.arrayContaining([expect.objectContaining({ description: 'child-span' })]),
44+
}),
45+
expect.anything(),
46+
);
47+
48+
// The floating span should be a separate transaction
49+
expect(beforeSendTransaction).toHaveBeenCalledWith(
50+
expect.objectContaining({
51+
transaction: 'floating-span',
52+
}),
53+
expect.anything(),
54+
);
55+
});
56+
});

0 commit comments

Comments
 (0)
0