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);
+ }
}