-
Notifications
You must be signed in to change notification settings - Fork 1k
XMLHttpRequest #595
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
XMLHttpRequest #595
Changes from 2 commits
8fce91a
0875f3f
f1c6013
6038bcc
ac68ab9
87dcdc6
6e10df7
e91d8f9
8e01e96
898c190
54d0ba0
9f2c563
8a17c2a
db00221
ef66398
7d884db
3e39b1a
bcc1204
c9163e5
f73aacb
88e122a
c3dac11
524da7a
50e151e
6c143e7
3d7b32e
91bad5d
5aa23ca
ab9795a
4d4e65f
ca96cb1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -35,18 +35,18 @@ import { EventNames } from './enums/EventNames'; | |||||
| import { Format } from './enums/Format'; | ||||||
| import { | ||||||
| OpenFunction, | ||||||
| PropagateTraceHeaderUrls, | ||||||
| PropagateTraceHeaderCorsUrls, | ||||||
| SendBody, | ||||||
| SendFunction, | ||||||
| XMLHttpRequestWrapped, | ||||||
| XhrMem, | ||||||
| } from './types'; | ||||||
|
|
||||||
| /** | ||||||
| * XMLHttpRequest config | ||||||
| */ | ||||||
| export interface XMLHttpRequestPluginConfig extends types.PluginConfig { | ||||||
| // urls which should include trace headers when origin doesn't match | ||||||
| propagateTraceHeaderUrls?: PropagateTraceHeaderUrls; | ||||||
| propagateTraceHeaderCorsUrls?: PropagateTraceHeaderCorsUrls; | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
|
|
@@ -61,16 +61,7 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> { | |||||
| protected _config!: XMLHttpRequestPluginConfig; | ||||||
|
|
||||||
| private _tasksCount = 0; | ||||||
| private _callbackToRemoveEvents: { [key: string]: Function } = {}; | ||||||
| private _spans: { [key: string]: tracing.Span } = {}; | ||||||
| // resources created between send and end - possible candidates for | ||||||
| // cors preflight requests | ||||||
| private _resourcesCreatedInTheMiddle: { | ||||||
| [key: string]: { | ||||||
| observer: PerformanceObserver; | ||||||
| entries: PerformanceResourceTiming[]; | ||||||
| }; | ||||||
| } = {}; | ||||||
| private _xhrMem = new WeakMap<XMLHttpRequest, XhrMem>(); | ||||||
| private _usedResources: { [key: string]: PerformanceResourceTiming[] } = {}; | ||||||
obecny marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
obecny marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| constructor(config: XMLHttpRequestPluginConfig = {}) { | ||||||
|
|
@@ -85,7 +76,8 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> { | |||||
| * @private | ||||||
| */ | ||||||
| private _addHeaders(xhr: XMLHttpRequest, span: types.Span) { | ||||||
| let propagateTraceHeaderUrls = this._config.propagateTraceHeaderUrls || []; | ||||||
| let propagateTraceHeaderUrls = | ||||||
| this._config.propagateTraceHeaderCorsUrls || []; | ||||||
| if ( | ||||||
| typeof propagateTraceHeaderUrls === 'string' || | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we have this logic handled by the utility function for matching strings? |
||||||
| propagateTraceHeaderUrls instanceof RegExp | ||||||
|
|
@@ -155,29 +147,35 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> { | |||||
| /** | ||||||
| * will collect information about all resources created | ||||||
| * between "send" and "end" | ||||||
| * @param spanId | ||||||
| * @param xhr | ||||||
| * @param spanName | ||||||
| * @private | ||||||
| */ | ||||||
| private _addPossibleCorsPreflightResourceObserver( | ||||||
| spanId: string, | ||||||
| xhr: XMLHttpRequest, | ||||||
| spanName: string | ||||||
| ) { | ||||||
| this._resourcesCreatedInTheMiddle[spanId] = { | ||||||
| const xhrMem = this._xhrMem.get(xhr); | ||||||
| if (!xhrMem) { | ||||||
| return; | ||||||
| } | ||||||
| xhrMem.resourcesCreatedInTheMiddle = { | ||||||
| observer: new PerformanceObserver(list => { | ||||||
| const entries = list.getEntries() as PerformanceResourceTiming[]; | ||||||
| entries.forEach(entry => { | ||||||
| if ( | ||||||
| entry.initiatorType === 'xmlhttprequest' && | ||||||
| entry.name === spanName | ||||||
| ) { | ||||||
| this._resourcesCreatedInTheMiddle[spanId].entries.push(entry); | ||||||
| if (xhrMem.resourcesCreatedInTheMiddle) { | ||||||
| xhrMem.resourcesCreatedInTheMiddle.entries.push(entry); | ||||||
| } | ||||||
| } | ||||||
| }); | ||||||
| }), | ||||||
| entries: [], | ||||||
| }; | ||||||
| this._resourcesCreatedInTheMiddle[spanId].observer.observe({ | ||||||
| xhrMem.resourcesCreatedInTheMiddle.observer.observe({ | ||||||
| entryTypes: ['resource'], | ||||||
| }); | ||||||
| } | ||||||
|
|
@@ -189,9 +187,7 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> { | |||||
| private _clearResources() { | ||||||
| if (this._tasksCount === 0) { | ||||||
| ((otperformance as unknown) as Performance).clearResourceTimings(); | ||||||
| this._callbackToRemoveEvents = {}; | ||||||
| this._resourcesCreatedInTheMiddle = {}; | ||||||
| this._spans = {}; | ||||||
| this._xhrMem = new WeakMap<XMLHttpRequest, XhrMem>(); | ||||||
obecny marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| this._usedResources = {}; | ||||||
| } | ||||||
| } | ||||||
|
|
@@ -235,12 +231,10 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> { | |||||
| * @param xhr | ||||||
| * @private | ||||||
| */ | ||||||
| private _cleanPreviousSpanInformation(xhr: XMLHttpRequestWrapped) { | ||||||
| const existingSpanId = xhr.__OT_SPAN_ID; | ||||||
| if (existingSpanId) { | ||||||
| const callbackToRemoveEvents = this._callbackToRemoveEvents[ | ||||||
| existingSpanId | ||||||
| ]; | ||||||
| private _cleanPreviousSpanInformation(xhr: XMLHttpRequest) { | ||||||
| const xhrMem = this._xhrMem.get(xhr); | ||||||
| if (xhrMem) { | ||||||
| const callbackToRemoveEvents = xhrMem.callbackToRemoveEvents; | ||||||
| if (callbackToRemoveEvents) { | ||||||
| callbackToRemoveEvents(); | ||||||
| } | ||||||
|
|
@@ -255,7 +249,7 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> { | |||||
| * @private | ||||||
| */ | ||||||
| private _createSpan( | ||||||
| xhr: XMLHttpRequestWrapped, | ||||||
| xhr: XMLHttpRequest, | ||||||
| url: string, | ||||||
| method: string | ||||||
| ): tracing.Span | undefined { | ||||||
|
|
@@ -275,11 +269,11 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> { | |||||
|
|
||||||
| currentSpan.addEvent(EventNames.METHOD_OPEN); | ||||||
|
|
||||||
| const spanId = currentSpan.context().spanId; | ||||||
| this._spans[spanId] = currentSpan; | ||||||
| this._xhrMem.set(xhr, { | ||||||
| span: currentSpan, | ||||||
| }); | ||||||
|
|
||||||
| this._cleanPreviousSpanInformation(xhr); | ||||||
| xhr.__OT_SPAN_ID = spanId; | ||||||
|
|
||||||
| return currentSpan; | ||||||
| } | ||||||
|
|
@@ -314,7 +308,7 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> { | |||||
| user?: string | null, | ||||||
| pass?: string | null | ||||||
| ): void { | ||||||
| plugin._createSpan(this as XMLHttpRequestWrapped, url, method); | ||||||
| plugin._createSpan(this as XMLHttpRequest, url, method); | ||||||
|
|
||||||
| return original.call(this, method, url, true, user, pass); | ||||||
|
||||||
| }; | ||||||
|
|
@@ -328,24 +322,23 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> { | |||||
| protected _patchSend() { | ||||||
| const plugin = this; | ||||||
|
|
||||||
| function endSpan(xhr: XMLHttpRequestWrapped, eventName: string) { | ||||||
| const spanId = xhr.__OT_SPAN_ID; | ||||||
| const callbackToRemoveEvents = spanId | ||||||
| ? plugin._callbackToRemoveEvents[spanId] | ||||||
| : undefined; | ||||||
| function endSpan(xhr: XMLHttpRequest, eventName: string) { | ||||||
| const xhrMem = plugin._xhrMem.get(xhr); | ||||||
| if (!xhrMem) { | ||||||
| return; | ||||||
| } | ||||||
| const callbackToRemoveEvents = xhrMem.callbackToRemoveEvents; | ||||||
|
|
||||||
| let resourcesCreatedInTheMiddle = spanId | ||||||
| ? plugin._resourcesCreatedInTheMiddle[spanId] | ||||||
| : undefined; | ||||||
| let resourcesCreatedInTheMiddle = xhrMem.resourcesCreatedInTheMiddle; | ||||||
| let entries; | ||||||
| if (resourcesCreatedInTheMiddle) { | ||||||
| entries = resourcesCreatedInTheMiddle.entries.slice(); | ||||||
| } | ||||||
| if (typeof callbackToRemoveEvents === 'function') { | ||||||
| callbackToRemoveEvents(); | ||||||
| } | ||||||
| const currentSpan = spanId ? plugin._spans[spanId] : undefined; | ||||||
| if (currentSpan && spanId) { | ||||||
| const currentSpan = xhrMem.span; | ||||||
| if (currentSpan) { | ||||||
| plugin._findResourceAndAddNetworkEvents(currentSpan, entries); | ||||||
| currentSpan.addEvent(eventName); | ||||||
|
|
||||||
|
|
@@ -378,38 +371,41 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> { | |||||
| plugin._clearResources(); | ||||||
| } | ||||||
|
|
||||||
| function onError(this: XMLHttpRequestWrapped) { | ||||||
| function onError(this: XMLHttpRequest) { | ||||||
| endSpan(this, EventNames.EVENT_ERROR); | ||||||
| } | ||||||
|
|
||||||
| function onTimeout(this: XMLHttpRequestWrapped) { | ||||||
| function onTimeout(this: XMLHttpRequest) { | ||||||
| endSpan(this, EventNames.EVENT_TIMEOUT); | ||||||
| } | ||||||
|
|
||||||
| function onLoad(this: XMLHttpRequestWrapped) { | ||||||
| function onLoad(this: XMLHttpRequest) { | ||||||
| if (this.status < 299) { | ||||||
| endSpan(this, EventNames.EVENT_LOAD); | ||||||
| } else { | ||||||
| endSpan(this, EventNames.EVENT_ERROR); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| function unregister(xhr: XMLHttpRequestWrapped, spanId: string) { | ||||||
| function unregister(xhr: XMLHttpRequest) { | ||||||
| xhr.removeEventListener('load', onLoad); | ||||||
| xhr.removeEventListener('error', onError); | ||||||
| xhr.removeEventListener('timeout', onTimeout); | ||||||
| delete plugin._callbackToRemoveEvents[spanId]; | ||||||
| delete xhr.__OT_SPAN_ID; | ||||||
| const xhrMem = plugin._xhrMem.get(xhr); | ||||||
| if (xhrMem) { | ||||||
| delete xhrMem.callbackToRemoveEvents; | ||||||
obecny marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| } | ||||||
| } | ||||||
|
|
||||||
| return (original: SendFunction): SendFunction => { | ||||||
obecny marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| return function patchSend(this: XMLHttpRequest, body?: SendBody): void { | ||||||
| const spanId = (this as XMLHttpRequestWrapped).__OT_SPAN_ID; | ||||||
| const currentSpan: types.Span | undefined = spanId | ||||||
| ? plugin._spans[spanId] | ||||||
| : undefined; | ||||||
| const xhrMem = plugin._xhrMem.get(this); | ||||||
| if (!xhrMem) { | ||||||
| return; | ||||||
dyladan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| } | ||||||
| const currentSpan: types.Span = xhrMem.span; | ||||||
|
|
||||||
| if (currentSpan && spanId) { | ||||||
| if (currentSpan) { | ||||||
| plugin._tasksCount++; | ||||||
| currentSpan.addEvent(EventNames.METHOD_SEND); | ||||||
| const spanName = (currentSpan as tracing.Span).name; | ||||||
|
|
@@ -418,14 +414,15 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> { | |||||
| this.addEventListener('error', onError); | ||||||
| this.addEventListener('timeout', onTimeout); | ||||||
|
|
||||||
| plugin._callbackToRemoveEvents[spanId] = () => { | ||||||
| unregister(this as XMLHttpRequestWrapped, spanId); | ||||||
| plugin._resourcesCreatedInTheMiddle[spanId].observer.disconnect(); | ||||||
| delete plugin._resourcesCreatedInTheMiddle[spanId]; | ||||||
| xhrMem.callbackToRemoveEvents = () => { | ||||||
| unregister(this); | ||||||
| if (xhrMem.resourcesCreatedInTheMiddle) { | ||||||
| xhrMem.resourcesCreatedInTheMiddle.observer.disconnect(); | ||||||
| delete xhrMem.resourcesCreatedInTheMiddle; | ||||||
| } | ||||||
| }; | ||||||
| plugin._addHeaders(this, currentSpan); | ||||||
|
|
||||||
| plugin._addPossibleCorsPreflightResourceObserver(spanId, spanName); | ||||||
| plugin._addPossibleCorsPreflightResourceObserver(this, spanName); | ||||||
| } | ||||||
| return original.call(this, body); | ||||||
|
||||||
| return original.call(this, body); | |
| return original.apply(this, arguments); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- call is faster
- we already know there is just one para, we know it's type so we can use it and typescript will also validate the type of this is correcty
- You don't have
argumentsword in typescript , so you would still declare array of aguments and define type for it, which would be quite weird anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and the same here, thx
@draffensperger @mayurkale22 ^^
Uh oh!
There was an error while loading. Please reload this page.