Skip to content
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

XHR instrumentation experimental package #239

Merged
merged 25 commits into from
Sep 19, 2023
Merged

Conversation

eskirk
Copy link
Collaborator

@eskirk eskirk commented Jul 31, 2023

Description

Adds the XHR (XMLHttpRequest) auto-instrumentation to the experimental package

Checklist

  • Tests added
  • Changelog updated
  • Documentation updated

@eskirk eskirk marked this pull request as ready for review September 13, 2023 20:50
return [
new DocumentLoadInstrumentation(),
new FetchInstrumentation(options),
new XMLHttpRequestInstrumentation(options),
// new FetchInstrumentation(options),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Which instrumentations (Faro vs Otel) to use is up to the user and they should not be disabled by defult.

For example you can autodetect if Faros' Fetch and Session Instrumentation are added and then disable the OTel instrumentations.

You can iterate over the instrumentation and look up for the respectiv instrumentation names, e. g. instrumentation.name === '@grafana/faro-web-sdk:instrumentation-fetch';

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also have quite users using the Web-Tracing package.
So this will be a breaking change and we need to communicate this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this - this was a testing change that slipped through.

The suggestion to filter out instrumentations is perfect, I will implement that. Thanks for the suggestion.

experimental/instrumentation-xhr/tsconfig.json Outdated Show resolved Hide resolved
experimental/instrumentation-xhr/src/types.ts Outdated Show resolved Hide resolved
/**
* XMLHttpRequest.prototype.open becomes instrumented and the parameter defaults are properly passed to the original function
*/
XMLHttpRequest.prototype.open = function (
Copy link
Collaborator

@codecapitano codecapitano Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: move the respective init code in a separate function each. May be a bit more readable and we wouldn't need the comments anymore.

initialize(): void {
this.internalLogger.info('Initializing XHR instrumentation');
this.ignoredUrls = this.options?.ignoredUrls ?? this.getTransportIgnoreUrls();
const instrumentation = this;
Copy link
Collaborator

@codecapitano codecapitano Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Why do you need to cache the this value of the class?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this in the instrumentation class differs from this inside the scope of the XHRHttpRequest(I am pretty sure, at least)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah of course, we are in class so you need the this keyword to get the function.

Copy link
Collaborator

@codecapitano codecapitano Sep 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you also can do is making originalOpen open static but I am not sure if this has any big advantages to your solution with caching the this value.
Only want to add it for completeness :)

static readonly originalOpen: XMLHttpRequest['open'] = XMLHttpRequest.prototype.open;

\\ ...


return XHRInstrumentation.originalOpen.apply(this, [..])

// @ts-expect-error - _url is attached to the xhr object
xhr._url = url;

return instrumentation.originalOpen?.apply(xhr, [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

originalOpen is in the outer scope so originalOpen.appy should work fine.

Copy link
Collaborator

@codecapitano codecapitano Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Why do we need the optional chainign operator?
In what cases will originalOpen be null | undefined?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for the optional chaining operator, good catch. But my editor complains if I remove instrumentation.

* Parse the input object into a string URL
*/
getRequestUrl(input: string | URL): string {
return input instanceof URL ? input.href : String(input);
Copy link
Collaborator

@codecapitano codecapitano Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Why do we need to call the String() constructor if input is already a string in the 'else' case?

XMLHttpRequest.prototype.send = function (body?: Document | XMLHttpRequestBodyInit | null | undefined): void {
const xhr = this;
// @ts-expect-error - _url is attached to the xhr object
const requestUrl = xhr._url;
Copy link
Collaborator

@codecapitano codecapitano Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Do we need that constant? Why not use xhr._url directly? getRequestUrl(xhr._url)

import { XHRInstrumentation } from '@grafana/faro-instrumentation-xhr';
import { getWebInstrumentations, initializeFaro } from '@grafana/faro-react';

initializeFaro({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: explain the availbale options too.

Copy link
Collaborator

@codecapitano codecapitano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only some little things and a few suggestions or questions.

Copy link
Collaborator

@codecapitano codecapitano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few questions and suggestions

Copy link
Collaborator

@codecapitano codecapitano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🦖

@eskirk eskirk merged commit b1bfff4 into main Sep 19, 2023
@eskirk eskirk deleted the elliot/instrumentation-xhr branch September 19, 2023 16:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants