Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finish unfinished Spans on Transaction completion #1296

Merged
merged 22 commits into from
Nov 8, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c2d186b
add test case.
lucas-zimerman Nov 2, 2021
872c2c1
Update test.
lucas-zimerman Nov 2, 2021
e2a32d1
removed some moqs
lucas-zimerman Nov 2, 2021
5591695
Code cleanup
lucas-zimerman Nov 2, 2021
34c498a
Close spans with events without exceptions.
lucas-zimerman Nov 3, 2021
ae96241
Format code
getsentry-bot Nov 3, 2021
cfb2519
rollback Hub CaptureEvent, removed `A` and implemented close unfinish…
lucas-zimerman Nov 4, 2021
9d3ddeb
typo.
lucas-zimerman Nov 4, 2021
d04bf92
Tests fixes.
lucas-zimerman Nov 4, 2021
8038daa
Merge branch 'main' into fix/message-only-errors-not-closing-span
lucas-zimerman Nov 4, 2021
657c9b5
small refactor
lucas-zimerman Nov 5, 2021
3c943fd
Merge branch 'fix/message-only-errors-not-closing-span' of https://gi…
lucas-zimerman Nov 5, 2021
0bd5097
Merge branch 'main' into fix/message-only-errors-not-closing-span
lucas-zimerman Nov 5, 2021
272eece
Update changelog.
lucas-zimerman Nov 5, 2021
07374b2
Self code review fixes.
lucas-zimerman Nov 5, 2021
f30239b
Moved OR condition to the left side.
lucas-zimerman Nov 5, 2021
a92e53c
Removed unneeded Span close.
lucas-zimerman Nov 8, 2021
1223d3d
Merge branch 'main' into fix/message-only-errors-not-closing-span
lucas-zimerman Nov 8, 2021
dc2895a
Format code
getsentry-bot Nov 8, 2021
bb0063e
Merge branch 'main' into fix/message-only-errors-not-closing-span
lucas-zimerman Nov 8, 2021
fa2aa9e
Removed unused extension.
lucas-zimerman Nov 8, 2021
b25266a
Merge branch 'fix/message-only-errors-not-closing-span' of https://gi…
lucas-zimerman Nov 8, 2021
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
15 changes: 10 additions & 5 deletions src/Sentry/Internal/Hub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,16 @@ public SentryId CaptureEvent(SentryEvent evt, Scope? scope = null)
evt.Contexts.Trace.SpanId = linkedSpan.SpanId;
evt.Contexts.Trace.TraceId = linkedSpan.TraceId;
evt.Contexts.Trace.ParentSpanId = linkedSpan.ParentSpanId;
}
else if (evt.IsErrored() && scope?.LastCreatedSpan() is { } lastSpan && lastSpan?.IsFinished == false)
{
// Can still be reset by the owner but lets consider it finished and errored for now.
lastSpan.Finish(SpanStatus.InternalError);

if (!linkedSpan.IsFinished && evt.IsErrored())
{
// Can still be reset by the owner but lets consider it finished and errored for now.
linkedSpan.Finish(SpanStatus.InternalError);
}
else if (!linkedSpan.IsFinished)
{
linkedSpan.Finish();
}
lucas-zimerman marked this conversation as resolved.
Show resolved Hide resolved
}

actualScope.SessionUpdate = evt switch
Expand Down
7 changes: 5 additions & 2 deletions src/Sentry/SentryEventExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
namespace Sentry
{
/// <summary>
/// Extension methods for <see cref="SentryEvent"/>
/// Extension methods for <see cref="SentryEvent"/>A
lucas-zimerman marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
public static class SentryEventExtensions
{
internal static bool IsErrored(this SentryEvent @event)
=> @event.Exception is not null || @event.SentryExceptions?.Any() == true;
=> @event.Level >= SentryLevel.Error ||
@event.Exception is not null ||
@event.SentryExceptions?.Any() == true;
Copy link
Member

Choose a reason for hiding this comment

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

Is there an IntenralExceptions instead? Otherwise it'll instantiate a list on the property getter IIRC

Suggested change
=> @event.Level >= SentryLevel.Error ||
@event.Exception is not null ||
@event.SentryExceptions?.Any() == true;
=> @event.Level >= SentryLevel.Error
|| @event.Exception is not null
|| @event.InternalSentryExceptions?.Any() == true;

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There's no InternalSentryExceptions.

We could use @event.HasException but that's basically the same code

internal bool HasException => Exception is not null || SentryExceptions?.Any() == true;

Copy link
Member

Choose a reason for hiding this comment

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

internal SentryValues<SentryException>? SentryExceptionValues { get; set; }
/// <summary>
/// The Sentry Exception interface.
/// </summary>
public IEnumerable<SentryException>? SentryExceptions
{
get => SentryExceptionValues?.Values ?? Enumerable.Empty<SentryException>();
set => SentryExceptionValues = value != null ? new SentryValues<SentryException>(value) : null;
}


}
}
84 changes: 84 additions & 0 deletions test/Sentry.Tests/HubTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ public void CaptureEvent_ExceptionWithOpenSpan_SpanFinishedWithInternalError()
var hub = new Hub(new SentryOptions
{
Dsn = DsnSamples.ValidDsnWithSecret,
TracesSampleRate = 1
}, client);
var scope = new Scope();
scope.Transaction = hub.StartTransaction("transaction", "operation");
Expand Down Expand Up @@ -1016,5 +1017,88 @@ public void ResumeSession_NoPausedSession_DoesNothing()
// Assert
client.DidNotReceive().CaptureSession(Arg.Is<SessionUpdate>(s => s.EndStatus != null));
}

private class ErroredMessageFixture
{
public SpanId SpanId { get; }
public SentryId TraceId { get; }
public SpanId ParentId { get; }
public Scope Scope { get; }
public ISpan Span { get; }
public TransactionTracer Transaction { get; }
public IInternalScopeManager ScopeManager { get; }

public ErroredMessageFixture()
{
Scope = new Scope();
Transaction = new TransactionTracer(Substitute.For<IHub>(), "Tracer", "Operation");
Span = Transaction.StartChild("Span", "Operation");
ScopeManager = Substitute.For<IInternalScopeManager>();

Scope.Transaction = Transaction;
SpanId = Span.SpanId;
ParentId = Transaction.SpanId;
TraceId = Transaction.TraceId;

ScopeManager.GetCurrent().Returns(new KeyValuePair<Scope, ISentryClient>(Scope, Substitute.For<ISentryClient>()));
lucas-zimerman marked this conversation as resolved.
Show resolved Hide resolved
}

public Hub GetSut() => new Hub(new SentryOptions() { Dsn = DsnSamples.ValidDsnWithSecret }, scopeManager: ScopeManager);
}

private readonly ErroredMessageFixture _fixture = new();

[Theory]
[InlineData(SentryLevel.Error)]
[InlineData(SentryLevel.Fatal)]
public void CaptureEvent_ErroredMessageWithoutException_ClosesCurrentSpan(SentryLevel level)
{
// Arrange
var span = _fixture.Span;
var hub = _fixture.GetSut();

var @event = new SentryEvent()
{
Message = "Errored message",
Level = level
};

// Act
hub.CaptureEvent(@event);

// Assert
Assert.Equal(_fixture.SpanId, @event.Contexts.Trace.SpanId);
Assert.Equal(_fixture.TraceId, @event.Contexts.Trace.TraceId);
Assert.Equal(_fixture.ParentId, @event.Contexts.Trace.ParentSpanId);
Assert.True(span.IsFinished);
Assert.Equal(SpanStatus.InternalError, span.Status);
}

[Theory]
[InlineData(SentryLevel.Warning)]
[InlineData(SentryLevel.Info)]
[InlineData(SentryLevel.Debug)]
public void CaptureEvent_InfoMessageWithoutException_ClosesCurrentSpan(SentryLevel level)
bruno-garcia marked this conversation as resolved.
Show resolved Hide resolved
{
// Arrange
var span = _fixture.Span;
var hub = _fixture.GetSut();

var @event = new SentryEvent()
{
Message = "Errored message",
Level = level
};

// Act
hub.CaptureEvent(@event);

// Assert
Assert.Equal(_fixture.SpanId, @event.Contexts.Trace.SpanId);
Assert.Equal(_fixture.TraceId, @event.Contexts.Trace.TraceId);
Assert.Equal(_fixture.ParentId, @event.Contexts.Trace.ParentSpanId);
Assert.True(span.IsFinished);
Assert.Equal(SpanStatus.UnknownError, span.Status);
Copy link
Member

Choose a reason for hiding this comment

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

This makes me realize that we're diverging here. Other SDKs are defaulting to Ok when no status is set. @marandaneto recently talked about this on another repo. He might be able to chime in here

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I have to agree that it was the expected result that I was expecting by calling Finish() but instead I got UnknownError.

I could make a separate PR to alter the default Finish status and then update this PR.

Copy link
Contributor

@marandaneto marandaneto Nov 5, 2021

Choose a reason for hiding this comment

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

for HTTP spans -> getsentry/develop#307 (comment)

if its a UI transaction, default to ok unless there's an exception (then INTERNAL_ERROR).

Copy link
Contributor

Choose a reason for hiding this comment

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

if there's no status at all, relay (ingestion) or UI not sure defaults to unknown

}
}
}