Skip to content

ref(sveltekit): Update trace propagation & span options #10838

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 38 additions & 38 deletions packages/sveltekit/src/server/handle.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import {
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
continueTrace,
getActiveSpan,
getCurrentScope,
getDynamicSamplingContextFromSpan,
getRootSpan,
setHttpStatus,
spanToTraceHeader,
withIsolationScope,
} from '@sentry/core';
import { getActiveTransaction, startSpan } from '@sentry/core';
import { startSpan } from '@sentry/core';
import { captureException } from '@sentry/node-experimental';
/* eslint-disable @sentry-internal/sdk/no-optional-chaining */
import type { Span } from '@sentry/types';
import { dynamicSamplingContextToSentryBaggageHeader, objectify } from '@sentry/utils';
import type { Handle, ResolveOptions } from '@sveltejs/kit';

Expand Down Expand Up @@ -103,12 +104,12 @@ export function addSentryCodeToPage(options: SentryHandleOptions): NonNullable<R
const nonce = fetchProxyScriptNonce ? `nonce="${fetchProxyScriptNonce}"` : '';

return ({ html }) => {
// eslint-disable-next-line deprecation/deprecation
const transaction = getActiveTransaction();
if (transaction) {
const traceparentData = spanToTraceHeader(transaction);
const activeSpan = getActiveSpan();
const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;
if (rootSpan) {
const traceparentData = spanToTraceHeader(rootSpan);
const dynamicSamplingContext = dynamicSamplingContextToSentryBaggageHeader(
getDynamicSamplingContextFromSpan(transaction),
getDynamicSamplingContextFromSpan(rootSpan),
);
const contentMeta = `<head>
<meta name="sentry-trace" content="${traceparentData}"/>
Expand Down Expand Up @@ -170,36 +171,35 @@ async function instrumentHandle(
return resolve(event);
}

const { dynamicSamplingContext, traceparentData, propagationContext } = getTracePropagationData(event);
getCurrentScope().setPropagationContext(propagationContext);

try {
const resolveResult = await startSpan(
{
op: 'http.server',
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.sveltekit',
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: event.route?.id ? 'route' : 'url',
const { sentryTrace, baggage } = getTracePropagationData(event);

return continueTrace({ sentryTrace, baggage }, async () => {
try {
const resolveResult = await startSpan(
{
op: 'http.server',
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.sveltekit',
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: event.route?.id ? 'route' : 'url',
},
name: `${event.request.method} ${event.route?.id || event.url.pathname}`,
},
name: `${event.request.method} ${event.route?.id || event.url.pathname}`,
...traceparentData,
metadata: {
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
async (span?: Span) => {
const res = await resolve(event, {
transformPageChunk: addSentryCodeToPage(options),
});
if (span) {
setHttpStatus(span, res.status);
}
return res;
},
},
async span => {
const res = await resolve(event, {
transformPageChunk: addSentryCodeToPage(options),
});
setHttpStatus(span, res.status);
return res;
},
);
return resolveResult;
} catch (e: unknown) {
sendErrorToSentry(e);
throw e;
} finally {
await flushIfServerless();
}
);
return resolveResult;
} catch (e: unknown) {
sendErrorToSentry(e);
throw e;
} finally {
await flushIfServerless();
}
});
}
77 changes: 36 additions & 41 deletions packages/sveltekit/src/server/load.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
/* eslint-disable @sentry-internal/sdk/no-optional-chaining */
import {
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
getCurrentScope,
continueTrace,
startSpan,
} from '@sentry/core';
import { captureException } from '@sentry/node-experimental';
import { addNonEnumerableProperty, objectify } from '@sentry/utils';
import type { LoadEvent, ServerLoadEvent } from '@sveltejs/kit';

import type { TransactionContext } from '@sentry/types';
import type { SentryWrappedFlag } from '../common/utils';
import { isHttpError, isRedirect } from '../common/utils';
import { flushIfServerless, getTracePropagationData } from './utils';
Expand Down Expand Up @@ -70,18 +68,19 @@ export function wrapLoadWithSentry<T extends (...args: any) => any>(origLoad: T)

const routeId = event.route && event.route.id;

const traceLoadContext: TransactionContext = {
op: 'function.sveltekit.load',
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.sveltekit',
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeId ? 'route' : 'url',
},
name: routeId ? routeId : event.url.pathname,
};

try {
// We need to await before returning, otherwise we won't catch any errors thrown by the load function
return await startSpan(traceLoadContext, () => wrappingTarget.apply(thisArg, args));
return await startSpan(
{
op: 'function.sveltekit.load',
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.sveltekit',
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeId ? 'route' : 'url',
},
name: routeId ? routeId : event.url.pathname,
},
() => wrappingTarget.apply(thisArg, args),
);
} catch (e) {
sendErrorToSentry(e);
throw e;
Expand Down Expand Up @@ -133,34 +132,30 @@ export function wrapServerLoadWithSentry<T extends (...args: any) => any>(origSe
// https://github.com/sveltejs/kit/blob/e133aba479fa9ba0e7f9e71512f5f937f0247e2c/packages/kit/src/runtime/server/page/load_data.js#L111C3-L124
const routeId = event.route && (Object.getOwnPropertyDescriptor(event.route, 'id')?.value as string | undefined);

const { dynamicSamplingContext, traceparentData, propagationContext } = getTracePropagationData(event);
getCurrentScope().setPropagationContext(propagationContext);

const traceLoadContext: TransactionContext = {
op: 'function.sveltekit.server.load',
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.sveltekit',
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeId ? 'route' : 'url',
},
name: routeId ? routeId : event.url.pathname,
metadata: {
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
},
data: {
'http.method': event.request.method,
},
...traceparentData,
};

try {
// We need to await before returning, otherwise we won't catch any errors thrown by the load function
return await startSpan(traceLoadContext, () => wrappingTarget.apply(thisArg, args));
} catch (e: unknown) {
sendErrorToSentry(e);
throw e;
} finally {
await flushIfServerless();
}
const { sentryTrace, baggage } = getTracePropagationData(event);

return continueTrace({ sentryTrace, baggage }, async () => {
try {
// We need to await before returning, otherwise we won't catch any errors thrown by the load function
return await startSpan(
{
op: 'function.sveltekit.server.load',
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.sveltekit',
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeId ? 'route' : 'url',
'http.method': event.request.method,
},
name: routeId ? routeId : event.url.pathname,
},
() => wrappingTarget.apply(thisArg, args),
);
} catch (e: unknown) {
sendErrorToSentry(e);
throw e;
} finally {
await flushIfServerless();
}
});
},
});
}
13 changes: 6 additions & 7 deletions packages/sveltekit/src/server/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { flush } from '@sentry/node-experimental';
import { logger, tracingContextFromHeaders } from '@sentry/utils';
import { logger } from '@sentry/utils';
import type { RequestEvent } from '@sveltejs/kit';

import { DEBUG_BUILD } from '../common/debug-build';
Expand All @@ -10,12 +10,11 @@ import { DEBUG_BUILD } from '../common/debug-build';
*
* Sets propagation context as a side effect.
*/
// eslint-disable-next-line deprecation/deprecation
export function getTracePropagationData(event: RequestEvent): ReturnType<typeof tracingContextFromHeaders> {
const sentryTraceHeader = event.request.headers.get('sentry-trace') || '';
const baggageHeader = event.request.headers.get('baggage');
// eslint-disable-next-line deprecation/deprecation
return tracingContextFromHeaders(sentryTraceHeader, baggageHeader);
export function getTracePropagationData(event: RequestEvent): { sentryTrace: string; baggage: string | null } {
const sentryTrace = event.request.headers.get('sentry-trace') || '';
const baggage = event.request.headers.get('baggage');

return { sentryTrace, baggage };
}

/** Flush the event queue to ensure that events get sent to Sentry before the response is finished and the lambda ends */
Expand Down
Loading