Skip to content

Express OpenTelemetry instrumentation

This guide instruments an Express application with the OpenTelemetry Node.js SDK. The auto-instrumentations capture spans for every route and outbound HTTP or database call, and the OTLP exporters send traces, metrics, and logs to Osuite.

  • Node.js 18 or newer.
  • An Express application you can start locally.
  • An Osuite ingest token from Settings → API Keys.
  1. Install the OpenTelemetry packages

    Terminal window
    npm install @opentelemetry/sdk-node \
    @opentelemetry/auto-instrumentations-node \
    @opentelemetry/exporter-trace-otlp-proto \
    @opentelemetry/exporter-metrics-otlp-proto \
    @opentelemetry/exporter-logs-otlp-proto
  2. Create the initialization module

    Create instrumentation.js in your project root. This file is loaded before your application so the auto-instrumentations can patch libraries as they are required.

    instrumentation.js
    const { NodeSDK } = require('@opentelemetry/sdk-node');
    const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
    const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-proto');
    const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-proto');
    const { OTLPLogExporter } = require('@opentelemetry/exporter-logs-otlp-proto');
    const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics');
    const { BatchLogRecordProcessor } = require('@opentelemetry/sdk-logs');
    const sdk = new NodeSDK({
    traceExporter: new OTLPTraceExporter(),
    metricReader: new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter(),
    }),
    logRecordProcessors: [new BatchLogRecordProcessor(new OTLPLogExporter())],
    instrumentations: [getNodeAutoInstrumentations()],
    });
    sdk.start();
    process.on('SIGTERM', () => {
    sdk.shutdown().finally(() => process.exit(0));
    });

    The exporters read the endpoint and token from environment variables, so this module contains no secrets and is identical across every service.

The exporters and resource are configured entirely through environment variables:

  • OTEL_EXPORTER_OTLP_ENDPOINT — your Osuite ingest endpoint.
  • OTEL_EXPORTER_OTLP_HEADERS — the x-osuite-ingest-token header that authenticates ingestion.
  • OTEL_SERVICE_NAME — the service name that identifies this service in Osuite.
  • OTEL_RESOURCE_ATTRIBUTES — additional resource attributes such as service.environment.

Load instrumentation.js before your app with node --require. Choose your deployment target:

Terminal window
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.osuite.io:443"
export OTEL_EXPORTER_OTLP_HEADERS="x-osuite-ingest-token=<your-ingest-token>"
export OTEL_SERVICE_NAME="checkout-api"
export OTEL_RESOURCE_ATTRIBUTES="service.environment=production"
node --require ./instrumentation.js server.js

What you should see

Send a request to your API, then open APM. The service appears within a minute under the service.name you set, emitting request-rate and latency metrics. Opening a trace shows the inbound Express route span with child spans for any downstream HTTP or database calls.

No data in Osuite after a few minutes? Work through these checks.

  • Endpoint — confirm the exporter targets exactly ingest.<region>.osuite.io:443 for your region, over TLS.
  • Token — confirm the ingest header carries a valid <your-ingest-token> and has not been rotated.
  • Pipeline — confirm the signal you expect (traces, logs, or metrics) is wired into an active pipeline with the otlp/osuite exporter attached.
  • Export errors — check the application or Collector logs for OTLP export failures (auth, DNS, TLS, connection refused).
  • Network — confirm the host has outbound access to the ingest endpoint on port 443.
  • Timing — allow up to a minute for the first data to appear before assuming a failure.

Still stuck? Ask the Investigation Agent or contact support.

For Node-specific issues — ESM vs CommonJS loading, the --require flag, or missing spans — see Node.js troubleshooting.