|
1 | 1 | /* eslint-disable @sentry-internal/sdk/no-optional-chaining */ |
2 | 2 | import type { Span } from '@sentry/core'; |
3 | | -import { getActiveTransaction, trace } from '@sentry/core'; |
| 3 | +import { getActiveTransaction, getCurrentHub, trace } from '@sentry/core'; |
4 | 4 | import { captureException } from '@sentry/node'; |
5 | 5 | import { |
6 | 6 | addExceptionMechanism, |
@@ -64,32 +64,42 @@ export const transformPageChunk: NonNullable<ResolveOptions['transformPageChunk' |
64 | 64 | * // export const handle = sequence(sentryHandle, yourCustomHandle); |
65 | 65 | * ``` |
66 | 66 | */ |
67 | | -export const sentryHandle: Handle = ({ event, resolve }) => { |
| 67 | +export const sentryHandle: Handle = input => { |
| 68 | + // if there is an active transaction, we know that this handle call is nested and hence |
| 69 | + // we don't create a new domain for it. If we created one, nested server calls would |
| 70 | + // create new transactions instead of adding a child span to the currently active span. |
| 71 | + if (getCurrentHub().getScope().getSpan()) { |
| 72 | + return instrumentHandle(input); |
| 73 | + } |
68 | 74 | return domain.create().bind(() => { |
69 | | - const sentryTraceHeader = event.request.headers.get('sentry-trace'); |
70 | | - const baggageHeader = event.request.headers.get('baggage'); |
71 | | - const traceparentData = sentryTraceHeader ? extractTraceparentData(sentryTraceHeader) : undefined; |
72 | | - const dynamicSamplingContext = baggageHeaderToDynamicSamplingContext(baggageHeader); |
73 | | - |
74 | | - return trace( |
75 | | - { |
76 | | - op: 'http.server', |
77 | | - name: `${event.request.method} ${event.route.id}`, |
78 | | - status: 'ok', |
79 | | - ...traceparentData, |
80 | | - metadata: { |
81 | | - source: 'route', |
82 | | - dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext, |
83 | | - }, |
84 | | - }, |
85 | | - async (span?: Span) => { |
86 | | - const res = await resolve(event, { transformPageChunk }); |
87 | | - if (span) { |
88 | | - span.setHttpStatus(res.status); |
89 | | - } |
90 | | - return res; |
91 | | - }, |
92 | | - sendErrorToSentry, |
93 | | - ); |
| 75 | + return instrumentHandle(input); |
94 | 76 | })(); |
95 | 77 | }; |
| 78 | + |
| 79 | +function instrumentHandle({ event, resolve }: Parameters<Handle>[0]): ReturnType<Handle> { |
| 80 | + const sentryTraceHeader = event.request.headers.get('sentry-trace'); |
| 81 | + const baggageHeader = event.request.headers.get('baggage'); |
| 82 | + const traceparentData = sentryTraceHeader ? extractTraceparentData(sentryTraceHeader) : undefined; |
| 83 | + const dynamicSamplingContext = baggageHeaderToDynamicSamplingContext(baggageHeader); |
| 84 | + |
| 85 | + return trace( |
| 86 | + { |
| 87 | + op: 'http.server', |
| 88 | + name: `${event.request.method} ${event.route.id}`, |
| 89 | + status: 'ok', |
| 90 | + ...traceparentData, |
| 91 | + metadata: { |
| 92 | + source: 'route', |
| 93 | + dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext, |
| 94 | + }, |
| 95 | + }, |
| 96 | + async (span?: Span) => { |
| 97 | + const res = await resolve(event, { transformPageChunk }); |
| 98 | + if (span) { |
| 99 | + span.setHttpStatus(res.status); |
| 100 | + } |
| 101 | + return res; |
| 102 | + }, |
| 103 | + sendErrorToSentry, |
| 104 | + ); |
| 105 | +} |
0 commit comments