Skip to content

Commit

Permalink
Document Load Instrumentation (open-telemetry#331)
Browse files Browse the repository at this point in the history
* chore: document load instrumentation

* chore: document load instrumentation

* chore: adding example for document load, fixing context

* chore: lint fix

* chore: updating documentation

* chore: reviews
  • Loading branch information
obecny authored Feb 19, 2021
1 parent fa0700b commit c8b7f3d
Show file tree
Hide file tree
Showing 24 changed files with 288 additions and 154 deletions.
1 change: 0 additions & 1 deletion examples/express/tracer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');

const EXPORTER = process.env.EXPORTER || '';


module.exports = (serviceName) => {
const provider = new NodeTracerProvider({
plugins: {
Expand Down
2 changes: 1 addition & 1 deletion examples/grpc_dynamic_codegen/capitalize_client.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

const api = require("@opentelemetry/api")
const api = require('@opentelemetry/api');
// eslint-disable-next-line import/order
const tracer = require('./tracer')('example-grpc-capitalize-client');
const path = require('path');
Expand Down
7 changes: 4 additions & 3 deletions examples/host-metrics/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { HostMetrics } = require('@opentelemetry/host-metrics');
// const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus');
const { MeterProvider } = require('@opentelemetry/metrics');
const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector');

const exporter = new CollectorMetricExporter({
headers: {},
serviceName: 'test-host-metrics',
Expand All @@ -29,6 +30,6 @@ const hostMetrics = new HostMetrics({ meterProvider, name: 'example-host-metrics
hostMetrics.start();

// keep running
(function wait () {
setTimeout(wait, 1000);
})();
(function wait() {
setTimeout(wait, 1000);
}());
31 changes: 14 additions & 17 deletions examples/mongodb/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@

// eslint-disable-next-line import/order
const tracer = require('./tracer')('example-mongodb-http-server');
const MongoClient = require('mongodb').MongoClient;
const { MongoClient } = require('mongodb');
const http = require('http');
const url = "mongodb://localhost:27017/mydb";

const url = 'mongodb://localhost:27017/mydb';
let db;

/** Starts a HTTP server that receives requests on sample server port. */
function startServer(port) {

// Connect to db
MongoClient.connect(url, function(err, database) {
if(err) throw err;
db = database.db("mydb");
MongoClient.connect(url, (err, database) => {
if (err) throw err;
db = database.db('mydb');
});
// Creates a server
const server = http.createServer(handleRequest);
Expand All @@ -28,7 +28,6 @@ function startServer(port) {

/** A function which handles requests and send response. */
function handleRequest(request, response) {

const currentSpan = tracer.getCurrentSpan();
// display traceid in the terminal
const { traceId } = currentSpan.context();
Expand All @@ -43,7 +42,7 @@ function handleRequest(request, response) {
if (request.url === '/collection/') {
handleCreateCollection(response);
} else if (request.url === '/insert/') {
handleInsertQuery(response);
handleInsertQuery(response);
} else if (request.url === '/get/') {
handleGetQuery(response);
} else {
Expand All @@ -58,39 +57,37 @@ function handleRequest(request, response) {
startServer(8080);

function handleInsertQuery(response) {
const obj = { name: "John", age: "20" };
db.collection("users").insertOne(obj, function(err, res) {
const obj = { name: 'John', age: '20' };
db.collection('users').insertOne(obj, (err, res) => {
if (err) {
console.log('Error code:', err.code);
response.end(err.message);
} else {
console.log("1 document inserted");
console.log('1 document inserted');
response.end();
}
});

}

function handleGetQuery(response) {
db.collection("users").find({}, function(err, res) {
db.collection('users').find({}, (err, res) => {
if (err) {
console.log('Error code:', err.code);
response.end(err.message);
} else {
console.log("1 document served");
console.log('1 document served');
response.end();
}
});

}

function handleCreateCollection(response) {
db.createCollection("users", function(err, res) {
db.createCollection('users', (err, res) => {
if (err) {
console.log('Error code:', err.code);
response.end(err.message);
} else {
console.log("1 collection created");
console.log('1 collection created');
response.end();
}
});
Expand Down
4 changes: 2 additions & 2 deletions examples/mongodb/tracer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ module.exports = (serviceName) => {
plugins: {
mongodb: {
enabled: true,
path: "@opentelemetry/plugin-mongodb",
enhancedDatabaseReporting: true
path: '@opentelemetry/plugin-mongodb',
enhancedDatabaseReporting: true,
},
http: {
enabled: true,
Expand Down
1 change: 0 additions & 1 deletion examples/redis/tracer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');

const EXPORTER = process.env.EXPORTER || '';


module.exports = (serviceName) => {
const provider = new NodeTracerProvider();

Expand Down
31 changes: 31 additions & 0 deletions examples/web/examples/document-load/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">

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

<!--
https://www.w3.org/TR/trace-context/
Set the `traceparent` in the server's HTML template code. It should be
dynamically generated server side to have the server's request trace Id,
a parent span Id that was set on the server's request span, and the trace
flags to indicate the server's sampling decision
(01 = sampled, 00 = notsampled).
'{version}-{traceId}-{spanId}-{sampleDecision}'
-->
<meta name="traceparent" content="00-ab42124a3c573678d4d8b21ba52df3bf-d21f7bc17caa5aba-01">

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

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

</body>

</html>
107 changes: 107 additions & 0 deletions examples/web/examples/document-load/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { context, getSpan, setSpan } from '@opentelemetry/api';
import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing';
import { WebTracerProvider } from '@opentelemetry/web';
import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load';
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';
import { CompositePropagator, HttpTraceContext } from '@opentelemetry/core';
import { registerInstrumentations } from '@opentelemetry/instrumentation';

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

provider.register({
contextManager: new ZoneContextManager(),
propagator: new CompositePropagator({
propagators: [
new B3Propagator(),
new HttpTraceContext(),
],
}),
});
registerInstrumentations({
instrumentations: [
new DocumentLoadInstrumentation(),
new XMLHttpRequestInstrumentation({
ignoreUrls: [/localhost/],
propagateTraceHeaderCorsUrls: [
'http://localhost:8090',
],
}),
],
tracerProvider: provider,
});

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

const getData = (url) => new Promise((resolve, reject) => {
// eslint-disable-next-line no-undef
const req = new XMLHttpRequest();
req.open('GET', url, true);
req.send();
req.onload = () => {
let json;
try {
json = JSON.parse(req.responseText);
} catch (e) {
reject(e);
}
resolve(json);
};
});

// example of keeping track of context between async operations
const prepareClickEvent = () => {
const url1 = 'https://raw.githubusercontent.com/open-telemetry/opentelemetry-js/master/package.json';
const url2 = 'https://raw.githubusercontent.com/open-telemetry/opentelemetry-js/master/packages/opentelemetry-web/package.json';

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

const onClick = () => {
let count = 0;

function finish() {
count++;
if (count === 2) {
mainSpan.end();
}
}

const mainSpan = tracer.startSpan('click button');
context.with(setSpan(context.active(), mainSpan), () => {
const span1 = tracer.startSpan('files-series-info-1');

const span2 = tracer.startSpan('files-series-info-2');

context.with(setSpan(context.active(), span1), () => {
getData(url1).then((data) => {
const curSpan = getSpan(context.active());
console.log('current span is span1', curSpan === span1);
console.log('info from package.json', data.description, data.version);
curSpan.addEvent('fetching-span1-completed');
span1.end();
finish();
});
});

context.with(setSpan(context.active(), span2), () => {
getData(url2).then((data) => {
setTimeout(() => {
const curSpan = getSpan(context.active());
console.log('current span is span2', curSpan === span2);
console.log('info from package.json', data.description, data.version);
curSpan.addEvent('fetching-span2-completed');
span2.end();
finish();
}, 100);
});
});
});
};
element.addEventListener('click', onClick);
};

window.addEventListener('load', prepareClickEvent);
5 changes: 3 additions & 2 deletions examples/web/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "web-examples",
"private": true,
"version": "0.12.0",
"version": "0.13.0",
"description": "Example of using web plugins in browser",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -37,8 +37,9 @@
"@opentelemetry/context-zone": "^0.15.0",
"@opentelemetry/core": "^0.15.0",
"@opentelemetry/exporter-collector": "^0.15.0",
"@opentelemetry/instrumentation-document-load": "^0.13.1",
"@opentelemetry/instrumentation-xml-http-request": "^0.15.0",
"@opentelemetry/instrumentation-user-interaction": "^0.12.1",
"@opentelemetry/instrumentation-user-interaction": "^0.13.1",
"@opentelemetry/propagator-b3": "^0.15.0",
"@opentelemetry/tracing": "^0.15.0",
"@opentelemetry/web": "^0.15.0"
Expand Down
3 changes: 3 additions & 0 deletions examples/web/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict';

const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const path = require('path');
Expand All @@ -7,6 +9,7 @@ const directory = path.resolve(__dirname);
const common = {
mode: 'development',
entry: {
'document-load': 'examples/document-load/index.js',
'user-interaction': 'examples/user-interaction/index.js',
},
output: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# OpenTelemetry Plugin Document Load
# OpenTelemetry Instrumentation Document Load
[![Gitter chat][gitter-image]][gitter-url]
[![NPM Published Version][npm-img]][npm-url]
[![dependencies][dependencies-image]][dependencies-url]
Expand All @@ -10,27 +10,49 @@ This module provides *automated instrumentation for document load* for Web appli
## Installation

```bash
npm install --save @opentelemetry/plugin-document-load
npm install --save @opentelemetry/instrumentation-document-load
```

## Usage

```js
import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing';
import { WebTracerProvider } from '@opentelemetry/web';
import { DocumentLoad } from '@opentelemetry/plugin-document-load';
import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { B3Propagator } from '@opentelemetry/propagator-b3';
import { CompositePropagator, HttpTraceContext } from '@opentelemetry/core';

const provider = new WebTracerProvider({
plugins: [
new DocumentLoad()
]
});
const provider = new WebTracerProvider();

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

provider.register({
propagator: new CompositePropagator({
propagators: [
new B3Propagator(),
new HttpTraceContext(),
],
}),
});

registerInstrumentations({
instrumentations: [
new DocumentLoadInstrumentation(),
new XMLHttpRequestInstrumentation({
ignoreUrls: [/localhost/],
propagateTraceHeaderCorsUrls: [
'http://localhost:8090',
],
}),
],
tracerProvider: provider,
});

```

## Optional: Send a trace parent from your server
This plugin supports connecting the server side spans for the initial HTML load with the client side span for the load from the browser's timing API. This works by having the server send its parent trace context (trace ID, span ID and trace sampling decision) to the client.
This instrumentation supports connecting the server side spans for the initial HTML load with the client side span for the load from the browser's timing API. This works by having the server send its parent trace context (trace ID, span ID and trace sampling decision) to the client.

Because the browser does not send a trace context header for the initial page navigation, the server needs to fake a trace context header in a middleware and then send that trace context header back to the client as a meta tag *traceparent* . The *traceparent* meta tag should be in the [trace context W3C draft format][trace-context-url] . For example:

Expand Down Expand Up @@ -72,10 +94,10 @@ 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/main/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-document-load
[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-plugin-document-load
[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/dev-status.svg?path=packages/opentelemetry-plugin-document-load
[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-plugin-document-load&type=dev
[npm-url]: https://www.npmjs.com/package/@opentelemetry/plugin-document-load
[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fplugin-document-load.svg
[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/status.svg?path=packages/opentelemetry-instrumentation-document-load
[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-instrumentation-document-load
[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/dev-status.svg?path=packages/opentelemetry-instrumentation-document-load
[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-instrumentation-document-load&type=dev
[npm-url]: https://www.npmjs.com/package/@opentelemetry/instrumentation-document-load
[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Finstrumentation-document-load.svg
[trace-context-url]: https://www.w3.org/TR/trace-context
Loading

0 comments on commit c8b7f3d

Please sign in to comment.