diff --git a/CHANGELOG.md b/CHANGELOG.md index 54ed60add3..035c44901d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased + +- Added `SentryOptions.DisableSentryHttpMessageHandler`. Useful if you're using `OpenTelemetry.Instrumentation.Http` and ending up with duplicate spans. ([#3879](https://github.com/getsentry/sentry-dotnet/pull/3879)) + ## 5.0.1 ### Fixes diff --git a/src/Sentry.Extensions.Logging/SentryHttpMessageHandlerBuilderFilter.cs b/src/Sentry.Extensions.Logging/SentryHttpMessageHandlerBuilderFilter.cs index f35cad05d9..7cbc7ebc54 100644 --- a/src/Sentry.Extensions.Logging/SentryHttpMessageHandlerBuilderFilter.cs +++ b/src/Sentry.Extensions.Logging/SentryHttpMessageHandlerBuilderFilter.cs @@ -14,7 +14,8 @@ public Action Configure(Action { var hub = _getHub(); - if (!handlerBuilder.AdditionalHandlers.Any(h => h is SentryHttpMessageHandler)) + var enableHandler = hub.GetSentryOptions()?.DisableSentryHttpMessageHandler == false; + if (enableHandler && !handlerBuilder.AdditionalHandlers.Any(h => h is SentryHttpMessageHandler)) { handlerBuilder.AdditionalHandlers.Add( new SentryHttpMessageHandler(hub) diff --git a/src/Sentry/BindableSentryOptions.cs b/src/Sentry/BindableSentryOptions.cs index 46d3ec7711..cd9e5cc8d8 100644 --- a/src/Sentry/BindableSentryOptions.cs +++ b/src/Sentry/BindableSentryOptions.cs @@ -48,6 +48,7 @@ internal partial class BindableSentryOptions public TimeSpan? AutoSessionTrackingInterval { get; set; } public bool? AutoSessionTracking { get; set; } public bool? UseAsyncFileIO { get; set; } + public bool? DisableSentryHttpMessageHandler { get; set; } public bool? JsonPreserveReferences { get; set; } public bool? EnableSpotlight { get; set; } public string? SpotlightUrl { get; set; } @@ -94,6 +95,7 @@ public void ApplyTo(SentryOptions options) options.AutoSessionTrackingInterval = AutoSessionTrackingInterval ?? options.AutoSessionTrackingInterval; options.AutoSessionTracking = AutoSessionTracking ?? options.AutoSessionTracking; options.UseAsyncFileIO = UseAsyncFileIO ?? options.UseAsyncFileIO; + options.DisableSentryHttpMessageHandler = DisableSentryHttpMessageHandler ?? options.DisableSentryHttpMessageHandler; options.JsonPreserveReferences = JsonPreserveReferences ?? options.JsonPreserveReferences; options.EnableSpotlight = EnableSpotlight ?? options.EnableSpotlight; options.SpotlightUrl = SpotlightUrl ?? options.SpotlightUrl; diff --git a/src/Sentry/SentryHttpMessageHandler.cs b/src/Sentry/SentryHttpMessageHandler.cs index db409c9132..f75f958b8a 100644 --- a/src/Sentry/SentryHttpMessageHandler.cs +++ b/src/Sentry/SentryHttpMessageHandler.cs @@ -5,7 +5,8 @@ namespace Sentry; /// -/// Special HTTP message handler that can be used to propagate Sentry headers and other contextual information. +/// Special HTTP message handler that can be used to propagate Sentry headers and other contextual information. Will +/// also create events for failed requests if is enabled. /// public class SentryHttpMessageHandler : SentryMessageHandler { diff --git a/src/Sentry/SentryOptions.cs b/src/Sentry/SentryOptions.cs index 127cc4bf11..be6d9eaa57 100644 --- a/src/Sentry/SentryOptions.cs +++ b/src/Sentry/SentryOptions.cs @@ -1066,6 +1066,14 @@ public StackTraceMode StackTraceMode /// internal Instrumenter Instrumenter { get; set; } = Instrumenter.Sentry; + /// + /// + /// Set to `true` to prevents Sentry from automatically registering . + /// + /// Defaults to `false`. Should be set to `true` when using the OpenTelemetry.Instrumentation.Http. + /// + public bool DisableSentryHttpMessageHandler { get; set; } = false; + /// /// Adds a to be used when serializing or deserializing /// objects to JSON with this SDK. For example, when custom context data might use diff --git a/test/Sentry.Extensions.Logging.Tests/SentryHttpMessageHandlerBuilderFilterTests.cs b/test/Sentry.Extensions.Logging.Tests/SentryHttpMessageHandlerBuilderFilterTests.cs new file mode 100644 index 0000000000..ee3e59fff6 --- /dev/null +++ b/test/Sentry.Extensions.Logging.Tests/SentryHttpMessageHandlerBuilderFilterTests.cs @@ -0,0 +1,54 @@ +using Microsoft.Extensions.Http; + +namespace Sentry.Extensions.Logging.Tests; + +public class SentryHttpMessageHandlerBuilderFilterTests +{ + [SkippableFact] + public void Configure_HandlerEnabled_ShouldAddSentryHttpMessageHandler() + { +#if __ANDROID__ + Skip.If(true, "Can't create proxies for classes without parameterless constructors on Android"); +#endif + + // Arrange + var hub = Substitute.For(); + SentryClientExtensions.SentryOptionsForTestingOnly = new SentryOptions { DisableSentryHttpMessageHandler = false }; + + var filter = new SentryHttpMessageHandlerBuilderFilter(() => hub); + var handlerBuilder = Substitute.For(); + handlerBuilder.AdditionalHandlers.Returns(new List()); + Action next = _ => { }; + + // Act + var configure = filter.Configure(next); + configure(handlerBuilder); + + // Assert + handlerBuilder.AdditionalHandlers.Should().ContainSingle(h => h is SentryHttpMessageHandler); + } + + [SkippableFact] + public void Configure_HandlerDisabled_ShouldNotAddSentryHttpMessageHandler() + { +#if __ANDROID__ + Skip.If(true, "Can't create proxies for classes without parameterless constructors on Android"); +#endif + + // Arrange + var hub = Substitute.For(); + SentryClientExtensions.SentryOptionsForTestingOnly = new SentryOptions { DisableSentryHttpMessageHandler = true }; + + var filter = new SentryHttpMessageHandlerBuilderFilter(() => hub); + var handlerBuilder = Substitute.For(); + handlerBuilder.AdditionalHandlers.Returns(new List()); + Action next = _ => { }; + + // Act + var configure = filter.Configure(next); + configure(handlerBuilder); + + // Assert + handlerBuilder.AdditionalHandlers.Should().NotContain(h => h is SentryHttpMessageHandler); + } +} diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index 6a7583141c..843b28f7e4 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -664,6 +664,7 @@ namespace Sentry public Sentry.SentryLevel DiagnosticLevel { get; set; } public Sentry.Extensibility.IDiagnosticLogger? DiagnosticLogger { get; set; } public bool DisableFileWrite { get; set; } + public bool DisableSentryHttpMessageHandler { get; set; } public string? Distribution { get; set; } public string? Dsn { get; set; } public bool EnableScopeSync { get; set; } diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt index 6a7583141c..843b28f7e4 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt @@ -664,6 +664,7 @@ namespace Sentry public Sentry.SentryLevel DiagnosticLevel { get; set; } public Sentry.Extensibility.IDiagnosticLogger? DiagnosticLogger { get; set; } public bool DisableFileWrite { get; set; } + public bool DisableSentryHttpMessageHandler { get; set; } public string? Distribution { get; set; } public string? Dsn { get; set; } public bool EnableScopeSync { get; set; } diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt index 460ab5309d..a14cf232b7 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt @@ -651,6 +651,7 @@ namespace Sentry public Sentry.SentryLevel DiagnosticLevel { get; set; } public Sentry.Extensibility.IDiagnosticLogger? DiagnosticLogger { get; set; } public bool DisableFileWrite { get; set; } + public bool DisableSentryHttpMessageHandler { get; set; } public string? Distribution { get; set; } public string? Dsn { get; set; } public bool EnableScopeSync { get; set; }