Skip to content

Fastify OpenTelemetry instrumentation

This guide instruments a Fastify server with the OpenTelemetry Node.js SDK. The auto-instrumentations capture spans for every route, hook, and outbound call, and the OTLP exporters send traces, metrics, and logs to Osuite.

  • Node.js 18 or newer.
  • Fastify 4 or newer.
  • 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

    The Fastify instrumentation (@opentelemetry/instrumentation-fastify) is included in the auto-instrumentations bundle, so there is nothing extra to add.

  2. Create the initialization module

    Create instrumentation.js in your project root. It is loaded before your application so the auto-instrumentations can patch Fastify as it is 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 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="orders-api"
export OTEL_RESOURCE_ATTRIBUTES="service.environment=production"
node --require ./instrumentation.js server.js

What you should see

Send a request to your server, 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 Fastify request span with child spans for route hooks and any downstream 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.