---
title: "OpenTelemetry Support"
description: "Using OpenTelemetry with Sentry Performance."
url: https://docs.sentry.io/platforms/go/guides/negroni/tracing/instrumentation/opentelemetry/
---

# OpenTelemetry Support | Sentry for Negroni

You can configure your [OpenTelemetry SDK](https://opentelemetry.io/) to send traces to Sentry over OTLP.

##### Span Processor Deprecation

The legacy `sentryotel.NewSentrySpanProcessor()` integration is deprecated in `sentry-go`. Prefer OTLP export instead: use `sentryotlp.NewTraceExporter()` to send traces directly to Sentry, or use a standard OpenTelemetry exporter if you're sending data through an OpenTelemetry Collector.

## [Install](https://docs.sentry.io/platforms/go/guides/negroni/tracing/instrumentation/opentelemetry.md#install)

OpenTelemetry integration was added in `sentry-go` version 0.18.0, and works only for Go >= 1.18.

The Sentry Go OpenTelemetry integration requires `go.opentelemetry.io/otel` (and its submodules), version `1.11.0` or higher.

Install the `otel` and `otel/otlp` modules in addition to the main SDK:

```bash
go get github.com/getsentry/sentry-go \
       github.com/getsentry/sentry-go/otel \
       github.com/getsentry/sentry-go/otel/otlp
```

## [Usage](https://docs.sentry.io/platforms/go/guides/negroni/tracing/instrumentation/opentelemetry.md#usage)

Create a trace exporter and register Sentry's OTel integration:

```go
import (
	"context"
	"go.opentelemetry.io/otel"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"

	"github.com/getsentry/sentry-go"
	sentryotel "github.com/getsentry/sentry-go/otel"
	sentryotlp "github.com/getsentry/sentry-go/otel/otlp"
	// ...
)

sentry.Init(sentry.ClientOptions{
	Dsn:              "___PUBLIC_DSN___",
	EnableTracing:    true,
	TracesSampleRate: 1.0,
	Debug:            true,
	Integrations: func(integrations []sentry.Integration) []sentry.Integration {
		return append(integrations, sentryotel.NewOtelIntegration())
	},
})

ctx := context.Background()
exporter, err := sentryotlp.NewTraceExporter(ctx, "___PUBLIC_DSN___")
if err != nil {
	panic(err)
}

tp := sdktrace.NewTracerProvider(
	sdktrace.WithBatcher(exporter),
)
otel.SetTracerProvider(tp)
```

Now, spans produced by OpenTelemetry will be exported to Sentry over OTLP.

### [Distributed Tracing](https://docs.sentry.io/platforms/go/guides/negroni/tracing/instrumentation/opentelemetry.md#distributed-tracing)

The OTLP integration does not set up a propagator for you. How you configure propagation depends on your setup:

* **Sentry frontend → OTel backend:** If a Sentry SDK on your frontend sends requests to this OTel-instrumented service, enable [`propagateTraceparent`](https://docs.sentry.io/concepts/otlp/sentry-with-otel.md#linking-sentry-and-otlp-traces) in your frontend SDK. This sends the W3C `traceparent` header, which your OTel-instrumented backend will pick up automatically.
* **OTel ↔ OTel:** If all your services use OpenTelemetry, configure propagators using the standard OpenTelemetry API (for example, `propagation.TraceContext{}`). See the [OpenTelemetry propagation documentation](https://opentelemetry.io/docs/languages/go/instrumentation/#propagators-and-context) for details.

If you're exporting through an OpenTelemetry Collector instead of sending traces directly to Sentry, you only need to keep the same `sentry.Init(...)` with `sentryotel.NewOtelIntegration()` in your Go app. Then configure the collector's `otlphttp` exporter to send traces to Sentry's OTLP endpoints. See the [OpenTelemetry Collector](https://docs.sentry.io/concepts/otlp/forwarding/pipelines/collector.md) guide.

### [Linking Errors to Transactions](https://docs.sentry.io/platforms/go/guides/negroni/tracing/instrumentation/opentelemetry.md#linking-errors-to-transactions)

To link errors and messages captured by the Sentry SDK to the active trace in the UI, pass the current OpenTelemetry-enhanced context in the `EventHint`:

```go
hub := sentry.CurrentHub()
//// or:
// hub := sentry.GetHubFromContext(ctx)
client, scope := hub.Client(), hub.Scope()
client.CaptureException(
	errors.New("new error"),
	&sentry.EventHint{Context: ctx},
	scope,
)
```

Events captured with the high-level `sentry.CaptureException` or `sentry.CaptureMessage` functions are not linked unless the active context is included in the event hint.

## [OpenTelemetry and Sentry](https://docs.sentry.io/platforms/go/guides/negroni/tracing/instrumentation/opentelemetry.md#opentelemetry-and-sentry)

With the OTLP-based setup, your OpenTelemetry spans are exported to Sentry using the standard OpenTelemetry trace pipeline instead of being converted locally by a Sentry span processor. Root spans show up in Sentry as transactions, child spans appear under those transactions, and the full trace remains connected across services.

If you also want captured Sentry errors to be linked to the active OpenTelemetry trace, register `sentryotel.NewOtelIntegration()` in `sentry.Init` and capture errors with an `EventHint` that includes the active `context.Context`.

If you're using an OpenTelemetry Collector, you don't need `sentryotlp.NewTraceExporter()`. Keep `sentryotel.NewOtelIntegration()` in your Sentry SDK setup, then configure the collector's `otlphttp` exporter to send traces to Sentry's OTLP endpoints. For the collector configuration, see the [OpenTelemetry Collector](https://docs.sentry.io/concepts/otlp/forwarding/pipelines/collector.md) guide.

## [Additional Configuration](https://docs.sentry.io/platforms/go/guides/negroni/tracing/instrumentation/opentelemetry.md#additional-configuration)

If you need more fine grained control over Sentry, take a look at the [Configuration page](https://docs.sentry.io/platforms/go/guides/negroni/configuration.md). In case you'd like to filter out transactions before sending them to Sentry (to get rid of health checks, for example), you may find the [Filtering page](https://docs.sentry.io/platforms/go/guides/negroni/configuration/filtering.md#filtering-transaction-events) helpful.
