Instrument Node.js applications with OpenTelemetry
This guide shows how to instrument your Nodejs application with OpenTelemetry and export the traces to Dynatrace.
- To learn more about how Dynatrace works with OpenTelemetry, see Send data to Dynatrace with OpenTelemetry.
- To learn how to export the metrics to Dynatrace with OpenTelemetry Instrument Node.js applications with OpenTelemetry Metrics.
Prerequisites
- Dynatrace version 1.222+
- Send W3C Trace Context HTTP headers is turned on (default setting). To verify this setting
- From the Dynatrace menu, go to Settings > Server-side service monitoring > Deep monitoring > Distributed tracing.
- Make sure Send W3C Trace Context HTTP headers is turned on.
Overview
To monitor your Nodejs application with OpenTelemetry you need to
Instrument your application
Send the data to Dynatrace
Configure context propagation
Verify that the traces are ingested into Dynatrace
Configure data capturing to meet privacy requirements
Instrument your application
You can use automatic instrumentation (provided by OpenTelemetry) or instrument manually.
To instrument automatically, install the following packages:
npm install @opentelemetry/api
npm install @opentelemetry/auto-instrumentations-node
npm install @opentelemetry/sdk-trace-base
npm install @opentelemetry/sdk-node
To instrument manually, install the packages below and add the code snippet below to any Nodejs method you want to monitor. Set names for the tracer, the span, and add attributes as you see fit.
npm install @opentelemetry/api
npm install @opentelemetry/sdk-trace-base
npm install @opentelemetry/sdk-node
const opentelemetry = require('@opentelemetry/api');
const span = opentelemetry.trace.getTracer('my-tracer').startSpan('my-span'); //TODO Add names for tracer and span
span.setAttribute('my-key-1', 'my-value-1'); //TODO Add attributes
//TODO your code goes here
span.end();
Send data to Dynatrace
To send data to Dynatrace, the following tracing setup and configuration should be run before your application code.
Create a file with a name like opentelemetry.js
, which will contain your tracing setup code.
/* opentelemetry.js */
const opentelemetry = require("@opentelemetry/sdk-node");
const { getNodeAutoInstrumentations } = require("@opentelemetry/auto-instrumentations-node"); //TODO remove this line when using the manual instrumentation
const { AlwaysOnSampler } = require("@opentelemetry/sdk-trace-base");
const sdk = new opentelemetry.NodeSDK({
sampler: new AlwaysOnSampler(),
instrumentations: [getNodeAutoInstrumentations()] //TODO remove this line when using the manual instrumentation
});
sdk.start();
To pass Resource Attributes into your traces, you need to set them as environment variables separately.
In this example, we set the service.name as node-quickstart
and the service.version as 1.0.1
.
export OTEL_RESOURCE_ATTRIBUTES=service.version=1.0.1,service.name=node-quickstart
The following extra packages are required:
npm install @opentelemetry/exporter-trace-otlp-proto
npm install @opentelemetry/resources
npm install @opentelemetry/semantic-conventions
npm install properties-reader
/* opentelemetry.js */
const fs = require('fs');
const opentelemetry = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); //TODO remove this line when using the manual instrumentation
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
const { OTLPTraceExporter } = require("@opentelemetry/exporter-trace-otlp-proto");
const { AlwaysOnSampler } = require("@opentelemetry/sdk-trace-base");
const propertiesReader = require('properties-reader');
const OTLPoptions = {
url: '<URL>', //TODO Replace <URL> to your SaaS/Managed-URL as mentioned in the next step
headers: {
Authorization: 'Api-Token <TOKEN>' //TODO Replace <TOKEN> with your API Token as mentioned in the next step
},
};
let dtmetadata = new Resource({})
for (let name of ['dt_metadata_e617c525669e072eebe3d0f08212e8f2.properties', '/var/lib/dynatrace/enrichment/dt_metadata.properties']) {
try {
dtmetadata = dtmetadata.merge(new Resource(name.startsWith('/var') ? propertiesReader(name).getAllProperties() : propertiesReader(fs.readFileSync(name).toString()).getAllProperties()))
} catch { }
};
const otlpExporter = new OTLPTraceExporter(OTLPoptions);
const sdk = new opentelemetry.NodeSDK({
sampler: new AlwaysOnSampler(),
traceExporter: otlpExporter,
instrumentations: [getNodeAutoInstrumentations()], //TODO remove this line when using the manual instrumentation
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'nodejs-quickstart', //TODO Replace with the name of your application
[SemanticResourceAttributes.SERVICE_VERSION]: '1.0.1', //TODO Replace with the version of your application
}).merge(dtmetadata),
});
sdk.start();
Lastly, you need to define the correct endpoint and token, to make sure your data arrives where it should be.
- To set the endpoint:
- Use your Environment ID to set the endpoint to which your app will send traces as follows:
- Dynatrace SaaS
https://{your-environment-id}.live.dynatrace.com/api/v2/otlp/v1/traces
- Dynatrace Managed
https://{your-domain}/e/{your-environment-id}/api/v2/otlp/v1/traces
- Dynatrace ActiveGate
https://{your-activegate-endpoint}/e/{your-environment-id}/api/v2/otlp/v1/traces
- You may need to include the port to your ActiveGate endpoint. For example:
https://{your-activegate-endpoint}:9999/e/{your-environment-id}/api/v2/otlp/v1/traces
- If you are running a containerized ActiveGate, you need to use the FQDN of it. For example:
https://{your-activegate-service-name}.dynatrace.svc.cluster.local/e/{your-environment-id}/api/v2/otlp/v1/traces
- You may need to include the port to your ActiveGate endpoint. For example:
- Dynatrace SaaS
- Replace
<URL>
in the code snippet above with your endpoint.
- Use your Environment ID to set the endpoint to which your app will send traces as follows:
- To create an authentication token
- In the Dynatrace menu, go to Access tokens and select Generate new token.
- Provide a Token name.
- In the Search scopes box, search for
Ingest OpenTelemetry traces
and select the checkbox. - Select Generate token.
- Select Copy to copy the token to your clipboard.
- Save the token in a safe place; you can't display it again.
- Replace
<TOKEN>
in the code snippet above with your token.
Now you can run the application as you normally would, but you can use the --require
flag to load the tracing code before the application code.
Linux:
node --require './opentelemetry.js' app.js
Windows:
node --require .\opentelemetry.js app.js
Configure context propagation optional
If you use manual instrumentation or a framework that is not supported by OpenTelemetry, you need to configure context propagation.
If your application receives a request or it calls other applications, you need to configure context propagation to make sure the spans are linked together.
- Whenever receiving an incoming request, you need to extract the parent context and create the new span as a child of it.
const remoteCtx = opentelemetry.propagation.extract(ROOT_CONTEXT, req.headers); //Extract context from incoming headers
const serverSpan = opentelemetry.trace.getTracer('my-server-tracer').startSpan( //TODO Replace with the name of your tracer
'my-server-span', { //TODO Replace with the name of your span
kind: SpanKind.SERVER,
attributes: {
'my-server-key-1': 'my-server-value-1', //TODO Add attributes
},
},
remoteCtx //Pass the extracted context
);
serverSpan.end(); //End the span
- If your application calls another service, you need to ensure that you propagate the context by adding it to your outgoing request.
const ctx = opentelemetry.trace.setSpan( //Set the span active, add active context
opentelemetry.context.active(),
serverSpan //Active span
);
let my_headers = {};
opentelemetry.propagation.inject(ctx, my_headers); //Inject the new context into headers
let response = await axios.get(URL, {headers: my_headers}); //Pass the new headers as config object to the outgoing call
// Your code goes here
serverSpan.end(); //End the span
Verify that the traces are ingested into Dynatrace
A few minutes after restarting your app, look for your spans:
- In the Dynatrace menu, go to Distributed traces and select the Ingested traces tab.
- If you use OneAgent, go to Distributed traces and select the PurePaths tab.
- Your spans will be part of an existing PurePath, if the root of your call is already monitored by OneAgent.
If your application does not receive any traffic, there will be no traces.
Configure data capture to meet privacy requirements optional
While Dynatrace automatically captures all OpenTelemetry resource and span attributes, only attribute values specified in the allowlist are stored and displayed in the Dynatrace web UI. This prevents accidental storage of personal data, so you can meet your privacy requirements and control the amount of monitoring data that's stored.
To view your custom span attributes, you need to allow them in the Dynatrace web UI first:
- Span attributes In the Dynatrace menu, go to Settings and select Server-side service monitoring > Span attributes.
- Resource attributes In the Dynatrace menu, go to Settings and select Server-side service monitoring > Resource attributes.