Instrumenting Your Node.js Apps with OpenTelemetry
Tags: opentelemetry, observability, tutorial, beginners
Published: 2021-06-24 16:21:26

When I first joined New Relic, I really didn't understand the importance of observability, because I came from a frontend background. As I began learning about why observability was valuable for developers, I started digging deeper into the open source ecosystem and learning what makes it possible for modern apps to maintain uptime. I learned more about OpenTelemetry, a popular open source tool for monitoring your apps and websites, but it was intimidating because I couldn't find any introductory tutorials online guiding me through the process of instrumentation.

It wasn't until I began instrumenting my own apps using the [OpenTelemetry documentation](https://opentelemetry.io/docs/) that I realized how easy it was to get started. I collaborated with [freeCodeCamp.org](https://freecodecamp.org) to create a beginner-friendly resource for anyone to begin instrumenting apps with OpenTelemetry. I worked with an amazing technical content creator named Ania Kubów to bring this one-hour video course to life. This course teaches how to use OpenTelemetry, including microservices, observability, tracing, and more.

## Instrumenting your Node.js apps with OpenTelemetry

As systems become increasingly complex, it’s increasingly important to get visibility into the inner workings of systems to increase performance and reliability. Distributed tracing shows how each request passes through the application, giving developers context to resolve incidents, showing what parts of their system are slow or broken. 

A single trace shows the path a request makes, from the browser or mobile device down to the database. By looking at traces as a whole, developers can quickly discover which parts of their application is having the biggest impact on performance as it affects your users’ experiences.

That’s pretty abstract, right? So let’s zero in on a specific example to help clarify things. We’ll use OpenTelemetry to generate and view traces from a small sample application.

{% youtube r8UvWSX3KA8 %}

## Spinning up our Movies App
We have written a simple application consisting of two microservices, movies and dashboard. The `movies` service provides the name of movies and their genre in JSON format, while the `dashboard` service returns the results from the movies service.

[👉 Clone the repo](https://github.com/lazyplatypus/Open-Telemetry-Demo)

To spin up the app, run
```
$ npm i
$ node dashboard.js
$ node movies.js
```

Notice the variable `delay`, built into the movies microservice that causes random delays returning the JSON.

```diff
const express = require('express')
const app = express()
const port = 3000

app.get('/movies', async function (req, res) {
   res.type('json')
+  var delay = Math.floor( ( Math.random() * 2000 ) + 100);
+  setTimeout((() => {
      res.send(({movies: [
         { name: 'Jaws', genre: 'Thriller'},
         { name: 'Annie', genre: 'Family'},
         { name: 'Jurassic Park', genre: 'Action'},
      ]}))
+  }), delay)
})
```

## Tracing HTTP Requests with Open Telemetry

 OpenTelemetry traces incoming and outgoing HTTP requests by attaching IDs. To do this, we need to 

- **Instantiate a trace provider** to get data flowing. 
- **Configure that trace provider with an exporter** to send telemetry data to another system where you can view, store, and analyze it.
- **Install OpenTelemetry plugins** to instrument specific node module(s) to automatically instrument various frameworks

You need to have Docker on your machine to run a Zipkin instance. If you don't have Docker yet, it's easy to install. As for Zipkin, it's an open-source distributed tracing system created by Twitter that helps gather timing data needed to troubleshoot latency problems in service architectures. The OpenZipkin volunteer organization currently runs it. Finally, if you want to export your OpenTelemetry data to New Relic in Step 4,  sign up to analyze, store, and use your telemetry data for free, forever.

### Step 1: Create our trace provider and configuring it with an exporter

To create a trace provider, you need to install the following tool:

```
$ npm install @opentelemetry/node
```

#### OpenTelemetry auto instrumentation package for NodeJS

The `@opentelemetry/node` module provides auto-instrumentation for Node.js applications, which automatically identifies frameworks (Express), common protocols (HTTP), databases, and other libraries within your application. This module uses other community-contributed plugins to automatically instrument your application to automatically produce spans and provide end-to-end tracing with just a few lines of code.

#### OpenTelemetry Plugins

Install the plugins:

```
$ npm install @opentelemetry/plugin-http
$ npm install @opentelemetry/plugin-express
```

When NodeJS’s HTTP module handles any API requests, the `@opentelemetry/plugin-http` plugin generates trace data. The `@opentelemetry/plugin-express` plugin generates trace data from requests sent through the Express framework.


### Step 2: Adding the Trace Provider and the Span Processor
After tracers are implemented into applications, they record timing and metadata about operations that take place (for example, when a web server records exactly when it receives a request, and when it sends a response).

Add this code snippet to 
- create a trace provider
- adds a span processor to the trace provider

This code gets data from your local application and prints it to the terminal:

```javascript
const { NodeTracerProvider } = require('@opentelemetry/node');
const { ConsoleSpanExporter, SimpleSpanProcessor } = require('@opentelemetry/tracing');

const provider = new NodeTracerProvider();
const consoleExporter = new ConsoleSpanExporter();
const spanProcessor = new SimpleSpanProcessor(consoleExporter);
provider.addSpanProcessor(spanProcessor);
provider.register()
```

If you want to learn more about this code, check out the [OpenTelemetry docs on tracers](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#tracer).

Once we add this code snippet, whenever we reload `http://localhost:3001/dashboard`, we should get something like this - beautiful things on the terminal. 

![giphy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fklulsur2tviyd32wlnf.gif)
 
### Step 3: Use Docker to install Zipkin and start tracing your application

You instrumented OpenTelemetry in the previous step. Now you move the data that you collected to a running Zipkin instance.

Let's spin up a Zipkin instance with the [Docker Hub Image](https://hub.docker.com/r/openzipkin/zipkin/)

```
$ docker run -d -p 9411:9411 openzipkin/zipkin
```

and you’ll have a Zipkin instance up and running. You’ll be able to load it by pointing your web browser to http://localhost:9411. You’ll see something like this

![Screenshot of Zipkin](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xs7db7lo5gck3i2ty12e.png)  

#### Exporting to Zipkin

Although neat, spans in a terminal window are a poor way to gain visibility into a service. You’re not going to want to scroll through JSON data in your terminal. Instead, it’s a lot easier to see a visualization in a dashboard. Let's work on that now. In the previous step, we added a console exporter to the system. Now you ship this data to Zipkin.

In this code snippet, we are instantiating a Zipkin exporter, and then adding it to the trace provider. 

```diff
const { NodeTracerProvider } = require('@opentelemetry/node')
const { ConsoleSpanExporter, SimpleSpanProcessor } = require('@opentelemetry/tracing')
+ const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin')
const provider = new NodeTracerProvider()
const consoleExporter = new ConsoleSpanExporter()
const spanProcessor = new SimpleSpanProcessor(consoleExporter)
provider.addSpanProcessor(spanProcessor)
provider.register()

+ const zipkinExporter = new ZipkinExporter({
+  url: 'http://localhost:9411/api/v2/spans',
+  serviceName: 'movies-service'
})

+ const zipkinProcessor = new SimpleSpanProcessor(zipkinExporter)
+ provider.addSpanProcessor(zipkinProcessor)
```

After you make these changes, let's visit our Zipkin instance at localhost:9411, start our application back up and request some URLs.

![Screen Shot 2021-06-23 at 3.54.32 PM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/scuaqg2k6y3zwwzospt4.png)
 

### Step 4: Using the OpenTelemetry Collector to export the data into New Relic

What happens if we want to send the OpenTelemetry data to another backend where you didn't have to manage all of your own telemetry data? 

Well, the amazing contributors to OpenTelemetry have come up with a solution to fix this!  

![Group 1792](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p2o98se1kb01bsjni2j6.png)
 
The OpenTelemetry Collector is a way for developers to receive, process, and export telemetry data to multiple backends. This collector acts as the intermediary, getting data from the instrumentation and sending it to multiple backends to store, process, and analyze the data.

It supports multiple open source observability data formats like Zipkin, Jaeger, Prometheus, and Fluent Bit, sending it to one or more open source or commercial backends.


#### New Relic
New Relic is a platform for you to analyze, store, and use your telemetry data for Free, forever. [Sign up now!](https://newrelic.com/signup?utm_campaign=fy20-q1-amer-obsv-video-free_code_camp-video-&utm_medium=video&utm_source=free_code_camp&utm_content=video&fiscal_year=fy20&quarter=q1&program=obsv&audience=none&creative=none&placement=none&targeting=none&ad_type=none&geo=amer)

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/692fiew3ync926gcfuw1.png)
 
#### Configuring the OpenTelemetry Collector with New Relic 
Clone the [OpenTelemetry Collector with New Relic Exporter](https://github.com/lazyplatypus/OpenTelemetry-NR-Exporter) and spin up the docker container, making sure to export the New Relic API key. 

To get a key, go to the New Relic one dashboard and choose API keys from the dropdown menu in the upper right.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kmo09xbtn40wowmno4rp.png)

Then, from the API keys window, click the Create a key button.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5h6l8j2bvt0tfmzemw2a.png)

When creating the key, make sure you choose the **Ingest - License** key type. Then click Create a key to generate the key.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/thkhp0cqaour3deyab71.png)
 
After you have an API key, you need to replace `<INSERT-API-KEY-HERE>` in the code snippet below with your API key.
 

```
export NEW_RELIC_API_KEY=<INSERT-API-KEY-HERE>
docker-compose -f docker-compose.yaml up
```

> 💡 Make sure to change the reporting URL from `http://localhost:9411/api/v2/spans` to `http://localhost:9411/` in both `dashboard.js` and `movies.js`

```diff
const zipkinExporter = new ZipkinExporter({
- url: 'http://localhost:9411/api/v2/spans',
+ url: 'http://localhost:9411',
  serviceName: 'movies-service'
})
```
# Step 5: Look at your ✨ beautiful data ✨
Navigate to the "Explorer" tab on [New Relic One](https://one.newrelic.com). 

![New Relic One Dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/im53j8pdag4sl034us77.png)
 
When you click on the service, you should be able to see some ✨beautiful✨ traces!

The trace in the dashboard is transmitting data about the random delay that was added to the API calls:

![OTel Traces](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fati4q1acf3pqn675yhz.png)


### Final Thoughts
Instrumenting your app with Open Telemetry makes it easy to figure out what is going wrong when parts of your application is slow, broken, or both. With the collector, you can forward your data anywhere, so you are never locked into a vendor. You can choose to spin up an open source backend, use a proprietary backend like New Relic, or just roll your own backend! Whatever you choose, I wish you well you in journey to instrument EVERYTHING! 

> ### Next Steps
> You can try out New Relic One with OpenTelemetry by signing up for our always free tier today.
> 
> To learn more about OpenTelemetry, look for our upcoming Understand OpenTelemetry blog series.