diff --git a/CHANGELOG.md b/CHANGELOG.md index 838a780377..1035800d02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Support DI for custom transaction processors ([#1993](https://github.com/getsentry/sentry-dotnet/pull/1993)) - Mark Transaction as aborted when unhandled exception occurs ([#1996](https://github.com/getsentry/sentry-dotnet/pull/1996)) - Build Windows and Tizen targets for `Sentry.Maui` ([#2005](https://github.com/getsentry/sentry-dotnet/pull/2005)) +- Add `ISpan.GetTransaction` convenience method ([#2014](https://github.com/getsentry/sentry-dotnet/pull/2014)) ### Fixes diff --git a/src/Sentry/ISpan.cs b/src/Sentry/ISpan.cs index c720598eae..7001b119bf 100644 --- a/src/Sentry/ISpan.cs +++ b/src/Sentry/ISpan.cs @@ -68,5 +68,16 @@ public static ISpan StartChild(this ISpan span, string operation, string? descri return child; } + + /// + /// Gets the transaction that this span belongs to. + /// + public static ITransaction GetTransaction(this ISpan span) => + span switch + { + ITransaction transaction => transaction, + SpanTracer tracer => tracer.Transaction, + _ => throw new ArgumentOutOfRangeException(nameof(span), span, null) + }; } } diff --git a/src/Sentry/SpanTracer.cs b/src/Sentry/SpanTracer.cs index f5cd28e4d9..c111af8189 100644 --- a/src/Sentry/SpanTracer.cs +++ b/src/Sentry/SpanTracer.cs @@ -11,9 +11,10 @@ namespace Sentry public class SpanTracer : ISpan { private readonly IHub _hub; - private readonly TransactionTracer _transaction; private readonly SentryStopwatch _stopwatch = SentryStopwatch.StartNew(); + internal TransactionTracer Transaction { get; } + /// public SpanId SpanId { get; } @@ -57,14 +58,13 @@ public void SetTag(string key, string value) => public void UnsetTag(string key) => (_tags ??= new ConcurrentDictionary()).TryRemove(key, out _); - private ConcurrentDictionary _data = new(); + private readonly ConcurrentDictionary _data = new(); /// public IReadOnlyDictionary Extra => _data; /// - public void SetExtra(string key, object? value) => - _data[key] = value; + public void SetExtra(string key, object? value) => _data[key] = value; /// /// Initializes an instance of . @@ -77,8 +77,7 @@ public SpanTracer( string operation) { _hub = hub; - _transaction = transaction; - + Transaction = transaction; SpanId = SpanId.Create(); ParentSpanId = parentSpanId; TraceId = traceId; @@ -86,8 +85,7 @@ public SpanTracer( } /// - public ISpan StartChild(string operation) => - _transaction.StartChild(SpanId, operation); + public ISpan StartChild(string operation) => Transaction.StartChild(SpanId, operation); /// public void Finish() @@ -111,13 +109,9 @@ public void Finish(Exception exception, SpanStatus status) } /// - public void Finish(Exception exception) => - Finish(exception, SpanStatusConverter.FromException(exception)); + public void Finish(Exception exception) => Finish(exception, SpanStatusConverter.FromException(exception)); /// - public SentryTraceHeader GetTraceHeader() => new( - TraceId, - SpanId, - IsSampled); + public SentryTraceHeader GetTraceHeader() => new(TraceId, SpanId, IsSampled); } } diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.Core3_1.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.Core3_1.verified.txt index 7a5eb85da0..6cb2f37fff 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.Core3_1.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.Core3_1.verified.txt @@ -737,6 +737,7 @@ namespace Sentry } public static class SpanExtensions { + public static Sentry.ITransaction GetTransaction(this Sentry.ISpan span) { } public static Sentry.ISpan StartChild(this Sentry.ISpan span, string operation, string? description) { } } public readonly struct SpanId : Sentry.IJsonSerializable, System.IEquatable diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet4_8.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet4_8.verified.txt index 2376f3aec1..a8a67cf7e0 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet4_8.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet4_8.verified.txt @@ -736,6 +736,7 @@ namespace Sentry } public static class SpanExtensions { + public static Sentry.ITransaction GetTransaction(this Sentry.ISpan span) { } public static Sentry.ISpan StartChild(this Sentry.ISpan span, string operation, string? description) { } } public readonly struct SpanId : Sentry.IJsonSerializable, System.IEquatable diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt index 7a5eb85da0..6cb2f37fff 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt @@ -737,6 +737,7 @@ namespace Sentry } public static class SpanExtensions { + public static Sentry.ITransaction GetTransaction(this Sentry.ISpan span) { } public static Sentry.ISpan StartChild(this Sentry.ISpan span, string operation, string? description) { } } public readonly struct SpanId : Sentry.IJsonSerializable, System.IEquatable diff --git a/test/Sentry.Tests/Protocol/TransactionTests.cs b/test/Sentry.Tests/Protocol/TransactionTests.cs index 8881a6f641..462fd10915 100644 --- a/test/Sentry.Tests/Protocol/TransactionTests.cs +++ b/test/Sentry.Tests/Protocol/TransactionTests.cs @@ -362,4 +362,33 @@ public void Finish_ChildSpan_StatusSet_DoesNotOverride() // Assert span.Status.Should().Be(SpanStatus.DataLoss); } + + [Fact] + public void ISpan_GetTransaction_FromTransaction() + { + // Arrange + var hub = Substitute.For(); + ISpan transaction = new TransactionTracer(hub, "my name", "my op"); + + // Act + var result = transaction.GetTransaction(); + + // Assert + Assert.Same(transaction, result); + } + + [Fact] + public void ISpan_GetTransaction_FromSpan() + { + // Arrange + var hub = Substitute.For(); + var transaction = new TransactionTracer(hub, "my name", "my op"); + var span = transaction.StartChild("child op"); + + // Act + var result = span.GetTransaction(); + + // Assert + Assert.Same(transaction, result); + } }