Skip to content

Commit

Permalink
chore: refactoring zipkin to be able to use it in web (#1399)
Browse files Browse the repository at this point in the history
  • Loading branch information
obecny committed Sep 3, 2020
1 parent d8b1be8 commit a7b9e9d
Show file tree
Hide file tree
Showing 21 changed files with 652 additions and 109 deletions.
19 changes: 19 additions & 0 deletions examples/tracer-web/examples/zipkin/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<title>Zipkin Exporter Example</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
Example of using Web Tracer with Zipkin Exporter
<script type="text/javascript" src="zipkin.js"></script>
<br/>
<button id="button1">Test WebTracer with Zipkin</button>

</body>

</html>
23 changes: 23 additions & 0 deletions examples/tracer-web/examples/zipkin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing';
import { WebTracerProvider } from '@opentelemetry/web';
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';

const provider = new WebTracerProvider();
provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
provider.addSpanProcessor(new SimpleSpanProcessor(new ZipkinExporter()));

provider.register();

const tracer = provider.getTracer('example-tracer-web');

const prepareClickEvent = () => {
const element = document.getElementById('button1');

const onClick = () => {
const span = tracer.startSpan('foo');
span.end();
};
element.addEventListener('click', onClick);
};

window.addEventListener('load', prepareClickEvent);
1 change: 1 addition & 0 deletions examples/tracer-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@opentelemetry/context-zone": "^0.11.0",
"@opentelemetry/core": "^0.11.0",
"@opentelemetry/exporter-collector": "^0.11.0",
"@opentelemetry/exporter-zipkin": "^0.11.0",
"@opentelemetry/metrics": "^0.11.0",
"@opentelemetry/plugin-document-load": "^0.9.0",
"@opentelemetry/plugin-fetch": "^0.11.0",
Expand Down
1 change: 1 addition & 0 deletions examples/tracer-web/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const common = {
fetch: 'examples/fetch/index.js',
'xml-http-request': 'examples/xml-http-request/index.js',
'user-interaction': 'examples/user-interaction/index.js',
zipkin: 'examples/zipkin/index.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
Expand Down
4 changes: 3 additions & 1 deletion packages/opentelemetry-exporter-zipkin/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module.exports = {
"env": {
"mocha": true,
"node": true
"commonjs": true,
"node": true,
"browser": true
},
...require('../../eslint.config.js')
}
2 changes: 1 addition & 1 deletion packages/opentelemetry-exporter-zipkin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ OpenTelemetry Zipkin Trace Exporter allows the user to send collected traces to
npm install --save @opentelemetry/exporter-zipkin
```

## Usage
## Usage in Node and Browser

Install the exporter on your application and pass the options. `serviceName` is an optional string. If omitted, the exporter will first try to get the service name from the Resource. If no service name can be detected on the Resource, a fallback name of "OpenTelemetry Service" will be used.

Expand Down
26 changes: 26 additions & 0 deletions packages/opentelemetry-exporter-zipkin/karma.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*!
* Copyright The 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
*
* http://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.
*/

const karmaWebpackConfig = require('../../karma.webpack');
const karmaBaseConfig = require('../../karma.base');

module.exports = (config) => {
config.set(Object.assign({}, karmaBaseConfig, {
webpack: karmaWebpackConfig,
files: ['test/browser/index-webpack.ts'],
preprocessors: { 'test/browser/index-webpack.ts': ['webpack'] }
}))
};
36 changes: 30 additions & 6 deletions packages/opentelemetry-exporter-zipkin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,29 @@
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
"repository": "open-telemetry/opentelemetry-js",
"browser": {
"./src/platform/index.ts": "./src/platform/browser/index.ts",
"./build/src/platform/index.js": "./build/src/platform/browser/index.js"
},
"scripts": {
"test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'",
"tdd": "npm run test -- --watch-extensions ts --watch",
"clean": "rimraf build/*",
"codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../",
"codecov:browser": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../",
"compile": "npm run version:update && tsc -p .",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --ext .ts --fix",
"codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../",
"precompile": "tsc --version",
"prepare": "npm run compile",
"tdd": "npm run test -- --watch-extensions ts --watch",
"test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'",
"test:browser": "nyc karma start --single-run",
"version:update": "node ../../scripts/version-update.js",
"compile": "npm run version:update && tsc -p .",
"prepare": "npm run compile"
"watch": "tsc -w"
},
"keywords": [
"opentelemetry",
"nodejs",
"browser",
"tracing",
"profiling"
],
Expand All @@ -40,17 +48,33 @@
"access": "public"
},
"devDependencies": {
"@babel/core": "7.11.0",
"@types/mocha": "8.0.2",
"@types/node": "14.0.27",
"@types/sinon": "9.0.4",
"@types/webpack-env": "1.15.2",
"babel-loader": "8.1.0",
"codecov": "3.7.2",
"gts": "2.0.2",
"istanbul-instrumenter-loader": "3.0.1",
"karma": "5.1.1",
"karma-chrome-launcher": "3.1.0",
"karma-coverage-istanbul-reporter": "3.0.3",
"karma-mocha": "2.0.1",
"karma-spec-reporter": "0.0.32",
"karma-webpack": "4.0.2",
"mocha": "7.2.0",
"nock": "12.0.3",
"nyc": "15.1.0",
"rimraf": "3.0.2",
"sinon": "9.0.2",
"ts-loader": "8.0.1",
"ts-mocha": "7.0.0",
"ts-node": "8.10.2",
"typescript": "3.9.7"
"typescript": "3.9.7",
"webpack": "4.44.1",
"webpack-cli": "3.3.12",
"webpack-merge": "5.0.9"
},
"dependencies": {
"@opentelemetry/api": "^0.11.0",
Expand Down
1 change: 1 addition & 0 deletions packages/opentelemetry-exporter-zipkin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
*/

export * from './zipkin';
export * from './platform';
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,4 @@
* limitations under the License.
*/

describe('Zipkin Exporter E2E', () => {
it('should report spans to Zipkin server');
});
export * from './util';
131 changes: 131 additions & 0 deletions packages/opentelemetry-exporter-zipkin/src/platform/browser/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Copyright The 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 api from '@opentelemetry/api';
import { ExportResult } from '@opentelemetry/core';
import * as zipkinTypes from '../../types';
import { OT_REQUEST_HEADER } from '../../utils';

/**
* Prepares send function that will send spans to the remote Zipkin service.
*/
export function prepareSend(
logger: api.Logger,
urlStr: string,
headers?: Record<string, string>
) {
let xhrHeaders: Record<string, string>;
const useBeacon = navigator.sendBeacon && !headers;
if (headers) {
xhrHeaders = {
Accept: 'application/json',
'Content-Type': 'application/json',
[OT_REQUEST_HEADER]: '1',
...headers,
};
}

/**
* Send spans to the remote Zipkin service.
*/
return function send(
zipkinSpans: zipkinTypes.Span[],
done: (result: ExportResult) => void
) {
if (zipkinSpans.length === 0) {
logger.debug('Zipkin send with empty spans');
return done(ExportResult.SUCCESS);
}
const payload = JSON.stringify(zipkinSpans);
if (useBeacon) {
sendWithBeacon(payload, done, urlStr, logger);
} else {
sendWithXhr(payload, done, urlStr, logger, xhrHeaders);
}
};
}

/**
* Sends data using beacon
* @param data
* @param done
* @param urlStr
* @param logger
*/
function sendWithBeacon(
data: string,
done: (result: ExportResult) => void,
urlStr: string,
logger: api.Logger
) {
if (navigator.sendBeacon(urlStr, data)) {
logger.debug('sendBeacon - can send', data);
done(ExportResult.SUCCESS);
} else {
logger.error('sendBeacon - cannot send', data);
done(ExportResult.FAILED_NOT_RETRYABLE);
}
}

/**
* Sends data using XMLHttpRequest
* @param data
* @param done
* @param urlStr
* @param logger
* @param xhrHeaders
*/
function sendWithXhr(
data: string,
done: (result: ExportResult) => void,
urlStr: string,
logger: api.Logger,
xhrHeaders: Record<string, string> = {}
) {
const xhr = new window.XMLHttpRequest();
xhr.open('POST', urlStr);
Object.entries(xhrHeaders).forEach(([k, v]) => {
xhr.setRequestHeader(k, v);
});

xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
const statusCode = xhr.status || 0;
logger.debug(
'Zipkin response status code: %d, body: %s',
statusCode,
data
);

if (xhr.status >= 200 && xhr.status < 400) {
return done(ExportResult.SUCCESS);
} else if (statusCode < 500) {
return done(ExportResult.FAILED_NOT_RETRYABLE);
} else {
return done(ExportResult.FAILED_RETRYABLE);
}
}
};

xhr.onerror = err => {
logger.error('Zipkin request error', err);
return done(ExportResult.FAILED_RETRYABLE);
};

// Issue request to remote service
logger.debug('Zipkin request payload: %s', data);
xhr.send(data);
}
17 changes: 17 additions & 0 deletions packages/opentelemetry-exporter-zipkin/src/platform/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright The 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.
*/

export * from './node';
17 changes: 17 additions & 0 deletions packages/opentelemetry-exporter-zipkin/src/platform/node/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright The 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.
*/

export * from './util';
Loading

0 comments on commit a7b9e9d

Please sign in to comment.