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

document: fix express example #413

Merged
merged 4 commits into from
Apr 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions examples/express/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ function makeRequest() {
api.context.with(api.setSpan(api.ROOT_CONTEXT, span), async () => {
try {
const res = await axios.get('http://localhost:8080/run_test');
span.setStatus({ code: api.StatusCode.OK });
console.log(res.statusText);
console.log('status:', res.statusText);
span.setStatus({ code: api.SpanStatusCode.OK });
} catch (e) {
span.setStatus({ code: api.StatusCode.ERROR, message: e.message });
console.log('failed:', e.message);
span.setStatus({ code: api.SpanStatusCode.ERROR, message: e.message });
}
span.end();
console.log('Sleeping 5 seconds before shutdown to ensure all records are flushed.');
Expand Down
9 changes: 4 additions & 5 deletions examples/express/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,14 @@
"@opentelemetry/exporter-jaeger": "^0.18.0",
"@opentelemetry/exporter-zipkin": "^0.18.0",
"@opentelemetry/instrumentation": "^0.18.0",
"@opentelemetry/instrumentation-express": "^0.15.0",
"@opentelemetry/instrumentation-http": "^0.18.2",
"@opentelemetry/node": "^0.18.0",
"@opentelemetry/plugin-express": "file:../../plugins/node/opentelemetry-plugin-express",
"@opentelemetry/plugin-http": "^0.18.0",
"@opentelemetry/tracing": "^0.18.0",
"axios": "^0.19.0",
"cross-env": "^7.0.3",
"express": "^4.17.1"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js#readme",
"devDependencies": {
"cross-env": "^6.0.0"
}
"devDependencies": {}
}
37 changes: 17 additions & 20 deletions examples/express/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,24 @@ const authMiddleware = (req, res, next) => {
}
};

async function setupRoutes() {
app.use(express.json());

app.get('/run_test', async (req, res) => {
const createdCat = await axios.post(`http://localhost:${PORT}/cats`, {
name: 'Tom',
friends: [
'Jerry',
],
}, {
headers: {
Authorization: 'secret_token',
},
});

return res.status(201).send(createdCat.data);
app.use(express.json());
app.get('/run_test', async (req, res) => {
// Calls another endpoint of the same API, somewhat mimicing an external API call
const createdCat = await axios.post(`http://localhost:${PORT}/cats`, {
name: 'Tom',
friends: [
'Jerry',
],
}, {
headers: {
Authorization: 'secret_token',
},
});
app.use('/cats', authMiddleware, getCrudController());
}

setupRoutes().then(() => {
app.listen(PORT);
return res.status(201).send(createdCat.data);
});
app.use('/cats', authMiddleware, getCrudController());

app.listen(PORT, () => {
console.log(`Listening on http://localhost:${PORT}`);
});
43 changes: 21 additions & 22 deletions examples/express/tracer.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
'use strict';

const opentelemetry = require('@opentelemetry/api');

// Not functionally required but gives some insight what happens behind the scenes
const { diag, DiagConsoleLogger, DiagLogLevel } = opentelemetry;
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.INFO);

const { registerInstrumentations } = require('@opentelemetry/instrumentation');
const { NodeTracerProvider } = require('@opentelemetry/node');
const { SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');

const EXPORTER = process.env.EXPORTER || '';
const Exporter = (process.env.EXPORTER || '')
.toLowerCase().startsWith('z') ? ZipkinExporter : JaegerExporter;
const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express');
const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http');

module.exports = (serviceName) => {
const provider = new NodeTracerProvider({
plugins: {
express: {
enabled: true,
path: '@opentelemetry/plugin-express',
},
http: {
enabled: true,
path: '@opentelemetry/plugin-http',
},
},
const provider = new NodeTracerProvider();
registerInstrumentations({
tracerProvider: provider,
instrumentations: [
// Express instrumentation expects HTTP layer to be instrumented
HttpInstrumentation,
ExpressInstrumentation,
],
});

let exporter;
if (EXPORTER.toLowerCase().startsWith('z')) {
exporter = new ZipkinExporter({
serviceName,
});
} else {
exporter = new JaegerExporter({
serviceName,
});
}
const exporter = new Exporter({
serviceName,
});

provider.addSpanProcessor(new SimpleSpanProcessor(exporter));

Expand Down
44 changes: 32 additions & 12 deletions plugins/node/opentelemetry-instrumentation-express/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,45 +12,65 @@ For automatic instrumentation see the

## Installation

This instrumentation relies on HTTP calls to also be instrumented. Make sure you install and enable both.

```bash
npm install --save @opentelemetry/instrumentation-express
npm install --save @opentelemetry/instrumentation-http @opentelemetry/instrumentation-express
```

### Supported Versions
- `^4.0.0`

## Usage

OpenTelemetry Express Instrumentation allows the user to automatically collect trace data and export them to their backend of choice, to give observability to distributed systems.

To load a specific instrumentation (express in this case), specify it in the Node Tracer's configuration.
To load the instrumentation, specify it in the Node Tracer's configuration:

```js
const { NodeTracerProvider } = require('@opentelemetry/node');
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http');
const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express');

const provider = new NodeTracerProvider();
registerInstrumentations({
tracerProvider: provider,
instrumentations: [
// Express instrumentation expects HTTP layer to be instrumented
HttpInstrumentation,
ExpressInstrumentation,
],
});
provider.register();
new ExpressInstrumentation();
```

See [examples/express](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/examples/express) for a short example.

### Caveats

Because of the way express works, it's hard to correctly compute the time taken by asynchronous middlewares and request handlers. For this reason, the time you'll see reported for asynchronous middlewares and request handlers will only represent the synchronous execution time, and **not** any asynchronous work.
Because of the way express works, it's hard to correctly compute the time taken by asynchronous middlewares and request handlers. For this reason, the time you'll see reported for asynchronous middlewares and request handlers still only represent the synchronous execution time, and **not** any asynchronous work.

### Express Instrumentation Options

Express instrumentation has few options available to choose from. You can set the following:

| Options | Type | Description |
| ------- | ---- | ----------- |
| `ignoreLayers` | `IgnoreMatcher[]` | Express instrumentation will not trace all layers that match. |
| `ignoreLayersType`| `ExpressLayerType[]` | Express instrumentation will ignore the layers that match based on their type. |
| Options | Type | Example | Description |
| ------- | ---- | ------- | ----------- |
| `ignoreLayers` | `IgnoreMatcher[]` | `[/^\/_internal\//]` | Ignore layers that by match. |
| `ignoreLayersType`| `ExpressLayerType[]` | `['request_handler']` | Ignore layers of specified type. |

`ignoreLayers` accepts an array of elements of types:

- `string` for full match of the path,
- `RegExp` for partial match of the path,
- `function` in the form of `(path) => boolean` for custom logic.

`ignoreLayersType` accepts an array of following strings:

For reference, here are the three different layer type:
- `router` is the name of `express.Router()`
- `middleware`
- `request_handler` is the name for anything thats not a router or a middleware.
- `router` is the name of `express.Router()`,
- `middleware`,
- `request_handler` is the name for anything that's not a router or a middleware.

## Useful links
- For more information on OpenTelemetry, visit: <https://opentelemetry.io/>
Expand Down