OpenTelemetry Support

Using OpenTelemetry with Sentry Performance.

The Sentry SDK uses OpenTelemetry under the hood. This means that any OpenTelemetry instrumentation that emits spans will automatically be picked up by Sentry - no further configuration needed! To start using Sentry and OpenTelemetry together, set up Tracing and Performance Monitoring with your Sentry SDK.

While the Sentry SDK includes some OpenTelemetry instrumentation out of the box, you may want to add additional instrumentation to your application. This can be done by registering the instrumentation through OpenTelemetry like this:

Copied
const Sentry = require("@sentry/node");
const {
  GenericPoolInstrumentation,
} = require("@opentelemetry/instrumentation-generic-pool");

Sentry.init({
  dsn: "__DSN__",

  // The SentrySampler will use this to determine which traces to sample
  tracesSampleRate: 1.0,
});

// Afterwards, you can add additional instrumentation:
Sentry.addOpenTelemetryInstrumentation(new GenericPoolInstrumentation());

Any instrumentation added like this will be automatically picked up by Sentry.

If you already have OpenTelemetry set up yourself, you can also use your existing setup.

This setup is only needed if you need to add custom span processors or exporters to your OpenTelemetry setup. Most Sentry users can follow standard SDK setup to get OpenTelemetry data with their SDK.

In this case, you need to set skipOpenTelemetrySetup: true in your init({}) config, and ensure you setup all the components that Sentry needs yourself. In this case, you need to install @sentry/opentelemetry, and add the following:

Copied
const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node");
const Sentry = require("@sentry/node");
const {
  SentrySpanProcessor,
  SentryPropagator,
  SentrySampler,
} = require("@sentry/opentelemetry");

const sentryClient = Sentry.init({
  dsn: "__DSN__",
  skipOpenTelemetrySetup: true,

  // The SentrySampler will use this to determine which traces to sample
  tracesSampleRate: 1.0,
});

// Note: This could be BasicTracerProvider or any other provider depending on
// how you are using the OpenTelemetry SDK
const provider = new NodeTracerProvider({
  // We need our sampler to ensure the correct subset of traces is sent to Sentry
  sampler: sentryClient ? new SentrySampler(sentryClient) : undefined,
});

// We need a custom span processor
provider.addSpanProcessor(new SentrySpanProcessor());

// We need a custom propagator and context manager
provider.register({
  propagator: new SentryPropagator(),
  contextManager: new Sentry.SentryContextManager(),
});

// Validate that the setup is correct
Sentry.validateOpenTelemetrySetup();

We recommend using Sentry.startSpan() and related APIs to create spans. However, you can also use native OpenTelemetry APIs to create spans.

You can access the tracer Sentry uses via client.tracer and then create spans with OpenTelemetry APIs, as shown below:

Copied
const Sentry = require("@sentry/node");

const tracer = Sentry.getClient()?.tracer;
// Now you can use native APIs on the tracer:
tracer.startActiveSpan("span name", () => {
  // measure something
});

You can also use any other tracer; all OpenTelemetry spans will be picked up by Sentry automatically.

We recommend using SentrySampler as this will ensure the correct subset of traces is sent to Sentry depending on your tracesSampleRate, as well as that all other Sentry features like trace propagation work as expected. If you however need to use your own sampler then make sure to wrap your SamplingResult with our wrapSamplingDecision method:

custom-sampler.js
Copied
const { wrapSamplingDecision } = require("@sentry/opentelemetry");

// implements Sampler from "@opentelemetry/sdk-trace-node"
class CustomSampler {
  shouldSample(
    context,
    _traceId,
    _spanName,
    _spanKind,
    attributes,
    _links
  ) {
    const decision = yourDecisionLogic();
    
    // wrap the result
    return wrapSamplingDecision({
      decision,
      context,
      spanAttributes: attributes,
    });
  }

  toString() {
    return CustomSampler.name;
  }
}

module.exports = CustomSampler;

Now use your sampler in your TraceProvider:

instrument.js
Copied
const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node");
const Sentry = require("@sentry/node");
const {
  SentrySpanProcessor,
  SentryPropagator,
  SentrySampler,
} = require("@sentry/opentelemetry");
const CustomSampler = require("./custom-sampler");

const sentryClient = Sentry.init({
  dsn: "__DSN__",
  skipOpenTelemetrySetup: true,
  
  // By defining any sample rate,
  // tracing intergations will be added by default
  tracesSampleRate: 0
});


const provider = new NodeTracerProvider({
  sampler: new CustomSampler(sentryClient),
});

// ...rest of your setup

// Validate that the setup is correct
Sentry.validateOpenTelemetrySetup();
Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").