From 1c39c8d5efca4ffa3fa2994a520dd461c4fd42c1 Mon Sep 17 00:00:00 2001 From: James Crosswell Date: Wed, 25 Jun 2025 10:23:23 +1200 Subject: [PATCH 1/3] Treat empty trace id as invalid when parsing trace headers --- .../Extensions/HttpContextExtensions.cs | 9 ++++++++- .../Extensions/HttpContextExtensionsTests.cs | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Sentry.AspNetCore/Extensions/HttpContextExtensions.cs b/src/Sentry.AspNetCore/Extensions/HttpContextExtensions.cs index 19e4dde3c4..9eb982036a 100644 --- a/src/Sentry.AspNetCore/Extensions/HttpContextExtensions.cs +++ b/src/Sentry.AspNetCore/Extensions/HttpContextExtensions.cs @@ -56,7 +56,14 @@ internal static class HttpContextExtensions try { - return SentryTraceHeader.Parse(value!); + var traceHeader = SentryTraceHeader.Parse(value!); + if (traceHeader?.TraceId != SentryId.Empty) + { + return traceHeader; + } + + options?.LogWarning("Sentry trace header '{0}' has an empty trace ID.", value); + return null; } catch (Exception ex) { diff --git a/test/Sentry.AspNetCore.Tests/Extensions/HttpContextExtensionsTests.cs b/test/Sentry.AspNetCore.Tests/Extensions/HttpContextExtensionsTests.cs index c116976049..339d661a4b 100644 --- a/test/Sentry.AspNetCore.Tests/Extensions/HttpContextExtensionsTests.cs +++ b/test/Sentry.AspNetCore.Tests/Extensions/HttpContextExtensionsTests.cs @@ -78,5 +78,20 @@ public void TryGetRouteTemplate_WithSentryRouteName_RouteName() // Assert Assert.Equal(expectedName, filteredRoute); } + + [Fact] + public void TryGetSentryTraceHeader_WithEmptyTraceId_ReturnsNull() + { + // Arrange + var httpContext = Fixture.GetSut(); + var options = new SentryOptions(); + httpContext.Request.Headers.Append(SentryTraceHeader.HttpHeaderName, "00000000000000000000000000000000-1000000000000000-1"); + + // Act + var header = httpContext.TryGetSentryTraceHeader(options); + + // Assert + Assert.Null(header); + } } #endif From 457f70d6200b71c375cbb00845cde55c9118ad4e Mon Sep 17 00:00:00 2001 From: James Crosswell Date: Wed, 25 Jun 2025 10:58:18 +1200 Subject: [PATCH 2/3] Fixed NoOpSpan.GetTraceHeader() --- src/Sentry/Internal/UnsampledSpan.cs | 1 + .../Internals/UnsampledSpanTests.cs | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 test/Sentry.Tests/Internals/UnsampledSpanTests.cs diff --git a/src/Sentry/Internal/UnsampledSpan.cs b/src/Sentry/Internal/UnsampledSpan.cs index 3b52bdaa8c..ae64942ef0 100644 --- a/src/Sentry/Internal/UnsampledSpan.cs +++ b/src/Sentry/Internal/UnsampledSpan.cs @@ -6,4 +6,5 @@ internal sealed class UnsampledSpan(UnsampledTransaction transaction, SpanId? sp public override SpanId SpanId { get; } = spanId ?? SpanId.Empty; internal UnsampledTransaction Transaction => transaction; public override ISpan StartChild(string operation) => transaction.StartChild(operation); + public override SentryTraceHeader GetTraceHeader() => transaction.GetTraceHeader(); } diff --git a/test/Sentry.Tests/Internals/UnsampledSpanTests.cs b/test/Sentry.Tests/Internals/UnsampledSpanTests.cs new file mode 100644 index 0000000000..a64edc9eed --- /dev/null +++ b/test/Sentry.Tests/Internals/UnsampledSpanTests.cs @@ -0,0 +1,24 @@ +namespace Sentry.Tests.Internals; + +public class UnsampledSpanTests +{ + [Fact] + public void GetTraceHeader_CreatesHeaderFromUnsampledTransaction() + { + // Arrange + var hub = Substitute.For(); + ITransactionContext context = new TransactionContext("TestTransaction", "TestOperation", + new SentryTraceHeader(SentryId.Create(), SpanId.Create(), false) + ); + var transaction = new UnsampledTransaction(hub, context); + var unsampledSpan = transaction.StartChild("Foo"); + + // Act + var traceHeader = unsampledSpan.GetTraceHeader(); + + // Assert + traceHeader.TraceId.Should().Be(context.TraceId); + traceHeader.SpanId.Should().Be(context.SpanId); + traceHeader.IsSampled.Should().Be(context.IsSampled); + } +} From 69fd3a047b1816a8a89dfbcb4bd3a020cff0db4a Mon Sep 17 00:00:00 2001 From: James Crosswell Date: Wed, 25 Jun 2025 11:04:37 +1200 Subject: [PATCH 3/3] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 054dfd7fe2..002c64191c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- Unsampled spans no longer propagate empty trace headers ([#4302](https://github.com/getsentry/sentry-dotnet/pull/4302)) + ## 5.11.1 ### Fixes