Skip to content

Commit

Permalink
feat: replacing base plugin with instrumentation for xml-http-request (
Browse files Browse the repository at this point in the history
…#1659)

* feat: replacing base plugin with instrumentation for xml-http-request

* feat: fixing import and checking for instrumentation based on function instead of instance
  • Loading branch information
obecny authored Nov 10, 2020
1 parent b703f9f commit 97736be
Show file tree
Hide file tree
Showing 33 changed files with 132 additions and 80 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ cache_2: &cache_2
- packages/opentelemetry-plugin-http/node_modules
- packages/opentelemetry-plugin-https/node_modules
- packages/opentelemetry-exporter-collector/node_modules
- packages/opentelemetry-plugin-xml-http-request/node_modules
- packages/opentelemetry-instrumentation-xml-http-request/node_modules
- packages/opentelemetry-resource-detector-aws/node_modules
- packages/opentelemetry-resource-detector-gcp/node_modules
- packages/opentelemetry-resources/node_modules
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ These plugins are hosted at <https://github.com/open-telemetry/opentelemetry-js-

##### Core

- [@opentelemetry/plugin-xml-http-request][otel-plugin-xml-http-request]
- [@opentelemetry/instrumentation-xml-http-request][otel-instrumentation-xml-http-request]
- [@opentelemetry/plugin-fetch][otel-plugin-fetch]

##### Contrib
Expand Down Expand Up @@ -248,7 +248,7 @@ Apache 2.0 - See [LICENSE][license-url] for more information.
[otel-plugin-grpc-js]: https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-plugin-grpc-js
[otel-plugin-http]: https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-plugin-http
[otel-plugin-https]: https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-plugin-https
[otel-plugin-xml-http-request]: https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-plugin-xml-http-request
[otel-instrumentation-xml-http-request]: https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-instrumentation-xml-http-request

[otel-shim-opentracing]: https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-shim-opentracing
[otel-tracing]: https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-tracing
Expand Down
2 changes: 1 addition & 1 deletion examples/tracer-web/examples/user-interaction/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</head>

<body>
Example of using Web Tracer with UserInteractionPlugin and XMLHttpRequestPlugin with console exporter and collector exporter
Example of using Web Tracer with UserInteractionPlugin and XMLHttpRequestInstrumentation with console exporter and collector exporter
<script type="text/javascript" src="user-interaction.js"></script>
<br/>
<button id="btnAdd" class="btnAddClass">Add button</button>
Expand Down
4 changes: 2 additions & 2 deletions examples/tracer-web/examples/user-interaction/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing';
import { WebTracerProvider } from '@opentelemetry/web';
import { XMLHttpRequestPlugin } from '@opentelemetry/plugin-xml-http-request';
import { UserInteractionPlugin } from '@opentelemetry/plugin-user-interaction';
import { ZoneContextManager } from '@opentelemetry/context-zone';
import { CollectorTraceExporter } from '@opentelemetry/exporter-collector';
import { B3Propagator } from '@opentelemetry/propagator-b3';
import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';

const providerWithZone = new WebTracerProvider({
plugins: [
new UserInteractionPlugin(),
new XMLHttpRequestPlugin({
new XMLHttpRequestInstrumentation({
ignoreUrls: [/localhost/],
propagateTraceHeaderCorsUrls: [
'http://localhost:8090',
Expand Down
4 changes: 2 additions & 2 deletions examples/tracer-web/examples/xml-http-request/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing';
import { WebTracerProvider } from '@opentelemetry/web';
import { XMLHttpRequestPlugin } from '@opentelemetry/plugin-xml-http-request';
import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';
import { ZoneContextManager } from '@opentelemetry/context-zone';
import { CollectorTraceExporter } from '@opentelemetry/exporter-collector';
import { B3Propagator } from '@opentelemetry/propagator-b3';

const providerWithZone = new WebTracerProvider({
plugins: [
new XMLHttpRequestPlugin({
new XMLHttpRequestInstrumentation({
ignoreUrls: [/localhost:8090\/sockjs-node/],
propagateTraceHeaderCorsUrls: [
'https://httpbin.org/get',
Expand Down
2 changes: 1 addition & 1 deletion examples/tracer-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"@opentelemetry/plugin-document-load": "^0.9.0",
"@opentelemetry/plugin-fetch": "^0.12.0",
"@opentelemetry/plugin-user-interaction": "^0.9.0",
"@opentelemetry/plugin-xml-http-request": "^0.12.0",
"@opentelemetry/instrumentation-xml-http-request": "^0.12.0",
"@opentelemetry/tracing": "^0.12.0",
"@opentelemetry/web": "^0.12.0"
},
Expand Down
4 changes: 2 additions & 2 deletions metapackages/plugins-web-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This package depends on all core web plugins maintained by OpenTelemetry authors

## Plugins

- [@opentelemetry/plugin-xml-http-request][otel-plugin-xml-http-request]
- [@opentelemetry/instrumentation-xml-http-request][otel-instrumentation-xml-http-request]

## Useful links

Expand All @@ -30,4 +30,4 @@ Apache 2.0 - See [LICENSE][license-url] for more information.
[npm-url]: https://www.npmjs.com/package/@opentelemetry/plugins-web-core
[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fplugins-web-core.svg

[otel-plugin-xml-http-request]: https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-plugin-xml-http-request
[otel-instrumentation-xml-http-request]: https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-instrumentation-xml-http-request
2 changes: 1 addition & 1 deletion metapackages/plugins-web-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
"url": "https://github.com/open-telemetry/opentelemetry-js/issues"
},
"dependencies": {
"@opentelemetry/plugin-xml-http-request": "^0.12.0"
"@opentelemetry/instrumentation-xml-http-request": "^0.12.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,38 @@ This module provides auto instrumentation for web using XMLHttpRequest .
## Installation

```bash
npm install --save @opentelemetry/plugin-xml-http-request
npm install --save @opentelemetry/instrumentation-xml-http-request
```

## Usage

```js
import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing';
import { WebTracer } from '@opentelemetry/web';
import { XMLHttpRequestPlugin } from '@opentelemetry/plugin-xml-http-request';
import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';
import { ZoneContextManager } from '@opentelemetry/context-zone';

// this is still possible
const webTracerWithZone = new WebTracer({
contextManager: new ZoneContextManager(),
plugins: [
new XMLHttpRequestPlugin({
new XMLHttpRequestInstrumentation({
propagateTraceHeaderCorsUrls: ['http://localhost:8090']
})
]
});
/////////////////////////////////////////

// or plugin can be also initialised separately and then set the tracer provider or meter provider
const xmlHttpRequestInstrumentation = new XMLHttpRequestInstrumentation({
propagateTraceHeaderCorsUrls: ['http://localhost:8090']
});
const webTracerWithZone = new WebTracer({
contextManager: new ZoneContextManager(),
});
xmlHttpRequestInstrumentation.setTracerProvider(webTracerWithZone);
/////////////////////////////////////////

webTracerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));

// and some test
Expand Down Expand Up @@ -61,9 +74,9 @@ Apache 2.0 - See [LICENSE][license-url] for more information.
[gitter-url]: https://gitter.im/open-telemetry/opentelemetry-node?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/master/LICENSE
[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/status.svg?path=packages/opentelemetry-plugin-xml-http-request
[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-plugin-xml-http-request
[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/dev-status.svg?path=packages/opentelemetry-plugin-xml-http-request
[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-plugin-xml-http-request&type=dev
[npm-url]: https://www.npmjs.com/package/@opentelemetry/plugin-xml-http-request
[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fplugin-xml-http-request.svg
[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/status.svg?path=packages/opentelemetry-instrumentation-xml-http-request
[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-instrumentation-xml-http-request
[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/dev-status.svg?path=packages/opentelemetry-instrumentation-xml-http-request
[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-instrumentation-xml-http-request&type=dev
[npm-url]: https://www.npmjs.com/package/@opentelemetry/instrumentation-xml-http-request
[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Finstrumentation-xml-http-request.svg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@opentelemetry/plugin-xml-http-request",
"name": "@opentelemetry/instrumentation-xml-http-request",
"version": "0.12.0",
"description": "OpenTelemetry XMLHttpRequest automatic instrumentation package.",
"main": "build/src/index.js",
Expand Down Expand Up @@ -50,7 +50,6 @@
"@opentelemetry/tracing": "^0.12.0",
"@types/mocha": "8.0.2",
"@types/node": "14.0.27",
"@types/shimmer": "1.0.1",
"@types/sinon": "9.0.4",
"@types/webpack-env": "1.15.2",
"babel-loader": "8.1.0",
Expand All @@ -77,9 +76,9 @@
},
"dependencies": {
"@opentelemetry/api": "^0.12.0",
"@opentelemetry/instrumentation": "^0.12.0",
"@opentelemetry/core": "^0.12.0",
"@opentelemetry/semantic-conventions": "^0.12.0",
"@opentelemetry/web": "^0.12.0",
"shimmer": "^1.2.1"
"@opentelemetry/web": "^0.12.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@

import * as api from '@opentelemetry/api';
import {
BasePlugin,
hrTime,
isUrlIgnored,
isWrapped,
otperformance,
} from '@opentelemetry/core';
InstrumentationBase,
InstrumentationConfig,
} from '@opentelemetry/instrumentation';
import { hrTime, isUrlIgnored, otperformance } from '@opentelemetry/core';
import { HttpAttribute } from '@opentelemetry/semantic-conventions';
import {
addSpanNetworkEvents,
Expand All @@ -30,7 +29,6 @@ import {
PerformanceTimingNames as PTN,
shouldPropagateTraceHeaders,
} from '@opentelemetry/web';
import * as shimmer from 'shimmer';
import { EventNames } from './enums/EventNames';
import {
OpenFunction,
Expand All @@ -49,7 +47,8 @@ const OBSERVER_WAIT_TIME_MS = 300;
/**
* XMLHttpRequest config
*/
export interface XMLHttpRequestPluginConfig extends api.PluginConfig {
export interface XMLHttpRequestInstrumentationConfig
extends InstrumentationConfig {
// the number of timing resources is limited, after the limit
// (chrome 250, safari 150) the information is not collected anymore
// the only way to prevent that is to regularly clean the resources
Expand All @@ -58,12 +57,20 @@ export interface XMLHttpRequestPluginConfig extends api.PluginConfig {
clearTimingResources?: boolean;
// urls which should include trace headers when origin doesn't match
propagateTraceHeaderCorsUrls?: PropagateTraceHeaderCorsUrls;
/**
* URLs that partially match any regex in ignoreUrls will not be traced.
* In addition, URLs that are _exact matches_ of strings in ignoreUrls will
* also not be traced.
*/
ignoreUrls?: Array<string | RegExp>;
}

/**
* This class represents a XMLHttpRequest plugin for auto instrumentation
*/
export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> {
export class XMLHttpRequestInstrumentation extends InstrumentationBase<
XMLHttpRequest
> {
readonly component: string = 'xml-http-request';
readonly version: string = VERSION;
moduleName = this.component;
Expand All @@ -72,8 +79,20 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> {
private _xhrMem = new WeakMap<XMLHttpRequest, XhrMem>();
private _usedResources = new WeakSet<PerformanceResourceTiming>();

constructor(protected _config: XMLHttpRequestPluginConfig = {}) {
super('@opentelemetry/plugin-xml-http-request', VERSION);
constructor(
config: XMLHttpRequestInstrumentationConfig & InstrumentationConfig = {}
) {
super(
'@opentelemetry/instrumentation-xml-http-request',
VERSION,
Object.assign({}, config)
);
}

init() {}

private _getConfig(): XMLHttpRequestInstrumentationConfig {
return this._config;
}

/**
Expand All @@ -86,7 +105,7 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> {
if (
!shouldPropagateTraceHeaders(
spanUrl,
this._config.propagateTraceHeaderCorsUrls
this._getConfig().propagateTraceHeaderCorsUrls
)
) {
return;
Expand All @@ -108,8 +127,8 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> {
span: api.Span,
corsPreFlightRequest: PerformanceResourceTiming
): void {
this._tracer.withSpan(span, () => {
const childSpan = this._tracer.startSpan('CORS Preflight', {
this.tracer.withSpan(span, () => {
const childSpan = this.tracer.startSpan('CORS Preflight', {
startTime: corsPreFlightRequest[PTN.FETCH_START],
});
addSpanNetworkEvents(childSpan, corsPreFlightRequest);
Expand Down Expand Up @@ -177,12 +196,12 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> {

/**
* Clears the resource timings and all resources assigned with spans
* when {@link XMLHttpRequestPluginConfig.clearTimingResources} is
* when {@link XMLHttpRequestInstrumentationConfig.clearTimingResources} is
* set to true (default false)
* @private
*/
private _clearResources() {
if (this._tasksCount === 0 && this._config.clearTimingResources) {
if (this._tasksCount === 0 && this._getConfig().clearTimingResources) {
((otperformance as unknown) as Performance).clearResourceTimings();
this._xhrMem = new WeakMap<XMLHttpRequest, XhrMem>();
this._usedResources = new WeakSet<PerformanceResourceTiming>();
Expand Down Expand Up @@ -268,13 +287,13 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> {
url: string,
method: string
): api.Span | undefined {
if (isUrlIgnored(url, this._config.ignoreUrls)) {
if (isUrlIgnored(url, this._getConfig().ignoreUrls)) {
this._logger.debug('ignoring span as url matches ignored url');
return;
}
const spanName = `HTTP ${method.toUpperCase()}`;

const currentSpan = this._tracer.startSpan(spanName, {
const currentSpan = this.tracer.startSpan(spanName, {
kind: api.SpanKind.CLIENT,
attributes: {
[HttpAttribute.HTTP_METHOD]: method,
Expand Down Expand Up @@ -417,7 +436,7 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> {
const spanUrl = xhrMem.spanUrl;

if (currentSpan && spanUrl) {
plugin._tracer.withSpan(currentSpan, () => {
plugin.tracer.withSpan(currentSpan, () => {
plugin._tasksCount++;
xhrMem.sendStartTime = hrTime();
currentSpan.addEvent(EventNames.METHOD_SEND);
Expand All @@ -443,35 +462,33 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> {
}

/**
* implements patch function
* implements enable function
*/
protected patch() {
enable() {
this._logger.debug('applying patch to', this.moduleName, this.version);

if (isWrapped(XMLHttpRequest.prototype.open)) {
shimmer.unwrap(XMLHttpRequest.prototype, 'open');
this._unwrap(XMLHttpRequest.prototype, 'open');
this._logger.debug('removing previous patch from method open');
}

if (isWrapped(XMLHttpRequest.prototype.send)) {
shimmer.unwrap(XMLHttpRequest.prototype, 'send');
this._unwrap(XMLHttpRequest.prototype, 'send');
this._logger.debug('removing previous patch from method send');
}

shimmer.wrap(XMLHttpRequest.prototype, 'open', this._patchOpen());
shimmer.wrap(XMLHttpRequest.prototype, 'send', this._patchSend());

return this._moduleExports;
this._wrap(XMLHttpRequest.prototype, 'open', this._patchOpen());
this._wrap(XMLHttpRequest.prototype, 'send', this._patchSend());
}

/**
* implements unpatch function
* implements disable function
*/
protected unpatch() {
disable() {
this._logger.debug('removing patch from', this.moduleName, this.version);

shimmer.unwrap(XMLHttpRequest.prototype, 'open');
shimmer.unwrap(XMLHttpRequest.prototype, 'send');
this._unwrap(XMLHttpRequest.prototype, 'open');
this._unwrap(XMLHttpRequest.prototype, 'send');

this._tasksCount = 0;
this._xhrMem = new WeakMap<XMLHttpRequest, XhrMem>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { Span } from '@opentelemetry/api';
import { HttpAttribute } from '@opentelemetry/semantic-conventions';
import { ReadableSpan, SpanProcessor } from '@opentelemetry/tracing';
import { WebTracerProvider } from '@opentelemetry/web';
import { XMLHttpRequestPlugin } from '../src';
import { XMLHttpRequestInstrumentation } from '../src';
import assert = require('assert');

class TestSpanProcessor implements SpanProcessor {
Expand All @@ -41,7 +41,7 @@ describe('unmocked xhr', () => {
let provider: WebTracerProvider;
beforeEach(() => {
provider = new WebTracerProvider({
plugins: [new XMLHttpRequestPlugin()],
plugins: [new XMLHttpRequestInstrumentation()],
});
testSpans = new TestSpanProcessor();
provider.addSpanProcessor(testSpans);
Expand Down
Loading

0 comments on commit 97736be

Please sign in to comment.