-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathload.ts
More file actions
90 lines (79 loc) · 3.2 KB
/
load.ts
File metadata and controls
90 lines (79 loc) · 3.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import {
addNonEnumerableProperty,
handleCallbackErrors,
objectify,
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
startSpan,
} from '@sentry/core';
import { captureException } from '@sentry/svelte';
import type { LoadEvent } from '@sveltejs/kit';
import type { SentryWrappedFlag } from '../common/utils';
import { getRouteId, isHttpError, isRedirect } from '../common/utils';
type PatchedLoadEvent = LoadEvent & Partial<SentryWrappedFlag>;
function sendErrorToSentry(e: unknown): unknown {
// In case we have a primitive, wrap it in the equivalent wrapper class (string -> String, etc.) so that we can
// store a seen flag on it.
const objectifiedErr = objectify(e);
// We don't want to capture thrown `Redirect`s as these are not errors but expected behaviour
// Neither 4xx errors, given that they are not valuable.
if (
isRedirect(objectifiedErr) ||
(isHttpError(objectifiedErr) && objectifiedErr.status < 500 && objectifiedErr.status >= 400)
) {
return objectifiedErr;
}
captureException(objectifiedErr, {
mechanism: {
type: 'auto.function.sveltekit.load',
handled: false,
},
});
return objectifiedErr;
}
/**
* Wrap load function with Sentry. This wrapper will
*
* - catch errors happening during the execution of `load`
* - create a load span if performance monitoring is enabled
* - attach tracing Http headers to `fetch` requests if performance monitoring is enabled to get connected traces.
* - add a fetch breadcrumb for every `fetch` request
*
* Note that tracing Http headers are only attached if the url matches the specified `tracePropagationTargets`
* entries to avoid CORS errors.
*
* @param origLoad SvelteKit user defined load function
*/
// The liberal generic typing of `T` is necessary because we cannot let T extend `Load`.
// This function needs to tell TS that it returns exactly the type that it was called with
// because SvelteKit generates the narrowed down `PageLoad` or `LayoutLoad` types
// at build time for every route.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function wrapLoadWithSentry<T extends (...args: any) => any>(origLoad: T): T {
return new Proxy(origLoad, {
apply: (wrappingTarget, thisArg, args: Parameters<T>) => {
// Type casting here because `T` cannot extend `Load` (see comment above function signature)
const event = args[0] as PatchedLoadEvent;
// Check if already wrapped
if (event.__sentry_wrapped__) {
return wrappingTarget.apply(thisArg, args);
}
const patchedEvent: PatchedLoadEvent = {
...event,
};
addNonEnumerableProperty(patchedEvent as unknown as Record<string, unknown>, '__sentry_wrapped__', true);
const routeId = getRouteId(event);
return 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,
},
() => handleCallbackErrors(() => wrappingTarget.apply(thisArg, [patchedEvent]), sendErrorToSentry),
);
},
});
}