Skip to content

Commit

Permalink
XMLHttpRequest (open-telemetry#595)
Browse files Browse the repository at this point in the history
* feat(xml-http-request): new plugin for auto instrumentation for xml-http-request

* chore: new example for xml-http-request and updated examples structure for web

* chore: updating readme

* chore: linting

* chore: fixing origin for tests

* chore: linting

* chore: updating to use b3 format from core

* chore: updates after reviews

* chore: wrong function call

* chore: updating attribute names

* chore: linting

* chore: adding preflight requests, fixing few other issues

* chore: adding image to examples, updating readme

* chore: forcing async to be true, but propagate rest params

* chore: fixing type for open and send function

* chore: fixing format for headers

* chore: reviews

* chore: decrement task count when span exists

* chore: changes after review

* chore: adding weakmap for keeping information connected with xhr

* chore: renaming config param

* chore: not needed cast

* chore: updating title

* chore: refactored xhr, removed tracing dependency, few other issues fixed

* chore: reviews

* chore: refactored for collecting timing resources

* chore: fixes after merging

* chore: reviews

* chore: reviews

Co-authored-by: Mayur Kale <[email protected]>
  • Loading branch information
obecny and mayurkale22 committed Dec 19, 2019
1 parent e8db33a commit bc583b8
Show file tree
Hide file tree
Showing 42 changed files with 2,701 additions and 74 deletions.
19 changes: 15 additions & 4 deletions examples/tracer-web/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Overview

This example shows how to use [@opentelemetry/web](https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-web) to instrument your JavaScript code running in the browser.
This example uses the `ConsoleSpanExporter()` to export spans to the browser console output.
This example shows how to use [@opentelemetry/web](https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-web) with different plugins and setup to instrument your JavaScript code running in the browser.

## Installation

Expand All @@ -19,11 +18,23 @@ $ npm start

By default, the application will run on port `8090`.

To see the results, open the browser at <http://localhost:8090/> and make sure you have the browser console open. The application is using the `ConsoleSpanExporter` and will post the created spans to the browser console.
## Examples

### Document Load

To see the results, open the browser at <http://localhost:8090/document-load/> and make sure you have the browser console open. The application is using the `ConsoleSpanExporter` and will post the created spans to the browser console.

The screen will look as follows:

![Screenshot of the running example](images/traces.png)
![Screenshot of the running example](images/document-load.png)

### XMLHttpRequest

To see the results, open the browser at <http://localhost:8090/xml-http-request/> and make sure you have the browser console open. The application is using the `ConsoleSpanExporter` and will post the created spans to the browser console.
The screen will look as follows:

![Screenshot of the running example](images/xml-http-request.png)


## Useful links

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<head>
<meta charset="utf-8">
<title>Web Tracer Example</title>
<title>Document Load Plugin Example</title>
<base href="/">

<!--
Expand All @@ -22,7 +22,7 @@

<body>
Example of using Web Tracer with document load plugin with console exporter and collector exporter
<script type="text/javascript" src="/bundle.js"></script>
<script type="text/javascript" src="document-load.js"></script>
<br/>
<button id="button1">Test WebTracer with ZoneScopeManager - async</button>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,4 @@ const getData = (url) => {
});
};

window.addEventListener('load', () => {
prepareClickEvent();
});
window.addEventListener('load', prepareClickEvent);
20 changes: 20 additions & 0 deletions examples/tracer-web/examples/xml-http-request/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<title>XMLHttpRequest Plugin Example</title>
<base href="/">

<meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
Example of using Web Tracer with XMLHttpRequest plugin with console exporter and collector exporter
<script type="text/javascript" src="xml-http-request.js"></script>
<br/>
<button id="button1">Test</button>

</body>

</html>
61 changes: 61 additions & 0 deletions examples/tracer-web/examples/xml-http-request/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use strict';

import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing';
import { WebTracer } from '@opentelemetry/web';
import { XMLHttpRequestPlugin } from '@opentelemetry/plugin-xml-http-request';
import { ZoneScopeManager } from '@opentelemetry/scope-zone';
import { CollectorExporter } from '@opentelemetry/exporter-collector';
import { B3Format } from '@opentelemetry/core';

const webTracerWithZone = new WebTracer({
httpTextFormat: new B3Format(),
scopeManager: new ZoneScopeManager(),
plugins: [
new XMLHttpRequestPlugin({
ignoreUrls: [/localhost:8090\/sockjs-node/],
propagateTraceHeaderCorsUrls: [
'https://httpbin.org/get'
]
})
]
});

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

// example of keeping track of scope between async operations
const prepareClickEvent = () => {
const url1 = 'https://httpbin.org/get';

const element = document.getElementById('button1');

const onClick = () => {
for (let i = 0, j = 5; i < j; i++) {
const span1 = webTracerWithZone.startSpan(`files-series-info-${i}`, {
parent: webTracerWithZone.getCurrentSpan()
});
webTracerWithZone.withSpan(span1, () => {
getData(url1).then((data) => {
webTracerWithZone.getCurrentSpan().addEvent('fetching-span1-completed');
span1.end();
});
});
}
};
element.addEventListener('click', onClick);
};

const getData = (url) => {
return new Promise(async (resolve, reject) => {
const req = new XMLHttpRequest();
req.open('GET', url, true);
req.setRequestHeader('Content-Type', 'application/json');
req.setRequestHeader('Accept', 'application/json');
req.send();
req.onload = function () {
resolve();
};
});
};

window.addEventListener('load', prepareClickEvent);
File renamed without changes
Binary file added examples/tracer-web/images/xml-http-request.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion examples/tracer-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "Example of using @opentelemetry/web in browser",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server -d --progress --colors --port 8090 --config webpack.config.js --hot --inline --host 0.0.0.0"
"start": "webpack-dev-server -d --progress --colors --port 8090 --config webpack.config.js --hot --inline --host 0.0.0.0 --content-base examples"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -36,6 +36,7 @@
"dependencies": {
"@opentelemetry/exporter-collector": "^0.3.0",
"@opentelemetry/plugin-document-load": "^0.3.0",
"@opentelemetry/plugin-xml-http-request": "^0.3.0",
"@opentelemetry/scope-zone": "^0.3.0",
"@opentelemetry/tracing": "^0.3.0",
"@opentelemetry/web": "^0.3.0"
Expand Down
18 changes: 10 additions & 8 deletions examples/tracer-web/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const path = require('path');
const mainPath = path.resolve('');
const directory = path.resolve(__dirname);

const common = {
mode: 'development',
entry: 'index.js',
entry: {
'document-load': 'examples/document-load/index.js',
'xml-http-request': 'examples/xml-http-request/index.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
sourceMapFilename: '[file].map'
},
target: 'web',
module: {
rules: [
Expand All @@ -28,7 +35,6 @@ const common = {
},
resolve: {
modules: [
path.resolve(mainPath, 'src'),
path.resolve(directory),
'node_modules'
],
Expand All @@ -38,12 +44,8 @@ const common = {

module.exports = webpackMerge(common, {
devtool: 'eval-source-map',
output: {
filename: 'bundle.js',
sourceMapFilename: '[file].map'
},
devServer: {
contentBase: path.resolve(__dirname),
contentBase: path.resolve(__dirname)
},
plugins: [
new webpack.DefinePlugin({
Expand Down
10 changes: 10 additions & 0 deletions packages/opentelemetry-core/src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,13 @@ export interface TimeOriginLegacy {
fetchStart: number;
};
}

/**
* This interface defines the params that are be added to the wrapped function
* using the "shimmer.wrap"
*/
export interface ShimWrapped {
__wrapped: boolean;
__unwrap: Function;
__original: Function;
}
2 changes: 2 additions & 0 deletions packages/opentelemetry-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ export * from './trace/spancontext-utils';
export * from './trace/TracerDelegate';
export * from './trace/TraceState';
export * from './metrics/NoopMeter';
export * from './utils/url';
export * from './utils/wrap';
48 changes: 48 additions & 0 deletions packages/opentelemetry-core/src/utils/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*!
* Copyright 2019, OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Check if {@param url} matches {@param urlToMatch}
* @param url
* @param urlToMatch
*/
export function urlMatches(url: string, urlToMatch: string | RegExp): boolean {
if (typeof urlToMatch === 'string') {
return url === urlToMatch;
} else {
return !!url.match(urlToMatch);
}
}
/**
* Check if {@param url} should be ignored when comparing against {@param ignoredUrls}
* @param url
* @param ignoredUrls
*/
export function isUrlIgnored(
url: string,
ignoredUrls?: Array<string | RegExp>
): boolean {
if (!ignoredUrls) {
return false;
}

for (const ignoreUrl of ignoredUrls) {
if (urlMatches(url, ignoreUrl)) {
return true;
}
}
return false;
}
30 changes: 30 additions & 0 deletions packages/opentelemetry-core/src/utils/wrap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*!
* Copyright 2019, OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { ShimWrapped } from '../common/types';

/**
* Checks if certain function has been already wrapped
* @param func
*/
export function isWrapped(func: any) {
return (
typeof func === 'function' &&
typeof (func as ShimWrapped).__original === 'function' &&
typeof (func as ShimWrapped).__unwrap === 'function' &&
(func as ShimWrapped).__wrapped === true
);
}
75 changes: 75 additions & 0 deletions packages/opentelemetry-core/test/utils/url.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* Copyright 2019, OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as assert from 'assert';

import { isUrlIgnored } from '../../src';

const urlIgnored = 'url should be ignored';
const urlNotIgnored = 'url should NOT be ignored';

const urlToTest = 'http://myaddress.com/somepath';

describe('BasePlugin - Utils', () => {
describe('isUrlIgnored', () => {
describe('when ignored urls are undefined', () => {
it('should return false', () => {
assert.strictEqual(isUrlIgnored(urlToTest), false, urlNotIgnored);
});
});
describe('when ignored urls are empty', () => {
it('should return false', () => {
assert.strictEqual(isUrlIgnored(urlToTest, []), false, urlNotIgnored);
});
});
describe('when ignored urls is the same as url', () => {
it('should return true', () => {
assert.strictEqual(
isUrlIgnored(urlToTest, ['http://myaddress.com/somepath']),
true,
urlIgnored
);
});
});
describe('when url is part of ignored urls', () => {
it('should return false', () => {
assert.strictEqual(
isUrlIgnored(urlToTest, ['http://myaddress.com/some']),
false,
urlNotIgnored
);
});
});
describe('when ignored urls is part of url - REGEXP', () => {
it('should return true', () => {
assert.strictEqual(
isUrlIgnored(urlToTest, [/.+?myaddress\.com/]),
true,
urlIgnored
);
});
});
describe('when url is part of ignored urls - REGEXP', () => {
it('should return false', () => {
assert.strictEqual(
isUrlIgnored(urlToTest, [/http:\/\/myaddress\.com\/somepath2/]),
false,
urlNotIgnored
);
});
});
});
});
Loading

0 comments on commit bc583b8

Please sign in to comment.