Send traces to Cloud Observability with Node.JS

This Quick Start guide shows you how to configure your Nodejs applications to send OpenTelemetry traces to Cloud Observability.

This guide does not provide documentation on application instrumentation. For Nodejs-specific information on instrumentation, please see the Nodejs OpenTelemetry getting started guide.

The sections below contain code snippets only. For full code listings, please see nodejs/otel-vanilla and nodejs/launcher in the Cloud Observability OpenTelemetry examples repository.

Sending OpenTelemetry data directly to Cloud Observability without a Collector for most developer setups will suffice. For non-development setups, however, it is highly recommended that you send OpenTelemetry data to Cloud Observability by way of the OpenTelemetry Collector. This can be done with or without a Launcher, as we’ll see below.

Pre-Requisites

Before you get started with sending OpenTelemetry data to Cloud Observability, you will need the following:

Install OpenTelemetry Packages

In your application code, you will need to install dependencies and import OpenTelemetry packages before you can send data to Cloud Observability.

Start by installing the Node.JS OpenTelemetry packages. Do this by opening up a terminal window and pasting the following snippet in your project directory:

1
2
3
4
5
6
7
npm install --save \
  @opentelemetry/api \
  @opentelemetry/resources \
  @opentelemetry/semantic-conventions \
  @opentelemetry/sdk-node \
  @opentelemetry/auto-instrumentations-node \
  @opentelemetry/exporter-trace-otlp-proto

gRPC or Protobuf over HTTP export may also be used. Please refer to the appropriate README for more information.

The packages installed include the core OpenTelemetry components, as well as automatic instrumentation for popular Node.JS packages.

Code Setup

Although auto-instrumentation is a great way to get started quickly with instrumenting your Node application, it is often not sufficient. In order to gain greater insights into your application code, you should also add manual instrumentation to your business logic. More on auto-instrumentation vs manual instrumentation here.

In order to manually instrument your Node code, you need to acquire a Tracer. The Tracer is responsible for creating Spans and interacting with the Context.

Import OpenTelemetry Packages

Before you can acquire a Tracer, you must first import the appropriate package. Open up your application code, and add the following import to your .js file:

Initialize OpenTelemetry

In Node.JS, it is conventional to create a tracing.js file that performs bootstrapping and initialization of OpenTelemetry.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// tracing.js

'use strict'

const process = require('process');
const opentelemetry = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-proto');

const traceExporter = new OTLPTraceExporter({
    url: "https://ingest.lightstep.com/traces/otlp/v0.9", // US data center
    // url: "https://ingest.eu.lightstep.com/traces/otlp/v0.9", // EU data center
    headers: {
        "lightstep-access-token": process.env.LIGHTSTEP_ACCESS_TOKEN,
    }
});
const sdk = new opentelemetry.NodeSDK({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'my-service',
  }),
  traceExporter,
  instrumentations: [getNodeAutoInstrumentations()]
});

// initialize the SDK and register with the OpenTelemetry API
// this enables the API to record telemetry
sdk.start()
  .then(() => console.log('Tracing initialized'))
  .catch((error) => console.log('Error initializing tracing', error));

// gracefully shut down the SDK on process exit
process.on('SIGTERM', () => {
  sdk.shutdown()
    .then(() => console.log('Tracing terminated'))
    .catch((error) => console.log('Error terminating tracing', error))
    .finally(() => process.exit(0));
});

Save this file.

Run your application

Once you have your tracing.js file, you should run your application as follows: node -r ./tracing.js app.js. The -r flag will require the tracing module that was created and ensure it runs before your application code. You will also need to configure environment variables as follows, depending on your OpenTelemetry Collector configuration:

Start tabs

Direct (OTLP/HTTP)

1
export LIGHTSTEP_ACCESS_TOKEN=<your_access_token>

Collector (OTLP/HTTP)

1
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317" #or whatever your collector URL is

End tabs

To view traces in your Cloud Observability project, click explorer in the left navigation bar, and then click on any span in the Trace Analysis table.

Troubleshooting

I can’t see data in Cloud Observability!

By default, the OpenTelemetry exporters will not print errors. You can add the following code to your tracing.js file, before configuration, to enable verbose logging.

1
2
const opentelemetryAPI = require("@opentelemetry/api");
opentelemetryAPI.diag.setLogger(new opentelemetryAPI.DiagConsoleLogger(), opentelemetryAPI.DiagLogLevel.WARN);

You can increase the verbosity of the logs with DiagLogLevel.DEBUG.

Expandable end

I want to use http/json instead of gRPC or Protobuf!

As of this writing, Cloud Observability does not support http/json for current versions of the OpenTelemetry protocol via direct ingest. Please use gRPC or Protobuf over HTTP.

We suggest using an OpenTelemetry collector to proxy your telemetry before sending it to Cloud Observability, which has no such limitation.

Expandable end

Check for multiple versions of OpenTelemetry

If multiple versions of OpenTelemetry are installed, traces are not created or propagated correctly. Check your dependencies to ensure that only a single version of OpenTelemetry is installed.

Expandable end

Check that security is configured correctly

Cloud Observability’s public Microsatellites only accept spans via a secure endpoint. If you see security related errors (e.g., Netty TLS errors with Java), you may not have the necessary root certificate installed on the machine where the tracer is running. To add a root certificate, see the documentation about encrypted connections.

Expandable end

Check that Metrics are enabled in the OpenTelemetry Collector

Not seeing metrics come through the OpenTelemetry Collector? Make sure that you have defined a Metrics pipeline in your Collector’s YAML config file.

Cloud Observability access token

See also

Send traces to Cloud Observability with Python

Send traces to Cloud Observability with Java

Send traces to Cloud Observability with .NET

Updated Sep 21, 2022