Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
### BREAKING CHANGES

- 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 `IDispose` 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))

### Fixes
Expand Down
34 changes: 16 additions & 18 deletions samples/Sentry.Samples.Console.Basic/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -79,7 +79,6 @@ async Task FirstFunction()
async Task SecondFunction()
{
var span = transaction.StartChild("function", nameof(SecondFunction));

try
{
// Simulate doing some work
Expand All @@ -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!");
}
2 changes: 1 addition & 1 deletion src/Sentry/ISpan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Sentry;
/// <summary>
/// SpanTracer interface
/// </summary>
public interface ISpan : ISpanData
public interface ISpan : ISpanData, IDisposable
{
/// <summary>
/// Span description.
Expand Down
4 changes: 4 additions & 0 deletions src/Sentry/Internal/NoOpSpan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,8 @@ public void SetMeasurement(string name, Measurement measurement)
}

public string? Origin { get; set; }

public void Dispose()
{
}
}
13 changes: 11 additions & 2 deletions src/Sentry/SpanTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ namespace Sentry;
/// <summary>
/// Transaction span tracer.
/// </summary>
public class SpanTracer : IBaseTracer, ISpan
public sealed class SpanTracer : IBaseTracer, ISpan
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Is it worth a consideration to make SpanTracer internal, too? (in a potential follow-up)

So that users cannot run into CA2000

var span = new SpanTracer(null!, transaction, default, default, null!); //CA2000
span.Finish();

Or is it a potential user code scenario to try to cast?

if (SentrySdk.StartSpan("operation", "description") is SpanTracer span)

But this could have quite a large impact.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'm not sure if people are trying to cast these.

I think for the time being we should leave it as is. Eventually the plan is to get rid of transactions and, at that point, there's probably less need to cast from ISpan so we could re-evaluate.

{
private readonly IHub _hub;
private readonly SentryStopwatch _stopwatch = SentryStopwatch.StartNew();
private string? _origin;

private readonly Instrumenter _instrumenter = Instrumenter.Sentry;

Expand Down Expand Up @@ -190,5 +191,13 @@ internal set
_origin = value;
}
}
private string? _origin;

/// <summary>
/// Automatically finishes the span at the end of a <c>using</c> block. This is a convenience method only. Disposing
/// is not required.
/// </summary>
public void Dispose()
{
Finish();
}
}
24 changes: 23 additions & 1 deletion src/Sentry/TransactionTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ namespace Sentry;
/// <summary>
/// Transaction tracer.
/// </summary>
public class TransactionTracer : IBaseTracer, ITransactionTracer
public sealed class TransactionTracer : IBaseTracer, ITransactionTracer
{
private readonly IHub _hub;
private readonly SentryOptions? _options;
private readonly Timer? _idleTimer;
private long _cancelIdleTimeout;
private readonly SentryStopwatch _stopwatch = SentryStopwatch.StartNew();
private int _hasFinished = 0;

private readonly Instrumenter _instrumenter = Instrumenter.Sentry;

Expand Down Expand Up @@ -361,6 +362,12 @@ public void Clear()
/// <inheritdoc />
public void Finish()
{
// TODO: Replace with InterlockedBoolean once this has been merged into version6
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO (as a "resolvable" comment)

if (Interlocked.Exchange(ref _hasFinished, 1) == 1)
{
return;
}

_options?.LogDebug("Attempting to finish Transaction '{0}'.", SpanId);
if (Interlocked.Exchange(ref _cancelIdleTimeout, 0) == 1)
{
Expand Down Expand Up @@ -431,4 +438,19 @@ private void ReleaseSpans()
#endif
_activeSpanTracker.Clear();
}

/// <summary>
/// <para>
/// Automatically finishes the transaction with a status of <see cref="SpanStatus.Ok" /> at the end of a
/// <c>using</c> block, if it has not already been finished.
/// </para>
/// <para>
/// This is the equivalent of calling <see cref="Finish()" /> when the transaction passes out of scope.
/// </para>
/// </summary>
/// <remarks>This is a convenience method only. Disposing is not required.</remarks>
public void Dispose()
{
Finish();
}
}
10 changes: 6 additions & 4 deletions test/Sentry.Tests/ApiApprovalTests.Run.DotNet10_0.verified.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -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<string, object?> Data { get; }
Expand All @@ -1178,6 +1178,7 @@ namespace Sentry
public Sentry.SpanStatus? Status { get; set; }
public System.Collections.Generic.IReadOnlyDictionary<string, string> 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) { }
Expand Down Expand Up @@ -1239,7 +1240,7 @@ namespace Sentry
public System.Collections.Generic.IReadOnlyDictionary<string, object?> 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<Sentry.Breadcrumb> Breadcrumbs { get; }
Expand Down Expand Up @@ -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) { }
Expand Down
10 changes: 6 additions & 4 deletions test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -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<string, object?> Data { get; }
Expand All @@ -1178,6 +1178,7 @@ namespace Sentry
public Sentry.SpanStatus? Status { get; set; }
public System.Collections.Generic.IReadOnlyDictionary<string, string> 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) { }
Expand Down Expand Up @@ -1239,7 +1240,7 @@ namespace Sentry
public System.Collections.Generic.IReadOnlyDictionary<string, object?> 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<Sentry.Breadcrumb> Breadcrumbs { get; }
Expand Down Expand Up @@ -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) { }
Expand Down
10 changes: 6 additions & 4 deletions test/Sentry.Tests/ApiApprovalTests.Run.DotNet9_0.verified.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -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<string, object?> Data { get; }
Expand All @@ -1178,6 +1178,7 @@ namespace Sentry
public Sentry.SpanStatus? Status { get; set; }
public System.Collections.Generic.IReadOnlyDictionary<string, string> 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) { }
Expand Down Expand Up @@ -1239,7 +1240,7 @@ namespace Sentry
public System.Collections.Generic.IReadOnlyDictionary<string, object?> 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<Sentry.Breadcrumb> Breadcrumbs { get; }
Expand Down Expand Up @@ -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) { }
Expand Down
10 changes: 6 additions & 4 deletions test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -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<string, object?> Data { get; }
Expand All @@ -1154,6 +1154,7 @@ namespace Sentry
public Sentry.SpanStatus? Status { get; set; }
public System.Collections.Generic.IReadOnlyDictionary<string, string> 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) { }
Expand Down Expand Up @@ -1215,7 +1216,7 @@ namespace Sentry
public System.Collections.Generic.IReadOnlyDictionary<string, object?> 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<Sentry.Breadcrumb> Breadcrumbs { get; }
Expand Down Expand Up @@ -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) { }
Expand Down
Loading
Loading