1- import { addTracingHeadersToFetchRequest } from '@sentry-internal/tracing' ;
2- import type { BaseClient } from '@sentry/core' ;
3- import { getCurrentHub , trace } from '@sentry/core' ;
4- import type { Breadcrumbs , BrowserTracing } from '@sentry/svelte' ;
1+ import { trace } from '@sentry/core' ;
52import { captureException } from '@sentry/svelte' ;
6- import type { Client , ClientOptions , SanitizedRequestData , Span } from '@sentry/types' ;
7- import {
8- addExceptionMechanism ,
9- addNonEnumerableProperty ,
10- getSanitizedUrlString ,
11- objectify ,
12- parseFetchArgs ,
13- parseUrl ,
14- stringMatchesSomePattern ,
15- } from '@sentry/utils' ;
3+ import { addExceptionMechanism , addNonEnumerableProperty , objectify } from '@sentry/utils' ;
164import type { LoadEvent } from '@sveltejs/kit' ;
175
186import type { SentryWrappedFlag } from '../common/utils' ;
197import { isRedirect } from '../common/utils' ;
20- import { isRequestCached } from './vendor/lookUpCache' ;
218
229type PatchedLoadEvent = LoadEvent & Partial < SentryWrappedFlag > ;
2310
@@ -80,7 +67,6 @@ export function wrapLoadWithSentry<T extends (...args: any) => any>(origLoad: T)
8067
8168 const patchedEvent : PatchedLoadEvent = {
8269 ...event ,
83- fetch : instrumentSvelteKitFetch ( event . fetch ) ,
8470 } ;
8571
8672 addNonEnumerableProperty ( patchedEvent as unknown as Record < string , unknown > , '__sentry_wrapped__' , true ) ;
@@ -101,182 +87,3 @@ export function wrapLoadWithSentry<T extends (...args: any) => any>(origLoad: T)
10187 } ,
10288 } ) ;
10389}
104-
105- type SvelteKitFetch = LoadEvent [ 'fetch' ] ;
106-
107- /**
108- * Instruments SvelteKit's client `fetch` implementation which is passed to the client-side universal `load` functions.
109- *
110- * We need to instrument this in addition to the native fetch we instrument in BrowserTracing because SvelteKit
111- * stores the native fetch implementation before our SDK is initialized.
112- *
113- * see: https://github.com/sveltejs/kit/blob/master/packages/kit/src/runtime/client/fetcher.js
114- *
115- * This instrumentation takes the fetch-related options from `BrowserTracing` to determine if we should
116- * instrument fetch for perfomance monitoring, create a span for or attach our tracing headers to the given request.
117- *
118- * To dertermine if breadcrumbs should be recorded, this instrumentation relies on the availability of and the options
119- * set in the `BreadCrumbs` integration.
120- *
121- * @param originalFetch SvelteKit's original fetch implemenetation
122- *
123- * @returns a proxy of SvelteKit's fetch implementation
124- */
125- function instrumentSvelteKitFetch ( originalFetch : SvelteKitFetch ) : SvelteKitFetch {
126- const client = getCurrentHub ( ) . getClient ( ) ;
127-
128- if ( ! isValidClient ( client ) ) {
129- return originalFetch ;
130- }
131-
132- const options = client . getOptions ( ) ;
133-
134- const browserTracingIntegration = client . getIntegrationById ( 'BrowserTracing' ) as BrowserTracing | undefined ;
135- const breadcrumbsIntegration = client . getIntegrationById ( 'Breadcrumbs' ) as Breadcrumbs | undefined ;
136-
137- const browserTracingOptions = browserTracingIntegration && browserTracingIntegration . options ;
138-
139- const shouldTraceFetch = browserTracingOptions && browserTracingOptions . traceFetch ;
140- const shouldAddFetchBreadcrumb = breadcrumbsIntegration && breadcrumbsIntegration . options . fetch ;
141-
142- /* Identical check as in BrowserTracing, just that we also need to verify that BrowserTracing is actually installed */
143- const shouldCreateSpan =
144- browserTracingOptions && typeof browserTracingOptions . shouldCreateSpanForRequest === 'function'
145- ? browserTracingOptions . shouldCreateSpanForRequest
146- : ( _ : string ) => shouldTraceFetch ;
147-
148- /* Identical check as in BrowserTracing, just that we also need to verify that BrowserTracing is actually installed */
149- const shouldAttachHeaders : ( url : string ) => boolean = url => {
150- return (
151- ! ! shouldTraceFetch &&
152- stringMatchesSomePattern (
153- url ,
154- options . tracePropagationTargets || browserTracingOptions . tracePropagationTargets || [ 'localhost' , / ^ \/ / ] ,
155- )
156- ) ;
157- } ;
158-
159- return new Proxy ( originalFetch , {
160- apply : ( wrappingTarget , thisArg , args : Parameters < LoadEvent [ 'fetch' ] > ) => {
161- const [ input , init ] = args ;
162-
163- if ( isRequestCached ( input , init ) ) {
164- return wrappingTarget . apply ( thisArg , args ) ;
165- }
166-
167- const { url : rawUrl , method } = parseFetchArgs ( args ) ;
168-
169- // TODO: extract this to a util function (and use it in breadcrumbs integration as well)
170- if ( rawUrl . match ( / s e n t r y _ k e y / ) ) {
171- // We don't create spans or breadcrumbs for fetch requests that contain `sentry_key` (internal sentry requests)
172- return wrappingTarget . apply ( thisArg , args ) ;
173- }
174-
175- const urlObject = parseUrl ( rawUrl ) ;
176-
177- const requestData : SanitizedRequestData = {
178- url : getSanitizedUrlString ( urlObject ) ,
179- 'http.method' : method ,
180- ...( urlObject . search && { 'http.query' : urlObject . search . substring ( 1 ) } ) ,
181- ...( urlObject . hash && { 'http.hash' : urlObject . hash . substring ( 1 ) } ) ,
182- } ;
183-
184- const patchedInit : RequestInit = { ...init } ;
185- const hub = getCurrentHub ( ) ;
186- const scope = hub . getScope ( ) ;
187- const client = hub . getClient ( ) ;
188-
189- let fetchPromise : Promise < Response > ;
190-
191- function callFetchTarget ( span ?: Span ) : Promise < Response > {
192- if ( client && shouldAttachHeaders ( rawUrl ) ) {
193- const headers = addTracingHeadersToFetchRequest ( input as string | Request , client , scope , patchedInit , span ) ;
194- patchedInit . headers = headers as HeadersInit ;
195- }
196- const patchedFetchArgs = [ input , patchedInit ] ;
197- return wrappingTarget . apply ( thisArg , patchedFetchArgs ) ;
198- }
199-
200- if ( shouldCreateSpan ( rawUrl ) ) {
201- fetchPromise = trace (
202- {
203- name : `${ method } ${ requestData . url } ` , // this will become the description of the span
204- op : 'http.client' ,
205- data : requestData ,
206- } ,
207- span => {
208- const promise = callFetchTarget ( span ) ;
209- if ( span ) {
210- promise . then ( res => span . setHttpStatus ( res . status ) ) . catch ( _ => span . setStatus ( 'internal_error' ) ) ;
211- }
212- return promise ;
213- } ,
214- ) ;
215- } else {
216- fetchPromise = callFetchTarget ( ) ;
217- }
218-
219- if ( shouldAddFetchBreadcrumb ) {
220- addFetchBreadcrumb ( fetchPromise , requestData , args ) ;
221- }
222-
223- return fetchPromise ;
224- } ,
225- } ) ;
226- }
227-
228- /* Adds a breadcrumb for the given fetch result */
229- function addFetchBreadcrumb (
230- fetchResult : Promise < Response > ,
231- requestData : SanitizedRequestData ,
232- args : Parameters < SvelteKitFetch > ,
233- ) : void {
234- const breadcrumbStartTimestamp = Date . now ( ) ;
235- fetchResult . then (
236- response => {
237- getCurrentHub ( ) . addBreadcrumb (
238- {
239- type : 'http' ,
240- category : 'fetch' ,
241- data : {
242- ...requestData ,
243- status_code : response . status ,
244- } ,
245- } ,
246- {
247- input : args ,
248- response,
249- startTimestamp : breadcrumbStartTimestamp ,
250- endTimestamp : Date . now ( ) ,
251- } ,
252- ) ;
253- } ,
254- error => {
255- getCurrentHub ( ) . addBreadcrumb (
256- {
257- type : 'http' ,
258- category : 'fetch' ,
259- level : 'error' ,
260- data : requestData ,
261- } ,
262- {
263- input : args ,
264- data : error ,
265- startTimestamp : breadcrumbStartTimestamp ,
266- endTimestamp : Date . now ( ) ,
267- } ,
268- ) ;
269- } ,
270- ) ;
271- }
272-
273- type MaybeClientWithGetIntegrationsById =
274- | ( Client & { getIntegrationById ?: BaseClient < ClientOptions > [ 'getIntegrationById' ] } )
275- | undefined ;
276-
277- type ClientWithGetIntegrationById = Required < MaybeClientWithGetIntegrationsById > &
278- Exclude < MaybeClientWithGetIntegrationsById , undefined > ;
279-
280- function isValidClient ( client : MaybeClientWithGetIntegrationsById ) : client is ClientWithGetIntegrationById {
281- return ! ! client && typeof client . getIntegrationById === 'function' ;
282- }
0 commit comments