Skip to content

Commit 6025ab9

Browse files
HazATkamilogorek
authored andcommitted
Fix/span on headers (getsentry#2341)
* fix: Correctly send span id in trace header for xhr * fix: Set correct headers for fetch * meta: Changelog
1 parent 67c726d commit 6025ab9

File tree

2 files changed

+45
-141
lines changed

2 files changed

+45
-141
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
Coming soon...
66

7-
## 5.10.0
7+
- [apm] fix: Sent correct span id with outgoing requests
8+
9+
## 5.10.0
810

911
- [hub] feat: Update `span` implementation (#2161)
1012
- [apm] feat: Add `@sentry/apm` package

packages/apm/src/integrations/tracing.ts

+42-140
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
import { EventProcessor, Hub, Integration, Span, SpanContext, SpanStatus } from '@sentry/types';
2-
import {
3-
addInstrumentationHandler,
4-
fill,
5-
getGlobalObject,
6-
isMatchingPattern,
7-
logger,
8-
supportsNativeFetch,
9-
} from '@sentry/utils';
2+
import { addInstrumentationHandler, getGlobalObject, isMatchingPattern, logger } from '@sentry/utils';
103

114
/**
125
* Options for Tracing integration
@@ -85,13 +78,6 @@ export class Tracing implements Integration {
8578
*/
8679
public static id: string = 'Tracing';
8780

88-
/**
89-
* If we have an xhr we need to store the url in the instance.
90-
*
91-
*/
92-
// @ts-ignore
93-
private _xhrUrl?: string;
94-
9581
/**
9682
* Is Tracing enabled, this will be determined once per pageload.
9783
*/
@@ -109,7 +95,7 @@ export class Tracing implements Integration {
10995

11096
private static _currentIndex: number = 0;
11197

112-
private static readonly _activities: { [key: number]: Activity } = {};
98+
public static readonly _activities: { [key: number]: Activity } = {};
11399

114100
private static _debounce: number = 0;
115101

@@ -124,7 +110,10 @@ export class Tracing implements Integration {
124110
idleTimeout: 500,
125111
shouldCreateSpanForRequest(url: string): boolean {
126112
const origins = (_options && _options.tracingOrigins) || defaultTracingOrigins;
127-
return origins.some((origin: string | RegExp) => isMatchingPattern(url, origin));
113+
return (
114+
origins.some((origin: string | RegExp) => isMatchingPattern(url, origin)) &&
115+
!isMatchingPattern(url, 'sentry_key')
116+
);
128117
},
129118
startTransactionOnLocationChange: true,
130119
traceFetch: true,
@@ -160,15 +149,13 @@ export class Tracing implements Integration {
160149
callback: xhrCallback,
161150
type: 'xhr',
162151
});
163-
this._traceXHR(getCurrentHub);
164152
}
165153
// tslint:disable-next-line: no-non-null-assertion
166154
if (this._options!.traceFetch !== false) {
167155
addInstrumentationHandler({
168156
callback: fetchCallback,
169157
type: 'fetch',
170158
});
171-
this._traceFetch(getCurrentHub);
172159
}
173160

174161
// tslint:disable-next-line: no-non-null-assertion
@@ -188,120 +175,6 @@ export class Tracing implements Integration {
188175
}
189176
}
190177

191-
/**
192-
* JSDoc
193-
*/
194-
private _traceXHR(getCurrentHub: () => Hub): void {
195-
if (!('XMLHttpRequest' in getGlobalObject<Window>())) {
196-
return;
197-
}
198-
199-
const xhrproto = XMLHttpRequest.prototype;
200-
201-
fill(
202-
xhrproto,
203-
'open',
204-
originalOpen =>
205-
function(this: XMLHttpRequest, ...args: any[]): void {
206-
// @ts-ignore
207-
const self = getCurrentHub().getIntegration(Tracing);
208-
if (self) {
209-
self._xhrUrl = args[1] as string;
210-
}
211-
// tslint:disable-next-line: no-unsafe-any
212-
return originalOpen.apply(this, args);
213-
},
214-
);
215-
216-
fill(
217-
xhrproto,
218-
'send',
219-
originalSend =>
220-
function(this: XMLHttpRequest, ...args: any[]): void {
221-
// @ts-ignore
222-
const self = getCurrentHub().getIntegration(Tracing);
223-
// tslint:disable-next-line: no-non-null-assertion
224-
if (self && self._xhrUrl && self._options!.tracingOrigins) {
225-
const url = self._xhrUrl;
226-
const headers = getCurrentHub().traceHeaders();
227-
// tslint:disable-next-line: prefer-for-of no-non-null-assertion
228-
let isWhitelisted = self._options!.tracingOrigins.some((origin: string | RegExp) =>
229-
isMatchingPattern(url, origin),
230-
);
231-
232-
if (isMatchingPattern(url, 'sentry_key')) {
233-
// If sentry_key is in the url, it's an internal store request to sentry
234-
// we do not want to add the trace header to store requests
235-
isWhitelisted = false;
236-
}
237-
238-
if (isWhitelisted && this.setRequestHeader) {
239-
Object.keys(headers).forEach(key => {
240-
this.setRequestHeader(key, headers[key]);
241-
});
242-
}
243-
}
244-
// tslint:disable-next-line: no-unsafe-any
245-
return originalSend.apply(this, args);
246-
},
247-
);
248-
}
249-
250-
/**
251-
* JSDoc
252-
*/
253-
private _traceFetch(getCurrentHub: () => Hub): void {
254-
if (!supportsNativeFetch()) {
255-
return;
256-
}
257-
258-
// tslint:disable: only-arrow-functions
259-
fill(getGlobalObject<Window>(), 'fetch', function(originalFetch: () => void): () => void {
260-
return function(...args: any[]): void {
261-
// @ts-ignore
262-
const hub = getCurrentHub();
263-
const self = hub.getIntegration(Tracing);
264-
// tslint:disable-next-line: no-non-null-assertion
265-
if (self && self._options!.tracingOrigins) {
266-
const url = args[0] as string;
267-
const options = (args[1] = (args[1] as { [key: string]: any }) || {});
268-
269-
let isWhitelisted = false;
270-
// tslint:disable-next-line: no-non-null-assertion
271-
self._options!.tracingOrigins.forEach((whiteListUrl: string | RegExp) => {
272-
if (!isWhitelisted) {
273-
isWhitelisted = isMatchingPattern(url, whiteListUrl);
274-
}
275-
});
276-
277-
if (isMatchingPattern(url, 'sentry_key')) {
278-
// If sentry_key is in the url, it's an internal store request to sentry
279-
// we do not want to add the trace header to store requests
280-
isWhitelisted = false;
281-
}
282-
283-
if (isWhitelisted) {
284-
if (options.headers) {
285-
if (Array.isArray(options.headers)) {
286-
options.headers = [...options.headers, ...Object.entries(hub.traceHeaders())];
287-
} else {
288-
options.headers = {
289-
...options.headers,
290-
...hub.traceHeaders(),
291-
};
292-
}
293-
} else {
294-
options.headers = hub.traceHeaders();
295-
}
296-
}
297-
}
298-
// tslint:disable-next-line: no-unsafe-any
299-
return originalFetch.apply(getGlobalObject<Window>(), args);
300-
};
301-
});
302-
// tslint:enable: only-arrow-functions
303-
}
304-
305178
/**
306179
* Is tracing enabled
307180
*/
@@ -508,6 +381,15 @@ function xhrCallback(handlerData: { [key: string]: any }): void {
508381
description: `${xhr.method} ${xhr.url}`,
509382
op: 'http',
510383
});
384+
385+
// Adding the trace header to the span
386+
const activity = Tracing._activities[handlerData.xhr.__sentry_xhr_activity_id__];
387+
if (activity) {
388+
const span = activity.span;
389+
if (span && handlerData.xhr.setRequestHeader) {
390+
handlerData.xhr.setRequestHeader('sentry-trace', span.toTraceparent());
391+
}
392+
}
511393
// tslint:enable: no-unsafe-any
512394
}
513395

@@ -520,22 +402,42 @@ function fetchCallback(handlerData: { [key: string]: any }): void {
520402
return;
521403
}
522404

523-
if (handlerData.endTimestamp && handlerData.__activity) {
524-
Tracing.popActivity(handlerData.__activity, handlerData.fetchData);
405+
if (!Tracing.options.shouldCreateSpanForRequest(handlerData.fetchData.url)) {
406+
return;
407+
}
408+
409+
if (handlerData.endTimestamp && handlerData.fetchData.__activity) {
410+
Tracing.popActivity(handlerData.fetchData.__activity, handlerData.fetchData);
525411
} else {
526-
handlerData.__activity = Tracing.pushActivity('fetch', {
412+
handlerData.fetchData.__activity = Tracing.pushActivity('fetch', {
527413
data: {
528414
...handlerData.fetchData,
529415
type: 'fetch',
530416
},
531417
description: `${handlerData.fetchData.method} ${handlerData.fetchData.url}`,
532418
op: 'http',
533419
});
534-
}
535420

536-
// if (handlerData.error) {
537-
// } else {
538-
// }
421+
const activity = Tracing._activities[handlerData.fetchData.__activity];
422+
if (activity) {
423+
const span = activity.span;
424+
if (span) {
425+
const options = (handlerData.args[1] = (handlerData.args[1] as { [key: string]: any }) || {});
426+
if (options.headers) {
427+
if (Array.isArray(options.headers)) {
428+
options.headers = [...options.headers, { 'sentry-trace': span.toTraceparent() }];
429+
} else {
430+
options.headers = {
431+
...options.headers,
432+
'sentry-trace': span.toTraceparent(),
433+
};
434+
}
435+
} else {
436+
options.headers = { 'sentry-trace': span.toTraceparent() };
437+
}
438+
}
439+
}
440+
}
539441
// tslint:enable: no-unsafe-any
540442
}
541443

0 commit comments

Comments
 (0)