Skip to main content

Instrument a Node.js app for traces

The AtherOps agent receives traces over OTLP -- it does not inject tracing into a running Node.js process on its own. You load the OpenTelemetry Node.js SDK at process startup, and it auto-instruments popular frameworks (Express, Fastify, HTTP, gRPC, and others) without code changes.

If you haven't read Metrics/logs vs APM traces yet, that page explains why detection of a Node.js process does not automatically produce traces.

Prerequisites

  • The AtherOps agent is installed and running on the host.
  • collection.traces.enabled: true is set in /etc/atherops/config.yaml (this is the default).
  • Node.js 14 or later.

Step 1: Install the SDK packages

npm install --save \
@opentelemetry/sdk-node \
@opentelemetry/auto-instrumentations-node \
@opentelemetry/exporter-trace-otlp-http

The auto-instrumentations-node package bundles instrumentation for the most common Node.js libraries. If you only need specific libraries you can install individual @opentelemetry/instrumentation-* packages instead.

Step 2: Load the SDK at startup

The simplest path uses the --require flag so no source changes are needed:

export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_SERVICE_NAME=my-node-service
export NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register"

node app.js

Or as a single command:

OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
OTEL_SERVICE_NAME=my-node-service \
node --require @opentelemetry/auto-instrumentations-node/register app.js

If you want explicit control over which instrumentations are active, create a tracing.js file:

const { NodeSDK } = require('@opentelemetry/sdk-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');

const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({
url: 'http://localhost:4318/v1/traces',
}),
instrumentations: [getNodeAutoInstrumentations()],
serviceName: 'my-node-service',
});

sdk.start();

Then load it:

node --require ./tracing.js app.js

Step 3: Verify spans are reaching AtherOps

Generate some traffic, then query:

curl -s \
-H "Authorization: Bearer $ATHEROPS_JWT" \
"https://api.atherops.com/query/traces?service=my-node-service&limit=10"

A non-empty JSON array means spans are flowing. See Enable traces: verify spans reached AtherOps for details on the query parameters and how to obtain the bearer token.

Choosing the OTLP endpoint

Both gRPC (port 4317) and HTTP/protobuf (port 4318) work. To use gRPC, install @opentelemetry/exporter-trace-otlp-grpc instead and set:

export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc

Troubleshooting

No spans appear after startup. Check the agent log:

journalctl -u atherops-otel-agent --since "5 min ago" | grep -i error

If there are no errors in the agent log, the SDK is likely not loaded -- confirm --require is present in your startup command and that @opentelemetry/auto-instrumentations-node is listed in node_modules.

Cannot find module '@opentelemetry/auto-instrumentations-node/register'. The register export was added in version 0.39.0. Run npm ls @opentelemetry/auto-instrumentations-node to check your installed version and upgrade if needed.

Spans appear in the agent log path but with forward traces failed. The agent is receiving spans but cannot reach AtherOps. Check the AtherOps platform URL in /etc/atherops/config.yaml and verify network connectivity from the host.

Further reading