diff --git a/samples/Sentry.Samples.OpenTelemetry.Console/Program.cs b/samples/Sentry.Samples.OpenTelemetry.Console/Program.cs
index 3371ec0cde..9438978130 100644
--- a/samples/Sentry.Samples.OpenTelemetry.Console/Program.cs
+++ b/samples/Sentry.Samples.OpenTelemetry.Console/Program.cs
@@ -6,25 +6,47 @@
*/
using OpenTelemetry;
-using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using Sentry.OpenTelemetry;
-var serviceName = "Sentry.Samples.OpenTelemetry.Console";
-var serviceVersion = "1.0.0";
+var activitySource = Sentry.OpenTelemetry.TracerProviderBuilderExtensions.DefaultActivitySource;
SentrySdk.Init(options =>
{
// options.Dsn = "... Your DSN ...";
+ options.Dsn = "https://eb18e953812b41c3aeb042e666fd3b5c@o447951.ingest.sentry.io/5428537";
options.TracesSampleRate = 1.0;
options.UseOpenTelemetry(); // <-- Configure Sentry to use OpenTelemetry trace information
});
-using var tracerProvider = Sdk.CreateTracerProviderBuilder()
- .AddSource(serviceName)
- .ConfigureResource(resource =>
- resource.AddService(
- serviceName: serviceName,
- serviceVersion: serviceVersion))
- .AddSentry() // <-- Configure OpenTelemetry to send traces to Sentry
- .Build();
+// using var tracerProvider = Sdk.CreateTracerProviderBuilder()
+// .AddSentry() // <-- Configure OpenTelemetry to send traces to Sentry
+// .Build();
+
+Console.WriteLine("Hello World!");
+Question();
+Console.WriteLine("Goodbye cruel world...");
+
+void Question()
+{
+ using var disposable = SentrySdk.PushScope();
+ SentrySdk.ConfigureScope(scope =>
+ {
+ scope.AddBreadcrumb("Asking the question...");
+ scope.SetTag("Question", "Meaning of life");
+ using var task = activitySource.StartActivity("Question");
+ Thread.Sleep(100); // simulate some work
+ Answer();
+ });
+}
+
+void Answer()
+{
+ SentrySdk.ConfigureScope(scope =>
+ {
+ scope.AddBreadcrumb("Giving the answer...");
+ scope.SetTag("Answer", "42");
+ using var task = activitySource.StartActivity("Answer");
+ Thread.Sleep(100); // simulate some work
+ });
+}
diff --git a/src/Sentry.OpenTelemetry/InternalTracerProvider.cs b/src/Sentry.OpenTelemetry/InternalTracerProvider.cs
new file mode 100644
index 0000000000..f94fd88422
--- /dev/null
+++ b/src/Sentry.OpenTelemetry/InternalTracerProvider.cs
@@ -0,0 +1,76 @@
+using OpenTelemetry;
+using OpenTelemetry.Trace;
+using Sentry.Extensibility;
+
+namespace Sentry.OpenTelemetry;
+
+internal static class InternalTracerProvider
+{
+ internal static IHub? FallbackHub;
+ private static TracerProvider? FallbackTracerProvider;
+ private static bool WasInitializedExternally;
+
+ internal static bool InitializedExternally
+ {
+ get => WasInitializedExternally;
+ set
+ {
+ if (value)
+ {
+ ClearProvider();
+ }
+
+ WasInitializedExternally = value;
+ }
+ }
+
+ public static void InitializeFallbackTracerProvider(this SentryOptions options)
+ {
+ try
+ {
+ ClearProvider();
+ // This is a dummy/naive example. It works for something like a Console app. Wiring up an ASP.NET Core app
+ // should be done using the OpenTelemetryBuilder extensions... If we knew OpenTelemetry was being used as
+ // the trace implementation, we could do something like this in the SentryOptions class, rather than in an
+ // extension method, and override it in SentryAspNetCoreOptions etc. to be platform specific.
+ options.PostInitCallbacks.Add(hub =>
+ {
+ FallbackHub = hub;
+ FallbackTracerProvider = Sdk.CreateTracerProviderBuilder()
+ .AddSentryInternal(true) // <-- Configure OpenTelemetry to send traces to Sentry
+ .Build();
+ });
+ }
+ catch (InternalTracerProviderException)
+ {
+ options.LogDebug("OpenTelemetry has been initialized externally: skipping auto-initialization");
+ }
+ }
+
+ public static void CancelInitialization()
+ {
+ throw new InternalTracerProviderException();
+ }
+
+ public static void ClearProvider()
+ {
+ FallbackHub = null;
+ FallbackTracerProvider?.Dispose();
+ FallbackTracerProvider = null;
+ }
+
+ internal class InternalTracerProviderException : Exception
+ {
+ public InternalTracerProviderException(string message) : base(message)
+ {
+ }
+
+ public InternalTracerProviderException() : base()
+ {
+ }
+
+ public InternalTracerProviderException(string? message, Exception? innerException) : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/src/Sentry.OpenTelemetry/SentryOptionsExtensions.cs b/src/Sentry.OpenTelemetry/SentryOptionsExtensions.cs
index 2035787a19..3614c7726f 100644
--- a/src/Sentry.OpenTelemetry/SentryOptionsExtensions.cs
+++ b/src/Sentry.OpenTelemetry/SentryOptionsExtensions.cs
@@ -1,5 +1,7 @@
+using OpenTelemetry;
using OpenTelemetry.Context.Propagation;
using OpenTelemetry.Trace;
+using Sentry.Extensibility;
namespace Sentry.OpenTelemetry;
@@ -53,5 +55,6 @@ public static void UseOpenTelemetry(this SentryOptions options)
options.AddTransactionProcessor(
new OpenTelemetryTransactionProcessor()
);
+ options.InitializeFallbackTracerProvider();
}
}
diff --git a/src/Sentry.OpenTelemetry/TracerProviderBuilderExtensions.cs b/src/Sentry.OpenTelemetry/TracerProviderBuilderExtensions.cs
index 96472eda98..5135cf398c 100644
--- a/src/Sentry.OpenTelemetry/TracerProviderBuilderExtensions.cs
+++ b/src/Sentry.OpenTelemetry/TracerProviderBuilderExtensions.cs
@@ -11,6 +11,11 @@ namespace Sentry.OpenTelemetry;
///
public static class TracerProviderBuilderExtensions
{
+ ///
+ /// The default for spans created by Sentry's instrumentation
+ ///
+ public static readonly ActivitySource DefaultActivitySource = new("Sentry");
+
///
/// Ensures OpenTelemetry trace information is sent to Sentry.
///
@@ -29,6 +34,22 @@ public static class TracerProviderBuilderExtensions
/// The supplied for chaining.
public static TracerProviderBuilder AddSentry(this TracerProviderBuilder tracerProviderBuilder, TextMapPropagator? defaultTextMapPropagator = null)
{
+ return tracerProviderBuilder.AddSentryInternal(false, defaultTextMapPropagator);
+ }
+
+ internal static TracerProviderBuilder AddSentryInternal(this TracerProviderBuilder tracerProviderBuilder, bool autoInitialized = false, TextMapPropagator? defaultTextMapPropagator = null)
+ {
+ // Don't automatically initialize if the user has already initialized
+ if (autoInitialized && InternalTracerProvider.InitializedExternally)
+ {
+ InternalTracerProvider.CancelInitialization();
+ }
+ if (!autoInitialized)
+ {
+ InternalTracerProvider.InitializedExternally = true;
+ }
+ tracerProviderBuilder.AddSource(DefaultActivitySource.Name);
+
defaultTextMapPropagator ??= new SentryPropagator();
Sdk.SetDefaultTextMapPropagator(defaultTextMapPropagator);
return tracerProviderBuilder.AddProcessor(ImplementationFactory);
@@ -45,7 +66,7 @@ internal static BaseProcessor ImplementationFactory(IServiceProvider s
enrichers.Add(new AspNetCoreEnricher(userFactory));
}
- var hub = services.GetService() ?? SentrySdk.CurrentHub;
+ var hub = services.GetService() ?? InternalTracerProvider.FallbackHub ?? SentrySdk.CurrentHub;
if (hub.IsEnabled)
{
return new SentrySpanProcessor(hub, enrichers);