diff --git a/CHANGELOG.md b/CHANGELOG.md
index e28ff1e0ab..f169ca4fa0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@
- `BreadcrumbLevel.Critical` has been renamed to `BreadcrumbLevel.Fatal` for consistency with the other Sentry SDKs ([#4605](https://github.com/getsentry/sentry-dotnet/pull/4605))
- SentryOptions.IsEnvironmentUser now defaults to false on MAUI. The means the User.Name will no longer be set, by default, to the name of the device ([#4606](https://github.com/getsentry/sentry-dotnet/pull/4606))
+- Spans and Transactions now implement `IDisposable` so that they can be used with `using` statements/declarations that will automatically finish the span with a status of OK when it passes out of scope, if it has not already been finished, to be consistent with `Activity` classes when using OpenTelemetry ([#4627](https://github.com/getsentry/sentry-dotnet/pull/4627))
+- SpanTracer and TransactionTracer are still public but these are now `sealed` (see also [#4627](https://github.com/getsentry/sentry-dotnet/pull/4627))
- Remove unnecessary files from SentryCocoaFramework before packing ([#4602](https://github.com/getsentry/sentry-dotnet/pull/4602))
- Backpressure handling is now enabled by default, meaning that the SDK will monitor system health and reduce the sampling rate of events and transactions when the system is under load. When the system is determined to be healthy again, the sampling rates are returned to their original levels. ([#4615](https://github.com/getsentry/sentry-dotnet/pull/4615))
- ScopeExtensions.Populate is now internal ([#4611](https://github.com/getsentry/sentry-dotnet/pull/4611))
diff --git a/samples/Sentry.Samples.Console.Basic/Program.cs b/samples/Sentry.Samples.Console.Basic/Program.cs
index dfc7723796..1a2605c0ee 100644
--- a/samples/Sentry.Samples.Console.Basic/Program.cs
+++ b/samples/Sentry.Samples.Console.Basic/Program.cs
@@ -63,7 +63,7 @@
// Always try to finish the transaction successfully.
// Unhandled exceptions will fail the transaction automatically.
-// Optionally, you can try/catch the exception, and call transaction.Finish(exception) on failure.
+// Optionally, you can try/catch the exception and call transaction.Finish(exception) on failure.
transaction.Finish();
async Task FirstFunction()
@@ -79,7 +79,6 @@ async Task FirstFunction()
async Task SecondFunction()
{
var span = transaction.StartChild("function", nameof(SecondFunction));
-
try
{
// Simulate doing some work
@@ -97,26 +96,25 @@ async Task SecondFunction()
SentrySdk.Logger.LogError(static log => log.SetAttribute("method", nameof(SecondFunction)),
"Error with message: {0}", exception.Message);
}
-
- span.Finish();
+ finally
+ {
+ span.Finish();
+ }
}
async Task ThirdFunction()
{
- var span = transaction.StartChild("function", nameof(ThirdFunction));
- try
- {
- // Simulate doing some work
- await Task.Delay(100);
+ // The `using` here ensures the span gets finished when we leave this method... This is unnecessary here,
+ // since the method always throws and the span will be finished automatically when the exception is captured,
+ // but this gives you another way to ensure spans are finished.
+ using var span = transaction.StartChild("function", nameof(ThirdFunction));
- SentrySdk.Logger.LogFatal(static log => log.SetAttribute("suppress", true),
- "Crash imminent!");
+ // Simulate doing some work
+ await Task.Delay(100);
- // This is an example of an unhandled exception. It will be captured automatically.
- throw new InvalidOperationException("Something happened that crashed the app!");
- }
- finally
- {
- span.Finish();
- }
+ SentrySdk.Logger.LogFatal(static log => log.SetAttribute("suppress", true),
+ "Crash imminent!");
+
+ // This is an example of an unhandled exception. It will be captured automatically.
+ throw new InvalidOperationException("Something happened that crashed the app!");
}
diff --git a/src/Sentry/ISpan.cs b/src/Sentry/ISpan.cs
index 5cf7193a9c..8bcd06d609 100644
--- a/src/Sentry/ISpan.cs
+++ b/src/Sentry/ISpan.cs
@@ -5,7 +5,7 @@ namespace Sentry;
///
/// SpanTracer interface
///
-public interface ISpan : ISpanData
+public interface ISpan : ISpanData, IDisposable
{
///
/// Span description.
diff --git a/src/Sentry/Internal/NoOpSpan.cs b/src/Sentry/Internal/NoOpSpan.cs
index d57aa34261..75cefe68b7 100644
--- a/src/Sentry/Internal/NoOpSpan.cs
+++ b/src/Sentry/Internal/NoOpSpan.cs
@@ -85,4 +85,8 @@ public void SetMeasurement(string name, Measurement measurement)
}
public string? Origin { get; set; }
+
+ public void Dispose()
+ {
+ }
}
diff --git a/src/Sentry/SpanTracer.cs b/src/Sentry/SpanTracer.cs
index ed51d48eaa..b221918694 100644
--- a/src/Sentry/SpanTracer.cs
+++ b/src/Sentry/SpanTracer.cs
@@ -6,10 +6,11 @@ namespace Sentry;
///
/// Transaction span tracer.
///
-public class SpanTracer : IBaseTracer, ISpan
+public sealed class SpanTracer : IBaseTracer, ISpan
{
private readonly IHub _hub;
private readonly SentryStopwatch _stopwatch = SentryStopwatch.StartNew();
+ private string? _origin;
private readonly Instrumenter _instrumenter = Instrumenter.Sentry;
@@ -190,5 +191,18 @@ internal set
_origin = value;
}
}
- private string? _origin;
+
+ ///
+ ///
+ /// Automatically finishes the span with a status of at the end of a
+ /// using block, if it has not already been finished.
+ ///
+ ///
+ /// This is the equivalent of calling when the span passes out of scope.
+ ///
+ /// ///
+ public void Dispose()
+ {
+ Finish();
+ }
}
diff --git a/src/Sentry/TransactionTracer.cs b/src/Sentry/TransactionTracer.cs
index d3f1de5a44..01b41a13dd 100644
--- a/src/Sentry/TransactionTracer.cs
+++ b/src/Sentry/TransactionTracer.cs
@@ -7,12 +7,13 @@ namespace Sentry;
///
/// Transaction tracer.
///
-public class TransactionTracer : IBaseTracer, ITransactionTracer
+public sealed class TransactionTracer : IBaseTracer, ITransactionTracer
{
private readonly IHub _hub;
private readonly SentryOptions? _options;
private readonly Timer? _idleTimer;
private readonly SentryStopwatch _stopwatch = SentryStopwatch.StartNew();
+ private InterlockedBoolean _hasFinished;
private InterlockedBoolean _cancelIdleTimeout;
@@ -362,6 +363,11 @@ public void Clear()
///
public void Finish()
{
+ if (_hasFinished.Exchange(true))
+ {
+ return;
+ }
+
_options?.LogDebug("Attempting to finish Transaction '{0}'.", SpanId);
if (_cancelIdleTimeout.Exchange(false) == true)
{
@@ -432,4 +438,19 @@ private void ReleaseSpans()
#endif
_activeSpanTracker.Clear();
}
+
+ ///
+ ///
+ /// Automatically finishes the transaction with a status of at the end of a
+ /// using block, if it has not already been finished.
+ ///
+ ///
+ /// This is the equivalent of calling when the transaction passes out of scope.
+ ///
+ ///
+ /// This is a convenience method only. Disposing is not required.
+ public void Dispose()
+ {
+ Finish();
+ }
}
diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt
index 9a2f11bf6a..a09086defc 100644
--- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt
+++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt
@@ -261,7 +261,7 @@ namespace Sentry
{
Sentry.SentryUser? Create();
}
- public interface ISpan : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.Protocol.ITraceContext
+ public interface ISpan : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.Protocol.ITraceContext, System.IDisposable
{
new string? Description { get; set; }
new string Operation { get; set; }
@@ -291,7 +291,7 @@ namespace Sentry
{
string? Platform { get; set; }
}
- public interface ITransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext
+ public interface ITransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext, System.IDisposable
{
new bool? IsParentSampled { get; set; }
new string Name { get; set; }
@@ -1160,7 +1160,7 @@ namespace Sentry
OutOfRange = 15,
DataLoss = 16,
}
- public class SpanTracer : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.Protocol.ITraceContext
+ public sealed class SpanTracer : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.Protocol.ITraceContext, System.IDisposable
{
public SpanTracer(Sentry.IHub hub, Sentry.TransactionTracer transaction, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string operation) { }
public System.Collections.Generic.IReadOnlyDictionary Data { get; }
@@ -1178,6 +1178,7 @@ namespace Sentry
public Sentry.SpanStatus? Status { get; set; }
public System.Collections.Generic.IReadOnlyDictionary Tags { get; }
public Sentry.SentryId TraceId { get; }
+ public void Dispose() { }
public void Finish() { }
public void Finish(Sentry.SpanStatus status) { }
public void Finish(System.Exception exception) { }
@@ -1239,7 +1240,7 @@ namespace Sentry
public System.Collections.Generic.IReadOnlyDictionary CustomSamplingContext { get; }
public Sentry.ITransactionContext TransactionContext { get; }
}
- public class TransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.ITransactionTracer, Sentry.Protocol.ITraceContext
+ public sealed class TransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.ITransactionTracer, Sentry.Protocol.ITraceContext, System.IDisposable
{
public TransactionTracer(Sentry.IHub hub, Sentry.ITransactionContext context) { }
public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; }
@@ -1275,6 +1276,7 @@ namespace Sentry
public Sentry.SentryId TraceId { get; }
public Sentry.SentryUser User { get; set; }
public void AddBreadcrumb(Sentry.Breadcrumb breadcrumb) { }
+ public void Dispose() { }
public void Finish() { }
public void Finish(Sentry.SpanStatus status) { }
public void Finish(System.Exception exception) { }
diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt
index 9a2f11bf6a..a09086defc 100644
--- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt
+++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt
@@ -261,7 +261,7 @@ namespace Sentry
{
Sentry.SentryUser? Create();
}
- public interface ISpan : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.Protocol.ITraceContext
+ public interface ISpan : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.Protocol.ITraceContext, System.IDisposable
{
new string? Description { get; set; }
new string Operation { get; set; }
@@ -291,7 +291,7 @@ namespace Sentry
{
string? Platform { get; set; }
}
- public interface ITransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext
+ public interface ITransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext, System.IDisposable
{
new bool? IsParentSampled { get; set; }
new string Name { get; set; }
@@ -1160,7 +1160,7 @@ namespace Sentry
OutOfRange = 15,
DataLoss = 16,
}
- public class SpanTracer : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.Protocol.ITraceContext
+ public sealed class SpanTracer : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.Protocol.ITraceContext, System.IDisposable
{
public SpanTracer(Sentry.IHub hub, Sentry.TransactionTracer transaction, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string operation) { }
public System.Collections.Generic.IReadOnlyDictionary Data { get; }
@@ -1178,6 +1178,7 @@ namespace Sentry
public Sentry.SpanStatus? Status { get; set; }
public System.Collections.Generic.IReadOnlyDictionary Tags { get; }
public Sentry.SentryId TraceId { get; }
+ public void Dispose() { }
public void Finish() { }
public void Finish(Sentry.SpanStatus status) { }
public void Finish(System.Exception exception) { }
@@ -1239,7 +1240,7 @@ namespace Sentry
public System.Collections.Generic.IReadOnlyDictionary CustomSamplingContext { get; }
public Sentry.ITransactionContext TransactionContext { get; }
}
- public class TransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.ITransactionTracer, Sentry.Protocol.ITraceContext
+ public sealed class TransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.ITransactionTracer, Sentry.Protocol.ITraceContext, System.IDisposable
{
public TransactionTracer(Sentry.IHub hub, Sentry.ITransactionContext context) { }
public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; }
@@ -1275,6 +1276,7 @@ namespace Sentry
public Sentry.SentryId TraceId { get; }
public Sentry.SentryUser User { get; set; }
public void AddBreadcrumb(Sentry.Breadcrumb breadcrumb) { }
+ public void Dispose() { }
public void Finish() { }
public void Finish(Sentry.SpanStatus status) { }
public void Finish(System.Exception exception) { }
diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt
index 9a2f11bf6a..a09086defc 100644
--- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt
+++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt
@@ -261,7 +261,7 @@ namespace Sentry
{
Sentry.SentryUser? Create();
}
- public interface ISpan : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.Protocol.ITraceContext
+ public interface ISpan : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.Protocol.ITraceContext, System.IDisposable
{
new string? Description { get; set; }
new string Operation { get; set; }
@@ -291,7 +291,7 @@ namespace Sentry
{
string? Platform { get; set; }
}
- public interface ITransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext
+ public interface ITransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext, System.IDisposable
{
new bool? IsParentSampled { get; set; }
new string Name { get; set; }
@@ -1160,7 +1160,7 @@ namespace Sentry
OutOfRange = 15,
DataLoss = 16,
}
- public class SpanTracer : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.Protocol.ITraceContext
+ public sealed class SpanTracer : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.Protocol.ITraceContext, System.IDisposable
{
public SpanTracer(Sentry.IHub hub, Sentry.TransactionTracer transaction, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string operation) { }
public System.Collections.Generic.IReadOnlyDictionary Data { get; }
@@ -1178,6 +1178,7 @@ namespace Sentry
public Sentry.SpanStatus? Status { get; set; }
public System.Collections.Generic.IReadOnlyDictionary Tags { get; }
public Sentry.SentryId TraceId { get; }
+ public void Dispose() { }
public void Finish() { }
public void Finish(Sentry.SpanStatus status) { }
public void Finish(System.Exception exception) { }
@@ -1239,7 +1240,7 @@ namespace Sentry
public System.Collections.Generic.IReadOnlyDictionary CustomSamplingContext { get; }
public Sentry.ITransactionContext TransactionContext { get; }
}
- public class TransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.ITransactionTracer, Sentry.Protocol.ITraceContext
+ public sealed class TransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.ITransactionTracer, Sentry.Protocol.ITraceContext, System.IDisposable
{
public TransactionTracer(Sentry.IHub hub, Sentry.ITransactionContext context) { }
public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; }
@@ -1275,6 +1276,7 @@ namespace Sentry
public Sentry.SentryId TraceId { get; }
public Sentry.SentryUser User { get; set; }
public void AddBreadcrumb(Sentry.Breadcrumb breadcrumb) { }
+ public void Dispose() { }
public void Finish() { }
public void Finish(Sentry.SpanStatus status) { }
public void Finish(System.Exception exception) { }
diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt
index d508934005..1d934bb3cb 100644
--- a/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt
+++ b/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt
@@ -249,7 +249,7 @@ namespace Sentry
{
Sentry.SentryUser? Create();
}
- public interface ISpan : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.Protocol.ITraceContext
+ public interface ISpan : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.Protocol.ITraceContext, System.IDisposable
{
new string? Description { get; set; }
new string Operation { get; set; }
@@ -279,7 +279,7 @@ namespace Sentry
{
string? Platform { get; set; }
}
- public interface ITransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext
+ public interface ITransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext, System.IDisposable
{
new bool? IsParentSampled { get; set; }
new string Name { get; set; }
@@ -1136,7 +1136,7 @@ namespace Sentry
OutOfRange = 15,
DataLoss = 16,
}
- public class SpanTracer : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.Protocol.ITraceContext
+ public sealed class SpanTracer : Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.Protocol.ITraceContext, System.IDisposable
{
public SpanTracer(Sentry.IHub hub, Sentry.TransactionTracer transaction, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string operation) { }
public System.Collections.Generic.IReadOnlyDictionary Data { get; }
@@ -1154,6 +1154,7 @@ namespace Sentry
public Sentry.SpanStatus? Status { get; set; }
public System.Collections.Generic.IReadOnlyDictionary Tags { get; }
public Sentry.SentryId TraceId { get; }
+ public void Dispose() { }
public void Finish() { }
public void Finish(Sentry.SpanStatus status) { }
public void Finish(System.Exception exception) { }
@@ -1215,7 +1216,7 @@ namespace Sentry
public System.Collections.Generic.IReadOnlyDictionary CustomSamplingContext { get; }
public Sentry.ITransactionContext TransactionContext { get; }
}
- public class TransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.ITransactionTracer, Sentry.Protocol.ITraceContext
+ public sealed class TransactionTracer : Sentry.IEventLike, Sentry.IHasData, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.ITransactionTracer, Sentry.Protocol.ITraceContext, System.IDisposable
{
public TransactionTracer(Sentry.IHub hub, Sentry.ITransactionContext context) { }
public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; }
@@ -1251,6 +1252,7 @@ namespace Sentry
public Sentry.SentryId TraceId { get; }
public Sentry.SentryUser User { get; set; }
public void AddBreadcrumb(Sentry.Breadcrumb breadcrumb) { }
+ public void Dispose() { }
public void Finish() { }
public void Finish(Sentry.SpanStatus status) { }
public void Finish(System.Exception exception) { }
diff --git a/test/Sentry.Tests/SpanTracerTests.cs b/test/Sentry.Tests/SpanTracerTests.cs
index 59becf2740..5748799bcd 100644
--- a/test/Sentry.Tests/SpanTracerTests.cs
+++ b/test/Sentry.Tests/SpanTracerTests.cs
@@ -10,7 +10,7 @@ public async Task SetExtra_DataInserted_NoDataLoss()
{
// Arrange
var hub = Substitute.For();
- var transaction = new SpanTracer(hub, null, null, SentryId.Empty, "");
+ var spanTracer = new SpanTracer(hub, null, null, SentryId.Empty, "");
var evt = new ManualResetEvent(false);
var ready = new ManualResetEvent(false);
var counter = 0;
@@ -27,7 +27,7 @@ public async Task SetExtra_DataInserted_NoDataLoss()
for (var i = 0; i < amount; i++)
{
- transaction.SetExtra(Guid.NewGuid().ToString(), Guid.NewGuid());
+ spanTracer.SetExtra(Guid.NewGuid().ToString(), Guid.NewGuid());
}
})).ToList();
ready.WaitOne();
@@ -36,7 +36,38 @@ public async Task SetExtra_DataInserted_NoDataLoss()
// Arrange
// 4 tasks testing X amount should be the same amount as Extras.
- Assert.Equal(4 * amount, transaction.Extra.Count);
+ Assert.Equal(4 * amount, spanTracer.Extra.Count);
}
}
+
+ [Fact]
+ public void Dispose_IsUnfinished_Finishes()
+ {
+ // Arrange
+ var hub = Substitute.For();
+ var spanTracer = new SpanTracer(hub, null, null, SentryId.Empty, "");
+
+ // Act
+ spanTracer.Dispose();
+
+ // Assert
+ spanTracer.IsFinished.Should().BeTrue();
+ }
+
+ [Fact]
+ public void Dispose_IsFinsished_DoesNothing()
+ {
+ // Arrange
+ var hub = Substitute.For();
+ var spanTracer = new SpanTracer(hub, null, null, SentryId.Empty, "");
+ spanTracer.Finish();
+ var finishTimestamp = spanTracer.EndTimestamp;
+
+ // Act
+ spanTracer.Dispose();
+
+ // Assert
+ spanTracer.IsFinished.Should().BeTrue();
+ spanTracer.EndTimestamp.Should().Be(finishTimestamp);
+ }
}
diff --git a/test/Sentry.Tests/TransactionTracerTests.cs b/test/Sentry.Tests/TransactionTracerTests.cs
new file mode 100644
index 0000000000..904bb13369
--- /dev/null
+++ b/test/Sentry.Tests/TransactionTracerTests.cs
@@ -0,0 +1,33 @@
+namespace Sentry.Tests;
+
+public class TransactionTracerTests
+{
+ [Fact]
+ public void Dispose_Unfinished_Finishes()
+ {
+ // Arrange
+ var hub = Substitute.For();
+ var transaction = new TransactionTracer(hub, "op", "name");
+
+ // Act
+ transaction.Dispose();
+
+ // Assert
+ hub.Received(1).CaptureTransaction(Arg.Is(t => t.SpanId == transaction.SpanId));
+ }
+
+ [Fact]
+ public void Dispose_Finished_DoesNothing()
+ {
+ // Arrange
+ var hub = Substitute.For();
+ var transaction = new TransactionTracer(hub, "op", "name");
+ transaction.Finish();
+
+ // Act
+ transaction.Dispose();
+
+ // Assert
+ hub.Received(1).CaptureTransaction(Arg.Is(t => t.SpanId == transaction.SpanId));
+ }
+}