forked from open-telemetry/opentelemetry-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: create a getting started guide (open-telemetry#566)
* docs: create a getting started guide * docs(getting-started): add a table of contents * chore: add todo to missing sections * docs(getting-started): add metrics guide * docs(getting-started): run prettier
- Loading branch information
1 parent
df2cc43
commit 66927ce
Showing
13 changed files
with
533 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,289 @@ | ||
# Getting Started with OpenTelemetry JS | ||
This guide will walk you through the setup and configuration process for a tracing backend (in this case [Zipkin](https://zipkin.io), but [Jaeger](https://www.jaegertracing.io) would be simple to use as well), a metrics backend like [Prometheus](https://prometheus.io), and auto-instrumentation of NodeJS. | ||
|
||
|
||
1. [Tracing Your Application with OpenTelemetry](#tracing-your-application-with-opentelemetry) | ||
1. [Setting up a Tracing Backend](#setting-up-a-tracing-backend) | ||
2. [Trace Your NodeJS Application](#trace-your-nodejs-application) | ||
1. [Install the required OpenTelemetry libraries](#install-the-required-opentelemetry-libraries) | ||
2. [Initialize a global tracer](#initialize-a-global-tracer) | ||
3. [Initialize and register a trace exporter](#initialize-and-register-a-trace-exporter) | ||
2. [Collect Metrics Using OpenTelemetry](#collect-metrics-using-opentelemetry) | ||
1. [Set up a Metrics Backend](#set-up-a-metrics-backend) | ||
2. [Monitor Your NodeJS Application](#monitor-your-nodejs-application) | ||
1. [Install the required OpenTelemetry metrics libraries](#install-the-required-opentelemetry-metrics-libraries) | ||
2. [Initialize a meter and collect metrics](#initialize-a-meter-and-collect-metrics) | ||
3. [Initialize and register a metrics exporter](#initialize-and-register-a-metrics-exporter) | ||
|
||
## Tracing Your Application with OpenTelemetry | ||
This guide assumes you are going to be using Zipkin as your tracing backend, but modifying it for Jaeger should be straightforward. | ||
|
||
An example application which can be used with this guide can be found at in the [example directory](example). You can see what it looks like with tracing enabled in the [traced-example directory](traced-example). | ||
|
||
### Setting up a Tracing Backend | ||
The first thing we will need before we can start collecting traces is a tracing backend like Zipkin that we can export traces to. If you already have a supported tracing backend (Zipkin or Jaeger), you can skip this step. If not, you will need to run one. | ||
|
||
In order to set up Zipkin as quickly as possible, run the latest [Docker Zipkin](https://github.com/openzipkin/docker-zipkin) container, exposing port `9411`. If you can’t run Docker containers, you will need to download and run Zipkin by following the Zipkin [quickstart guide](https://zipkin.io/pages/quickstart.html). | ||
|
||
```sh | ||
$ docker run --rm -d -p 9411:9411 --name zipkin openzipkin/zipkin | ||
``` | ||
|
||
Browse to <http://localhost:9411> to ensure that you can see the Zipkin UI. | ||
|
||
<p align="center"><img src="./images/zipkin.png?raw=true"/></p> | ||
|
||
### Trace Your NodeJS Application | ||
This guide uses the example application provided in the `example` directory, but the steps to instrument your own application should be broadly the same. Here is an overview of what we will be doing. | ||
|
||
1. Install the required OpenTelemetry libraries | ||
2. Initialize a global tracer | ||
3. Initialize and register a trace exporter | ||
|
||
#### Install the required OpenTelemetry libraries | ||
To create traces on NodeJS, you will need `@opentelemetry/node`, `@opentelemetry/core`, and any plugins required by your application such as gRPC, or HTTP. If you are using the example application, you will need to install `@opentelemetry/plugin-http`. | ||
|
||
```sh | ||
$ npm install \ | ||
@opentelemetry/core \ | ||
@opentelemetry/node \ | ||
@opentelemetry/plugin-http | ||
``` | ||
|
||
#### Initialize a global tracer | ||
All tracing initialization should happen before your application’s code runs. The easiest way to do this is to initialize tracing in a separate file that is required using node’s `-r` option before application code runs. | ||
|
||
Create a file named `tracing.js` and add the following code: | ||
|
||
```javascript | ||
'use strict'; | ||
|
||
const opentelemetry = require("@opentelemetry/core") | ||
const { NodeTracer } = require("@opentelemetry/node") | ||
|
||
const tracer = new NodeTracer({ | ||
logLevel: opentelemetry.LogLevel.ERROR | ||
}); | ||
|
||
opentelemetry.initGlobalTracer(tracer); | ||
``` | ||
|
||
If you run your application now with `node -r ./tracing.js app.js`, your application will create and propagate traces over HTTP. If an already instrumented service that supports [Trace Context](https://www.w3.org/TR/trace-context/) headers calls your application using HTTP, and you call another application using HTTP, the Trace Context headers will be correctly propagated. | ||
|
||
If you wish to see a completed trace, however, there is one more step. You must register an exporter to send traces to a tracing backend. | ||
|
||
#### Initialize and Register a Trace Exporter | ||
This guide uses the Zipkin tracing backend, but if you are using another backend like [Jaeger](https://www.jaegertracing.io), this is where you would make your change. | ||
|
||
To export traces, we will need a few more dependencies. Install them with the following command: | ||
|
||
```sh | ||
$ npm install \ | ||
@opentelemetry/tracing \ | ||
@opentelemetry/exporter-zipkin | ||
|
||
$ # for jaeger you would run this command: | ||
$ # npm install @opentelemetry/exporter-jaeger | ||
``` | ||
|
||
After these dependencies are installed, we will need to initialize and register them. Modify `tracing.js` so that it matches the following code snippet, replacing the service name `"getting-started"` with your own service name if you wish. | ||
|
||
```javascript | ||
'use strict'; | ||
|
||
const opentelemetry = require("@opentelemetry/core") | ||
const { NodeTracer } = require("@opentelemetry/node") | ||
|
||
const { SimpleSpanProcessor } = require("@opentelemetry/tracing") | ||
const { ZipkinExporter } = require("@opentelemetry/exporter-zipkin"); | ||
|
||
const tracer = new NodeTracer({ | ||
logLevel: opentelemetry.LogLevel.ERROR | ||
}); | ||
|
||
opentelemetry.initGlobalTracer(tracer); | ||
|
||
tracer.addSpanProcessor( | ||
new SimpleSpanProcessor( | ||
new ZipkinExporter({ | ||
serviceName: "getting-started", | ||
// If you are running your tracing backend on another host, | ||
// you can point to it using the `url` parameter of the | ||
// exporter config. | ||
}) | ||
) | ||
); | ||
|
||
|
||
console.log("tracing initialized") | ||
``` | ||
|
||
Now if you run your application with the `tracing.js` file loaded, and you send requests to your application over HTTP (in the sample application just browse to http://localhost:8080), you will see traces exported to your tracing backend that look like this: | ||
|
||
```sh | ||
$ node -r ./tracing.js app.js | ||
``` | ||
|
||
<p align="center"><img src="./images/zipkin-trace.png?raw=true"/></p> | ||
|
||
**Note:** Some spans appear to be duplicated, but they are not. This is because the sample application is both the client and the server for these requests. You see one span that is the client side request timing, and one span that is the server side request timing. Anywhere they don’t overlap is network time. | ||
|
||
## Collect Metrics Using OpenTelemetry | ||
This guide assumes you are going to be using Prometheus as your metrics backend. It is currently the only metrics backend supported by OpenTelemetry JS. | ||
|
||
**Note**: This section is a work in progress | ||
|
||
### Set up a Metrics Backend | ||
Now that we have end-to-end traces, we will collect and export some basic metrics. | ||
|
||
Currently, the only supported metrics backend is [Prometheus](https://prometheus.io). Head to the [Prometheus download page](https://prometheus.io/download/) and download the latest release of Prometheus for your operating system. | ||
|
||
Open a command line and `cd` into the directory where you downloaded the Prometheus tarball. Untar it and change into the newly created directory. | ||
|
||
```sh | ||
$ cd Downloads | ||
|
||
$ # Replace the file name below with your downloaded tarball | ||
$ tar xvfz prometheus-2.14.0.darwin-amd64.tar | ||
|
||
$ # Replace the dir below with your created directory | ||
$ cd prometheus-2.14.0.darwin-amd64 | ||
|
||
$ ls | ||
LICENSE console_libraries data prometheus.yml tsdb | ||
NOTICE consoles prometheus promtool | ||
``` | ||
|
||
The created directory should have a file named `prometheus.yml`. This is the file used to configure Prometheus. For now, just make sure Prometheus starts by running the `./prometheus` binary in the folder and browse to <http://localhost:9090>. | ||
|
||
```sh | ||
$ ./prometheus | ||
# some output elided for brevity | ||
msg="Starting Prometheus" version="(version=2.14.0, branch=HEAD, revision=edeb7a44cbf745f1d8be4ea6f215e79e651bfe19)" | ||
# some output elided for brevity | ||
level=info ts=2019-11-21T20:39:40.262Z caller=web.go:496 component=web msg="Start listening for connections" address=0.0.0.0:9090 | ||
# some output elided for brevity | ||
level=info ts=2019-11-21T20:39:40.383Z caller=main.go:626 msg="Server is ready to receive web requests." | ||
``` | ||
|
||
<p align="center"><img src="./images/prometheus.png?raw=true"/></p> | ||
|
||
### Monitor Your NodeJS Application | ||
|
||
An example application which can be used with this guide can be found at in the [example directory](example). You can see what it looks like with metric monitoring enabled in the [monitored-example directory](monitored-example). | ||
|
||
1. Install the required OpenTelemetry metrics libraries | ||
2. Initialize a meter and collect metrics | ||
3. Initialize and register a metrics exporter | ||
|
||
#### Install the required OpenTelemetry metrics libraries | ||
To create metrics on NodeJS, you will need `@opentelemetry/metrics`. | ||
|
||
```sh | ||
$ npm install \ | ||
@opentelemetry/metrics | ||
``` | ||
|
||
#### Initialize a meter and collect metrics | ||
In order to create and monitor metrics, we will need a `Meter`. In OpenTelemetry, a `Meter` is the mechanism used to create and manage metrics, labels, and metric exporters. | ||
|
||
Create a file named `monitoring.js` and add the following code: | ||
|
||
```javascript | ||
'use strict'; | ||
|
||
const { Meter } = require("@opentelemetry/metrics"); | ||
|
||
const meter = new Meter(); | ||
``` | ||
|
||
Now, you can require this file from your application code and use the `Meter` to create and manage metrics. The simplest of these metrics is a counter. Let's create and export from our `monitoring.js` file a middleware function that express can use to count all requests by route. Modify the `monitoring.js` file so that it looks like this: | ||
|
||
```javascript | ||
'use strict'; | ||
|
||
const { Meter } = require("@opentelemetry/metrics"); | ||
|
||
const meter = new Meter(); | ||
|
||
const requestCount = meter.createCounter("requests", { | ||
monotonic: true, | ||
labelKeys: ["route"], | ||
description: "Count all incoming requests" | ||
}); | ||
|
||
const handles = new Map(); | ||
|
||
module.exports.countAllRequests = () => { | ||
return (req, res, next) => { | ||
if (!handles.has(req.path)) { | ||
const labelSet = meter.labels({ route: req.path }); | ||
const handle = requestCount.getHandle(labelSet); | ||
handles.set(req.path, handle); | ||
} | ||
|
||
handles.get(req.path).add(1); | ||
next(); | ||
}; | ||
}; | ||
``` | ||
|
||
Now let's import and use this middleware in our application code: | ||
|
||
```javascript | ||
const { countAllRequests } = require("./monitoring"); | ||
const app = express(); | ||
app.use(countAllRequests()); | ||
``` | ||
|
||
Now, when we make requests to our service our meter will count all requests. | ||
|
||
**Note**: Creating a new `labelSet` and `handle` on every request is not ideal as creating the `labelSet` can often be an expensive operation. This is why handles are created and stored in a `Map` according to the route key. | ||
|
||
#### Initialize and register a metrics exporter | ||
Counting metrics is only useful if we can export them somewhere that we can see them. For this, we're going to use prometheus. Creating and registering a metrics exporter is much like the tracing exporter above. First we will need to install the prometheus exporter. | ||
|
||
```sh | ||
$ npm install @opentelemetry/exporter-prometheus | ||
``` | ||
|
||
Next, modify your `monitoring.js` file to look like this: | ||
|
||
```javascript | ||
"use strict"; | ||
|
||
const { Meter } = require("@opentelemetry/metrics"); | ||
const { PrometheusExporter } = require("@opentelemetry/exporter-prometheus"); | ||
|
||
const meter = new Meter(); | ||
|
||
meter.addExporter( | ||
new PrometheusExporter( | ||
{ startServer: true }, | ||
() => { | ||
console.log("prometheus scrape endpoint: http://localhost:9464/metrics"); | ||
} | ||
) | ||
); | ||
|
||
const requestCount = meter.createCounter("requests", { | ||
monotonic: true, | ||
labelKeys: ["route"], | ||
description: "Count all incoming requests" | ||
}); | ||
|
||
const handles = new Map(); | ||
|
||
module.exports.countAllRequests = () => { | ||
return (req, res, next) => { | ||
if (!handles.has(req.path)) { | ||
const labelSet = meter.labels({ route: req.path }); | ||
const handle = requestCount.getHandle(labelSet); | ||
handles.set(req.path, handle); | ||
} | ||
|
||
handles.get(req.path).add(1); | ||
next(); | ||
}; | ||
}; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
"use strict"; | ||
|
||
const PORT = process.env.PORT || "8080"; | ||
|
||
const express = require("express"); | ||
const axios = require("axios"); | ||
|
||
const app = express(); | ||
|
||
app.get("/", (req, res) => { | ||
axios | ||
.get(`http://localhost:${PORT}/middle-tier`) | ||
.then(() => axios.get(`http://localhost:${PORT}/middle-tier`)) | ||
.then(result => { | ||
res.send(result.data); | ||
}) | ||
.catch(err => { | ||
console.error(err); | ||
res.status(500).send(); | ||
}); | ||
}); | ||
|
||
app.get("/middle-tier", (req, res) => { | ||
axios | ||
.get(`http://localhost:${PORT}/backend`) | ||
.then(() => axios.get(`http://localhost:${PORT}/backend`)) | ||
.then(result => { | ||
res.send(result.data); | ||
}) | ||
.catch(err => { | ||
console.error(err); | ||
res.status(500).send(); | ||
}); | ||
}); | ||
|
||
app.get("/backend", (req, res) => { | ||
res.send("Hello from the backend"); | ||
}); | ||
|
||
app.listen(parseInt(PORT, 10), () => { | ||
console.log(`Listening for requests on http://localhost:${PORT}`); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"name": "@opentelemetry/getting-started", | ||
"version": "1.0.0", | ||
"description": "This repository provides everything required to follow the OpenTelemetry Getting Started Guide", | ||
"main": "app.js", | ||
"scripts": { | ||
"start": "node app.js" | ||
}, | ||
"author": "OpenTelemetry Authors", | ||
"license": "Apache-2.0", | ||
"dependencies": { | ||
"axios": "^0.19.0", | ||
"express": "^4.17.1" | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.