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' ;
5
2
import { 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' ;
16
4
import type { LoadEvent } from '@sveltejs/kit' ;
17
5
18
6
import type { SentryWrappedFlag } from '../common/utils' ;
19
7
import { isRedirect } from '../common/utils' ;
20
- import { isRequestCached } from './vendor/lookUpCache' ;
21
8
22
9
type PatchedLoadEvent = LoadEvent & Partial < SentryWrappedFlag > ;
23
10
@@ -80,7 +67,6 @@ export function wrapLoadWithSentry<T extends (...args: any) => any>(origLoad: T)
80
67
81
68
const patchedEvent : PatchedLoadEvent = {
82
69
...event ,
83
- fetch : instrumentSvelteKitFetch ( event . fetch ) ,
84
70
} ;
85
71
86
72
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)
101
87
} ,
102
88
} ) ;
103
89
}
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