This page is not yet available in Spanish. We are working on its translation.
If you have any questions or feedback about our current translation project, feel free to reach out to us!
Join the Preview!

Using the Sentry SDK with Error Tracking is in Preview.

Using the Sentry SDK with Error Tracking helps you migrate to Datadog. However, to get the most out of Error Tracking, it is recommended to use the Datadog SDKs. See Frontend Error Tracking and Backend Error Tracking.

Overview

You can use Sentry SDKs to send your events to Datadog, so you can start using Error Tracking on existing applications that are instrumented using Sentry SDKs.

Setting up the Sentry SDK with Datadog requires a minimal code change to point the SDK to a Datadog Data Source Name (DSN).

Events and non-error events (messages) appear in Datadog as logs in the log explorer. Other item types (traces, attachments, sessions, etc.) are not supported.

Supported SDKs

The following Sentry SDKs are verified to work with Error Tracking:

PlatformTested version
JavaScript@sentry/node@9.13.0
@sentry/browser@9.13.0
Pythonsentry-sdk==2.26.1
Javaio.sentry:sentry:8.6.0
.NETSentry 5.5.1
Gosentry-go v0.32.0
Rubysentry-ruby 5.23.0

Setup

Prerequisites

Sentry SDK events are sent into Datadog as logs. You must have Error Tracking for Logs enabled for errors to show up in Error Tracking.

Note: By default, enabling Error Tracking for Logs enables Error Tracking on all of your logs. You can use rules to configure Error Tracking for Logs to only collect errors from the Sentry SDK. To do this, create a rule for logs with scope source:sentry-sdk, and create an exclusion rule for all other logs.

Error Tracking rules including only Logs from the Sentry SDK

Service configuration

To configure the Sentry SDK to send events into Datadog:

  1. Configure a Datadog Data Source Name (DSN). Follow the in-app instructions to generate your unique DSN.
  2. Set a service tag on all events. This is used to separate errors and is shown in the Datadog UI:
  Sentry.init({
      dsn: 'https://<TOKEN>@sentry-intake.<DD_SITE>/1',
      initialScope: {
          tags: {
              service: 'my-app'
          }
      }
  });
  
  sentry_sdk.init(
      dsn="https://<TOKEN>@sentry-intake.<DD_SITE>/1",
  )
  sentry_sdk.set_tag("service", "my-app")
  
  Sentry.init(options -> {
      options.setDsn("https://<TOKEN>@sentry-intake.<DD_SITE>/1");
  });
  Sentry.configureScope(scope -> {
      scope.setTag("service", "my-app");
  });
  
  SentrySdk.Init(options =>
  {
      options.Dsn = "https://<TOKEN>@sentry-intake.<DD_SITE>/1";
      options.SetBeforeSend((sentryEvent, hint) => {
          sentryEvent.SetTag("service", "my-app");
          return sentryEvent;
      });
  });
  
  sentry.Init(sentry.ClientOptions{
      Dsn: "https://<TOKEN>@sentry-intake.<DD_SITE>/1",
  })
  sentry.ConfigureScope(func(scope *sentry.Scope) {
      scope.SetTag("service", "my-app");
  })
  
  Sentry.init do |config|
      config.dsn = https://<TOKEN>@sentry-intake.<DD_SITE>/1'
  end
  Sentry.set_tags('service': 'my-app')
  

Upload JavaScript source maps

If your frontend JavaScript source code is minified, you can upload source maps to Datadog to deobfuscate stack traces in Error Tracking.

See Upload JavaScript Source Maps.

The version on source maps is matched with the release configured on the Sentry SDK.

Source code integration

Datadog Source Code Integration allows you to connect your telemetry with your Git repositories.

Source Code Integration works with Sentry SDKs by configuring telemetry tags:

Sentry.setTag("git.commit.sha", "<commitSha>");
Sentry.setTag("git.repository_url", "<git-provider.example/me/my-repo>");
sentry_sdk.set_tag("git.commit.sha", "<commitSha>")
sentry_sdk.set_tag("git.repository_url", "<git-provider.example/me/my-repo>")
Sentry.configureScope(scope -> {
    scope.setTag("git.commit.sha", "<commitSha>");
    scope.setTag("git.repository_url", "<git-provider.example/me/my-repo>");
});
SentrySdk.ConfigureScope(scope =>
{
    scope.SetTag("git.commit.sha", "<commitSha>");
    scope.SetTag("git.repository_url", "<git-provider.example/me/my-repo>");
});
sentry.ConfigureScope(func(scope *sentry.Scope) {
    scope.SetTag("git.commit.sha", "<commitSha>");
    scope.SetTag("git.repository_url", "<git-provider.example/me/my-repo>");
})
Sentry.set_tags('git.commit.sha', '<commitSha>')
Sentry.set_tags('git.repository_url', '<git-provider.example/me/my-repo>')

To get the most out of Error Tracking, Datadog recommends migrating to the Datadog SDK and/or Agent-based setups. See Backend Error Tracking and Frontend Error Tracking for more information.

During your migration, you can use the Sentry SDK and Datadog at the same time.

Note: Doing so may result in errors being reported twice.

From the Sentry SDK

You can configure Sentry SDKs to send events to multiple DSNs at once. On most Sentry SDKs, you can override the default transport to achieve this.

// Change to import from "@sentry/react", "@sentry/nextjs", etc. as needed
import * as Sentry from "@sentry/browser";
import { makeFetchTransport } from "@sentry/browser"; // import { makeNodeTransport } from "@sentry/node" for Node.js
import { makeMultiplexedTransport } from "@sentry/core";

const sentryDsn = '<SENTRY_DSN>';
const datadogDsn = '<DATADOG_DSN>';

Sentry.init({
  dsn: sentryDsn,
  transport: makeMultiplexedTransport(makeFetchTransport, () => [sentryDsn, datadogDsn]),
  // ...
});
Sentry.setTag('service', 'my-app');
  1. Copy the following function into your code:
from sentry_sdk.transport import Transport, make_transport
def make_multi_transport(dsns):
    class MultiTransport(Transport):
        def __init__(self, options):
            super().__init__(options)
            self.transports = [
                make_transport({**options, "dsn": dsn, "transport": None}) for dsn in dsns
            ]
        def capture_envelope(self, *args, **kwargs):
            for transport in self.transports:
                transport.capture_envelope(*args, **kwargs)
        def flush(self, *args, **kwargs):
            for transport in self.transports:
                transport.flush(*args, **kwargs)
        def kill(self):
            for transport in self.transports:
                transport.kill()
        def record_lost_event(self, *args, **kwargs):
            for transport in self.transports:
                transport.record_lost_event(*args, **kwargs)
    return MultiTransport
  1. Use as follows:
_SENTRY_DSN = "<SENTRY_DSN>"
_DATADOG_DSN = "<DATADOG_DSN>"
sentry_sdk.init(
    dsn=_SENTRY_DSN,
    transport=make_multi_transport([_SENTRY_DSN, _DATADOG_DSN]),
    # ...
)
sentry_sdk.set_tag("service", "my-app")
  1. Copy the following class into your code. Make sure to define it in the io.sentry package.
package io.sentry;

public record MultiTransportFactory(List<String> dsns) implements ITransportFactory {
  @Override
  public ITransport create(final SentryOptions options, final RequestDetails requestDetails) {
    final var transports = dsns.stream()
        .map(dsn -> {
          var requestOptions = new SentryOptions();
          requestOptions.setDsn(dsn);
          requestOptions.setSentryClientName(options.getSentryClientName());
          return new AsyncHttpTransportFactory().
              create(options, new RequestDetailsResolver(requestOptions).resolve());
        })
        .toList();
    return new ITransport() {
      @Override
      public void send(SentryEnvelope envelope, Hint hint) throws IOException {
        for (ITransport transport : transports) {
          transport.send(envelope, hint);
        }
      }

      @Override
      public boolean isHealthy() {
        return transports.stream().allMatch(ITransport::isHealthy);
      }

      @Override
      public void flush(long timeoutMillis) {
        transports.forEach(transport -> transport.flush(timeoutMillis));
      }

      @Override
      public RateLimiter getRateLimiter() {
        return null;
      }

      @Override
      public void close(boolean isRestarting) throws IOException {
        for (ITransport transport : transports) {
          transport.close(isRestarting);
        }
      }

      @Override
      public void close() throws IOException {
        for (ITransport transport : transports) {
          transport.close();
        }
      }
    };
  }
}
  1. Use as follows:
final var sentryDsn = "<SENTRY_DSN>"
final var datadogDsn = "<DATADOG_DSN>"

Sentry.init(options -> {
  options.setDsn(sentryDsn);
  options.setTransportFactory(new MultiTransportFactory(List.of(sentryDsn, datadogDsn)));
});
Sentry.setTag("service", "my-app");
  1. Copy the following snippet into your code:
type MultiTransport struct {
	dsns       []string
	transports []*sentry.HTTPTransport
}

func NewMultiTransport(dsns []string) *MultiTransport {
	transports := make([]*sentry.HTTPTransport, len(dsns))
	for i := range dsns {
		transports[i] = sentry.NewHTTPTransport()
	}
	return &MultiTransport{
		dsns:       dsns,
		transports: transports,
	}
}

func (mt *MultiTransport) Configure(options sentry.ClientOptions) {
	for i := range mt.dsns {
		options.Dsn = mt.dsns[i]
		if options.EnableTracing {
			// Replicating the default behavior:
			// https://github.com/getsentry/sentry-go/blob/v0.32.0/client.go#L358
			mt.transports[i].BufferSize = 1000
		}
		mt.transports[i].Configure(options)
	}
}

func (mt *MultiTransport) Flush(timeout time.Duration) bool {
	allDone := true
	for _, t := range mt.transports {
		if ok := t.Flush(timeout); !ok {
			allDone = false
		}
	}
	return allDone
}

func (mt *MultiTransport) SendEvent(event *sentry.Event) {
	for _, t := range mt.transports {
		t.SendEvent(event)
	}
}

func (mt *MultiTransport) Close() {
	for _, t := range mt.transports {
		t.Close()
	}
}
  1. Use as follows:
sentryDSN := "<SENTRY_DSN>"
datadogDSN := "<DATADOG_DSN>"

err := sentry.Init(sentry.ClientOptions{
	Dsn: sentryDSN,
	Transport: NewMultiTransport([]string{sentryDSN, datadogDSN}),
})
// ...
sentry.ConfigureScope(func(scope *sentry.Scope) {
	scope.SetTag("service", "my-app")
})

Using Sentry Mirror

Sentry Mirror is a proxy that replicates traffic to multiple DSNs. You run in it your own environment, and point your applications to Sentry Mirror’s inbound DSN.

Sentry Mirror is configured using a YAML file:

ip: 0.0.0.0
port: 3000
keys:
  - inbound: http://1234567890abcdef1234567890abcdef@my-domain.example/123
    outbound:
      - <SENTRY_DSN>
      - <DATADOG_DSN>

Further Reading

Más enlaces, artículos y documentación útiles:

PREVIEWING: guacbot/translation-pipeline