Skip to content

Commit 751d26a

Browse files
committed
wip
1 parent 3a91a62 commit 751d26a

File tree

5 files changed

+220
-181
lines changed

5 files changed

+220
-181
lines changed

packages/sveltekit/src/client/load.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@ function sendErrorToSentry(e: unknown): unknown {
2828

2929
/**
3030
* Wrap load function with Sentry
31+
* TODO: usage
3132
*
3233
* @param origLoad SvelteKit user defined load function
3334
*/
34-
export function wrapLoadWithSentry(origLoad: Load): Load {
35+
export function wrapLoadWithSentry<T extends Load>(origLoad: T): T {
3536
return new Proxy(origLoad, {
36-
apply: (wrappingTarget, thisArg, args: Parameters<Load>) => {
37+
apply: (wrappingTarget, thisArg, args: Parameters<T>) => {
3738
const [event] = args;
3839

3940
const routeId = event.route.id;

packages/sveltekit/src/index.types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export * from './server';
99

1010
import type { Integration, Options, StackParser } from '@sentry/types';
1111
// eslint-disable-next-line import/no-unresolved
12-
import type { HandleClientError, HandleServerError, Load, ServerLoad } from '@sveltejs/kit';
12+
import type { HandleClientError, HandleServerError, Load } from '@sveltejs/kit';
1313

1414
import type * as clientSdk from './client';
1515
import type * as serverSdk from './server';
@@ -21,7 +21,7 @@ export declare function handleErrorWithSentry<T extends HandleClientError | Hand
2121
handleError?: T,
2222
): ReturnType<T>;
2323

24-
export declare function wrapLoadWithSentry<S extends ServerLoad | Load>(origLoad: S): S;
24+
export declare function wrapLoadWithSentry<T extends Load>(origLoad: T): T;
2525

2626
// We export a merged Integrations object so that users can (at least typing-wise) use all integrations everywhere.
2727
export declare const Integrations: typeof clientSdk.Integrations & typeof serverSdk.Integrations;

packages/sveltekit/src/server/handle.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,12 @@
22
import type { Span } from '@sentry/core';
33
import { getActiveTransaction, getCurrentHub, trace } from '@sentry/core';
44
import { captureException } from '@sentry/node';
5-
import {
6-
addExceptionMechanism,
7-
baggageHeaderToDynamicSamplingContext,
8-
dynamicSamplingContextToSentryBaggageHeader,
9-
extractTraceparentData,
10-
objectify,
11-
} from '@sentry/utils';
5+
import { addExceptionMechanism, dynamicSamplingContextToSentryBaggageHeader, objectify } from '@sentry/utils';
126
import type { Handle, ResolveOptions } from '@sveltejs/kit';
137
import * as domain from 'domain';
148

9+
import { getTracePropagationData } from './utils';
10+
1511
function sendErrorToSentry(e: unknown): unknown {
1612
// In case we have a primitive, wrap it in the equivalent wrapper class (string -> String, etc.) so that we can
1713
// store a seen flag on it.
@@ -77,10 +73,7 @@ export const sentryHandle: Handle = input => {
7773
};
7874

7975
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);
76+
const { traceparentData, dynamicSamplingContext } = getTracePropagationData(event);
8477

8578
return trace(
8679
{

packages/sveltekit/src/server/load.ts

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
/* eslint-disable @sentry-internal/sdk/no-optional-chaining */
22
import { trace } from '@sentry/core';
33
import { captureException } from '@sentry/node';
4-
import type { DynamicSamplingContext, TraceparentData, TransactionContext } from '@sentry/types';
5-
import {
6-
addExceptionMechanism,
7-
baggageHeaderToDynamicSamplingContext,
8-
extractTraceparentData,
9-
objectify,
10-
} from '@sentry/utils';
11-
import type { HttpError, Load, LoadEvent, ServerLoad, ServerLoadEvent } from '@sveltejs/kit';
4+
import type { TransactionContext } from '@sentry/types';
5+
import { addExceptionMechanism, objectify } from '@sentry/utils';
6+
import type { HttpError, Load, ServerLoad } from '@sveltejs/kit';
7+
8+
import { getTracePropagationData } from './utils';
129

1310
function isHttpError(err: unknown): err is HttpError {
1411
return typeof err === 'object' && err !== null && 'status' in err && 'body' in err;
@@ -45,58 +42,65 @@ function sendErrorToSentry(e: unknown): unknown {
4542
}
4643

4744
/**
48-
* Wrap load function with Sentry
45+
* Wrap a universal load function (e.g. +page.js or +layout.js) with Sentry functionality
46+
*
47+
* Usage:
48+
* ```js
49+
* import { }
50+
* ```
4951
*
5052
* @param origLoad SvelteKit user defined load function
5153
*/
52-
export function wrapLoadWithSentry<T extends ServerLoad | Load>(origLoad: T): T {
54+
export function wrapLoadWithSentry<T extends Load>(origLoad: T): T {
5355
return new Proxy(origLoad, {
54-
apply: (wrappingTarget, thisArg, args: Parameters<ServerLoad | Load>) => {
56+
apply: (wrappingTarget, thisArg, args: Parameters<T>) => {
5557
const [event] = args;
5658
const routeId = event.route && event.route.id;
5759

58-
const { traceparentData, dynamicSamplingContext } = getTracePropagationData(event);
59-
6060
const traceLoadContext: TransactionContext = {
61-
op: `function.sveltekit${isServerOnlyLoad(event) ? '.server' : ''}.load`,
61+
op: 'function.sveltekit.load',
6262
name: routeId ? routeId : event.url.pathname,
6363
status: 'ok',
6464
metadata: {
6565
source: routeId ? 'route' : 'url',
66-
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
6766
},
68-
...traceparentData,
6967
};
7068

7169
return trace(traceLoadContext, () => wrappingTarget.apply(thisArg, args), sendErrorToSentry);
7270
},
7371
});
7472
}
7573

76-
function getTracePropagationData(event: ServerLoadEvent | LoadEvent): {
77-
traceparentData?: TraceparentData;
78-
dynamicSamplingContext?: Partial<DynamicSamplingContext>;
79-
} {
80-
if (!isServerOnlyLoad(event)) {
81-
return {};
82-
}
83-
84-
const sentryTraceHeader = event.request.headers.get('sentry-trace');
85-
const baggageHeader = event.request.headers.get('baggage');
86-
const traceparentData = sentryTraceHeader ? extractTraceparentData(sentryTraceHeader) : undefined;
87-
const dynamicSamplingContext = baggageHeaderToDynamicSamplingContext(baggageHeader);
88-
89-
return { traceparentData, dynamicSamplingContext };
90-
}
91-
9274
/**
93-
* Our server-side wrapLoadWithSentry can be used to wrap two different kinds of `load` functions:
94-
* - load functions from `+(page|layout).ts`: These can be called both on client and on server
95-
* - load functions from `+(page|layout).server.ts`: These are only called on the server
75+
* Wrap a server-only load function (e.g. +page.server.js or +layout.server.js) with Sentry functionality
76+
* TODO: usage
9677
*
97-
* In both cases, load events look differently. We can distinguish them by checking if the
98-
* event has a `request` field (which only the server-exclusive load event has).
78+
* @param origServerLoad SvelteKit user defined server-only load function
9979
*/
100-
function isServerOnlyLoad(event: ServerLoadEvent | LoadEvent): event is ServerLoadEvent {
101-
return 'request' in event;
80+
export function wrapServerLoadWithSentry<T extends ServerLoad>(origServerLoad: T): T {
81+
return new Proxy(origServerLoad, {
82+
apply: (wrappingTarget, thisArg, args: Parameters<T>) => {
83+
const [event] = args;
84+
const routeId = event.route && event.route.id;
85+
86+
// Usually, the `handleWithSentry` hook handler should already create a transaction and store
87+
// traceparent and DSC on that transaction before the server-only load function is called.
88+
// However, since we have access to `event.request` we can still pass it to `trace`
89+
// in case our handler isn't called or for some reason the handle hook is bypassed.
90+
const { dynamicSamplingContext, traceparentData } = getTracePropagationData(event);
91+
92+
const traceLoadContext: TransactionContext = {
93+
op: 'function.sveltekit.server.load',
94+
name: routeId ? routeId : event.url.pathname,
95+
status: 'ok',
96+
metadata: {
97+
source: routeId ? 'route' : 'url',
98+
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
99+
},
100+
...traceparentData,
101+
};
102+
103+
return trace(traceLoadContext, () => wrappingTarget.apply(thisArg, args), sendErrorToSentry);
104+
},
105+
});
102106
}

0 commit comments

Comments
 (0)