diff --git a/CHANGELOG.md b/CHANGELOG.md index 4de8ce8c86..eaa4da4d2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- When using OTel and ASP.NET Core the SDK could try to process OTel spans after the SDK had been closed ([#3726](https://github.com/getsentry/sentry-dotnet/pull/3726)) + ## 4.12.2 ### Features diff --git a/src/Sentry.OpenTelemetry/SentrySpanProcessor.cs b/src/Sentry.OpenTelemetry/SentrySpanProcessor.cs index c34415caf5..9f32987db5 100644 --- a/src/Sentry.OpenTelemetry/SentrySpanProcessor.cs +++ b/src/Sentry.OpenTelemetry/SentrySpanProcessor.cs @@ -83,6 +83,14 @@ internal SentrySpanProcessor(IHub hub, IEnumerable? enri /// public override void OnStart(Activity data) { + if (!_hub.IsEnabled) + { + // This would be unusual... it might happen if the SDK is closed while the processor is still running and + // we receive new telemetry. In this case, we can't log anything because our logger is disabled, so we just + // swallow it + return; + } + if (data.ParentSpanId != default && _map.TryGetValue(data.ParentSpanId, out var mappedParent)) { // Explicit ParentSpanId of another activity that we have already mapped @@ -165,6 +173,14 @@ private void CreateRootSpan(Activity data) /// public override void OnEnd(Activity data) { + if (!_hub.IsEnabled) + { + // This would be unusual... it might happen if the SDK is closed while the processor is still running and + // we receive new telemetry. In this case, we can't log anything because our logger is disabled, so we just + // swallow it + return; + } + // Make a dictionary of the attributes (aka "tags") for faster lookup when used throughout the processor. var attributes = data.TagObjects.ToDict(); diff --git a/test/Sentry.OpenTelemetry.Tests/SentrySpanProcessorTests.cs b/test/Sentry.OpenTelemetry.Tests/SentrySpanProcessorTests.cs index 7ee5b0de0e..92839b2f56 100644 --- a/test/Sentry.OpenTelemetry.Tests/SentrySpanProcessorTests.cs +++ b/test/Sentry.OpenTelemetry.Tests/SentrySpanProcessorTests.cs @@ -34,9 +34,9 @@ public Fixture() public Hub GetHub() => Hub ??= new Hub(Options, Client, SessionManager, Clock, ScopeManager); - public SentrySpanProcessor GetSut() + public SentrySpanProcessor GetSut(IHub hub = null) { - return new SentrySpanProcessor(GetHub(), Enrichers); + return new SentrySpanProcessor(hub ?? GetHub(), Enrichers); } } @@ -488,6 +488,54 @@ public void OnEnd_IsSentryRequest_DoesNotFinishTransaction(string urlKey) transaction.IsSentryRequest.Should().BeTrue(); } + [Fact] + public void OnStart_DisabledHub_DoesNothing() + { + // Arrange + _fixture.Options.Instrumenter = Instrumenter.OpenTelemetry; + SentryClientExtensions.SentryOptionsForTestingOnly = _fixture.Options; + var hub = Substitute.For(); + hub.IsEnabled.Returns(false); + var sut = _fixture.GetSut(hub); + + var data = Tracer.StartActivity()!; + + // Act + sut.OnStart(data); + + // Assert + sut._map.Should().BeEmpty(); + hub.Received(0).GetSpan(); + hub.Received(0).StartTransaction( + Arg.Any(), + Arg.Any>() + ); + } + + [Fact] + public void OnEnd_DisabledHub_DoesNothing() + { + // Arrange + _fixture.Options.Instrumenter = Instrumenter.OpenTelemetry; + SentryClientExtensions.SentryOptionsForTestingOnly = _fixture.Options; + var hub = Substitute.For(); + hub.IsEnabled.Returns(true, false); + var sut = _fixture.GetSut(hub); + + var data = Tracer.StartActivity()!; + + // Act + sut.OnEnd(data); + + // Assert + sut._map.Should().BeEmpty(); + hub.Received(0).GetSpan(); + hub.Received(0).StartTransaction( + Arg.Any(), + Arg.Any>() + ); + } + private static void FilterActivity(Activity activity) { // Simulates filtering an activity - see https://github.com/getsentry/sentry-dotnet/pull/3198