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

feat: Tracing without performance #2493

Merged
merged 49 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
d486409
wip
bitsandfoxes Jul 18, 2023
3ec17d7
added propagation context
bitsandfoxes Jul 18, 2023
60dabd0
baggage fetching
bitsandfoxes Jul 19, 2023
8c90704
scope creates propagationcontext
bitsandfoxes Jul 19, 2023
3f88d89
http handler retrieves baggage from hub
bitsandfoxes Jul 19, 2023
56f14d9
keeping things internal
bitsandfoxes Jul 19, 2023
6fecb32
properly propagating things with tracing disabled
bitsandfoxes Jul 19, 2023
84971ed
wip
bitsandfoxes Jul 20, 2023
6c7aff1
simplifying
bitsandfoxes Jul 20, 2023
717b37e
caching parsed DSN
bitsandfoxes Jul 24, 2023
16494c6
reviewpoints
bitsandfoxes Jul 25, 2023
0a37731
continuing trace in ASP.NET Core
bitsandfoxes Jul 25, 2023
c6d632c
simplified
bitsandfoxes Jul 25, 2023
9f94934
simplified 2
bitsandfoxes Jul 25, 2023
b421c88
merged main
bitsandfoxes Jul 25, 2023
f4a6b04
cleanup
bitsandfoxes Jul 25, 2023
848af4e
fixed tracing middleware
bitsandfoxes Jul 25, 2023
dc0e022
wip
bitsandfoxes Jul 26, 2023
b973357
tests
bitsandfoxes Jul 28, 2023
522a752
Apply suggestions from code review
bitsandfoxes Jul 31, 2023
cb54916
objects as keys
bitsandfoxes Jul 31, 2023
7b54760
merge
bitsandfoxes Jul 31, 2023
d87e4d5
fixed using
bitsandfoxes Jul 31, 2023
cd02bce
logging the name of the missing key
bitsandfoxes Jul 31, 2023
d27622d
cleanup
bitsandfoxes Jul 31, 2023
6bfd515
comments
bitsandfoxes Jul 31, 2023
ffc633a
merged main
bitsandfoxes Jul 31, 2023
91b3bd1
renamed internal 'IsTracingEnabled' to 'IsPerformanceMonitoringEnabled'
bitsandfoxes Jul 31, 2023
3ed5a8f
test
bitsandfoxes Jul 31, 2023
dfc4274
istracingenabled
bitsandfoxes Jul 31, 2023
b812630
removed unused method
bitsandfoxes Jul 31, 2023
9640278
fixed parsing dsn test
bitsandfoxes Jul 31, 2023
57ff2f5
last one? maybe?
bitsandfoxes Aug 1, 2023
dd1ed93
added release to options in verify
bitsandfoxes Aug 2, 2023
48ba10a
updated verify
bitsandfoxes Aug 2, 2023
75916f0
simplified
bitsandfoxes Aug 2, 2023
fde8865
reverted submodule bump
bitsandfoxes Aug 2, 2023
ee2a0c8
disabled hub
bitsandfoxes Aug 2, 2023
ced245b
Updated CHANGELOG.md
bitsandfoxes Aug 2, 2023
5c3b22e
setting release
bitsandfoxes Aug 2, 2023
cc049ad
missed a release
bitsandfoxes Aug 2, 2023
f072aad
trying to fix the verified
bitsandfoxes Aug 2, 2023
3cb0af4
line numbers
bitsandfoxes Aug 2, 2023
3dd2265
last round of verified?
bitsandfoxes Aug 2, 2023
60d1f1c
reset
bitsandfoxes Aug 2, 2023
b5afd16
dear lord.. please accept these verified update
bitsandfoxes Aug 2, 2023
88ba20c
added missing mono
bitsandfoxes Aug 2, 2023
bde03c6
whitespace?
bitsandfoxes Aug 2, 2023
139579a
Apply suggestions from code review
bitsandfoxes Aug 3, 2023
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
7 changes: 0 additions & 7 deletions src/Sentry.AspNet/HttpContextExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Security.Policy;
using Sentry.Extensibility;

namespace Sentry.AspNet;
Expand Down Expand Up @@ -91,12 +90,6 @@ public static ITransaction StartSentryTransaction(this HttpContext httpContext)
const string transactionOperation = "http.server";

var transactionContext = SentrySdk.ContinueTrace(traceHeader, baggageHeader, transactionName, transactionOperation);
if (transactionContext is null)
{
throw new NullReferenceException("Failed to create a transaction context. " + "Tracing was " +
"most likely disabled. Make sure set a `TraceSampler` and to set the `TracesSampleRate` > 0.");
}

transactionContext.NameSource = TransactionNameSource.Url;

var customSamplingContext = new Dictionary<string, object?>(3, StringComparer.Ordinal)
Expand Down
8 changes: 4 additions & 4 deletions src/Sentry.AspNetCore/SentryMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ namespace Sentry.AspNetCore;
/// </summary>
internal class SentryMiddleware : IMiddleware
{
internal const string TraceHeaderItemKey = "sentry-trace-header";
internal const string BaggageHeaderItemKey = "sentry-baggage-header";
internal const string TransactionContextItemKey = "sentry-transaction-context";
internal static readonly object TraceHeaderItemKey = new();
internal static readonly object BaggageHeaderItemKey = new();
internal static readonly object TransactionContextItemKey = new();

private readonly Func<IHub> _getHub;
private readonly SentryAspNetCoreOptions _options;
Expand Down Expand Up @@ -99,7 +99,7 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next)
var baggageHeader = context.TryGetBaggageHeader(_options);
var transactionContext = hub.ContinueTrace(traceHeader, baggageHeader);

// Adding the headers and thw TransactionContext to the context to be picked up by the Sentry tracing middleware
// Adding the headers and the TransactionContext to the context to be picked up by the Sentry tracing middleware
context.Items.Add(TraceHeaderItemKey, traceHeader);
context.Items.Add(BaggageHeaderItemKey, baggageHeader);
context.Items.Add(TransactionContextItemKey, transactionContext);
jamescrosswell marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
5 changes: 2 additions & 3 deletions src/Sentry.AspNetCore/SentryTracingMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public SentryTracingMiddleware(
context.Items.TryGetValue(SentryMiddleware.TransactionContextItemKey, out var transactionContextObject);
if (transactionContextObject is not TransactionContext transactionContext)
{
throw new KeyNotFoundException($"Failed to retrieve the '{SentryMiddleware.TransactionContextItemKey}' from the HttpContext items.");
throw new KeyNotFoundException($"Failed to retrieve the '{nameof(SentryMiddleware.TransactionContextItemKey)}' from the HttpContext items.");
}

// It's important to try and set the transaction name to some value here so that it's available for use
Expand Down Expand Up @@ -76,8 +76,7 @@ public SentryTracingMiddleware(
dynamicSamplingContext = DynamicSamplingContext.Empty;
}

var hub = _getHub();
var transaction = hub.StartTransaction(transactionContext, customSamplingContext, dynamicSamplingContext);
var transaction = _getHub().StartTransaction(transactionContext, customSamplingContext, dynamicSamplingContext);

_options.LogInfo(
"Started transaction with span ID '{0}' and trace ID '{1}'.",
Expand Down
17 changes: 16 additions & 1 deletion src/Sentry/DynamicSamplingContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,19 @@ public static DynamicSamplingContext CreateFromTransaction(TransactionTracer tra
}

public static DynamicSamplingContext CreateFromPropagationContext(SentryPropagationContext propagationContext, SentryOptions options)
=> new(propagationContext.TraceId, options.ParsedDsn.PublicKey, propagationContext.IsSampled);
{
var publicKey = options.ParsedDsn.PublicKey;
var traceId = propagationContext.TraceId;
var release = options.SettingLocator.GetRelease();
var environment = options.SettingLocator.GetEnvironment();

return new DynamicSamplingContext(
traceId,
publicKey,
null,
release: release,
environment:environment);
}
bitsandfoxes marked this conversation as resolved.
Show resolved Hide resolved
}

internal static class DynamicSamplingContextExtensions
Expand All @@ -156,4 +168,7 @@ internal static class DynamicSamplingContextExtensions

public static DynamicSamplingContext CreateDynamicSamplingContext(this TransactionTracer transaction, SentryOptions options)
=> DynamicSamplingContext.CreateFromTransaction(transaction, options);

public static DynamicSamplingContext CreateDynamicSamplingContext(this SentryPropagationContext propagationContext, SentryOptions options)
=> DynamicSamplingContext.CreateFromPropagationContext(propagationContext, options);
}
8 changes: 6 additions & 2 deletions src/Sentry/Extensibility/DisabledHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,15 @@ public void BindException(Exception exception, ISpan span)
/// <summary>
/// Returns null.
/// </summary>
public TransactionContext? ContinueTrace(
public TransactionContext ContinueTrace(
SentryTraceHeader? traceHeader,
BaggageHeader? baggageHeader,
string? name = null,
string? operation = null) => null;
string? operation = null)
{
// Transactions from DisabledHub are always sampled out
return new TransactionContext(string.Empty, string.Empty, false);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we could do the same thing we've done for the DisabledHub.Instance here, to avoid creating a new object every time this method is called.

Not sure where to put that... maybe TransactionContext.Disabled or TransactionContext.DisabledInstance?

}

/// <summary>
/// No-Op.
Expand Down
10 changes: 1 addition & 9 deletions src/Sentry/Extensibility/HubAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,9 @@ public void BindException(Exception exception, ISpan span) =>
/// Forwards the call to <see cref="SentrySdk"/>.
/// </summary>
[DebuggerStepThrough]
[Obsolete("This method will be removed in a future major version. Use the `GetTraceParent` instead.")]
public SentryTraceHeader? GetTraceHeader()
=> SentrySdk.GetTraceHeader();

/// <summary>
/// Forwards the call to <see cref="SentrySdk"/>.
/// </summary>
[DebuggerStepThrough]
public SentryTraceHeader? GetTraceParent()
=> SentrySdk.GetTraceParent();

/// <summary>
/// Forwards the call to <see cref="SentrySdk"/>.
/// </summary>
Expand All @@ -125,7 +117,7 @@ public void BindException(Exception exception, ISpan span) =>
/// Forwards the call to <see cref="SentrySdk"/>.
/// </summary>
[DebuggerStepThrough]
public TransactionContext? ContinueTrace(
public TransactionContext ContinueTrace(
SentryTraceHeader? traceHeader,
BaggageHeader? baggageHeader,
string? name = null,
Expand Down
11 changes: 3 additions & 8 deletions src/Sentry/IHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,12 @@ ITransaction StartTransaction(
ISpan? GetSpan();

/// <summary>
/// Gets the Sentry trace header for the last active span.
/// Gets the Sentry trace header that allows tracing across services
/// </summary>
SentryTraceHeader? GetTraceHeader();

/// <summary>
/// Gets the Sentry trace header of the parent that allows tracing across services
/// </summary>
SentryTraceHeader? GetTraceParent();

/// <summary>
/// Gets the Sentry "baggage" header that allows tracing across services
/// Gets the Sentry baggage header that allows tracing across services
/// </summary>
BaggageHeader? GetBaggage();

Expand All @@ -60,7 +55,7 @@ ITransaction StartTransaction(
/// <remarks>
/// If no "sentry-trace" header is provided a random trace ID and span ID is created.
/// </remarks>
TransactionContext? ContinueTrace(
TransactionContext ContinueTrace(
SentryTraceHeader? traceHeader,
BaggageHeader? baggageHeader,
string? name = null,
Expand Down
37 changes: 16 additions & 21 deletions src/Sentry/Internal/Hub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,34 +195,32 @@ public void BindException(Exception exception, ISpan span)

public ISpan? GetSpan() => ScopeManager.GetCurrent().Key.Span;

[Obsolete("Use GetTraceParent instead")]
public SentryTraceHeader? GetTraceHeader() => GetTraceParent();

public SentryTraceHeader GetTraceParent()
public SentryTraceHeader GetTraceHeader()
{
if (_options.IsTracingEnabled && GetSpan()?.GetTraceHeader() is { } traceHeader)
if (GetSpan()?.GetTraceHeader() is { } traceHeader)
{
return traceHeader;
}
bitsandfoxes marked this conversation as resolved.
Show resolved Hide resolved

// Fallback: Either tracing was disabled or there was no span on the current scope.
// With either tracing disabled or no active span on the current scope we fall back to the propagation context
var propagationContext = ScopeManager.GetCurrent().Key.PropagationContext;
// With performance disabled, we must not append a sampling decision.
// In either case, we must not append a sampling decision.
return new SentryTraceHeader(propagationContext.TraceId, propagationContext.SpanId, null);
bitsandfoxes marked this conversation as resolved.
Show resolved Hide resolved
}

public BaggageHeader? GetBaggage()
public BaggageHeader GetBaggage()
{
if (_options.IsTracingEnabled && GetSpan() is TransactionTracer {DynamicSamplingContext: {IsEmpty: false} dsc} )
if (GetSpan() is TransactionTracer { DynamicSamplingContext: { IsEmpty: false } dsc } )
{
return dsc.ToBaggageHeader();
}
bitsandfoxes marked this conversation as resolved.
Show resolved Hide resolved

var propagationContext = ScopeManager.GetCurrent().Key.PropagationContext;
return propagationContext.DynamicSamplingContext?.ToBaggageHeader();
propagationContext.DynamicSamplingContext ??= propagationContext.CreateDynamicSamplingContext(_options);
return propagationContext.DynamicSamplingContext.ToBaggageHeader();
}

public TransactionContext? ContinueTrace(
public TransactionContext ContinueTrace(
SentryTraceHeader? traceHeader,
BaggageHeader? baggageHeader,
string? name = null,
Expand All @@ -231,15 +229,12 @@ public SentryTraceHeader GetTraceParent()
var propagationContext = SentryPropagationContext.CreateFromHeaders(_options.DiagnosticLogger, traceHeader, baggageHeader);
ConfigureScope(scope => scope.PropagationContext = propagationContext);
bitsandfoxes marked this conversation as resolved.
Show resolved Hide resolved

if (_options.IsTracingEnabled)
{
return new TransactionContext(
name ?? string.Empty,
operation ?? string.Empty,
new SentryTraceHeader(propagationContext.TraceId, propagationContext.SpanId, propagationContext.IsSampled));
}

return null;
// If we have to create a new SentryTraceHeader we don't make a sampling decision
traceHeader ??= new SentryTraceHeader(propagationContext.TraceId, propagationContext.SpanId, null);
return new TransactionContext(
name ?? string.Empty,
operation ?? string.Empty,
traceHeader);
}

public void StartSession()
Expand Down Expand Up @@ -401,7 +396,7 @@ SentryId IHubEx.CaptureEventInternal(SentryEvent evt, Hint? hint, Scope? scope)
else
{
var propagationContext = actualScope.PropagationContext;
propagationContext.DynamicSamplingContext ??= DynamicSamplingContext.CreateFromPropagationContext(propagationContext, _options);
propagationContext.DynamicSamplingContext ??= propagationContext.CreateDynamicSamplingContext(_options);

evt.Contexts.Trace.TraceId = propagationContext.TraceId;
evt.Contexts.Trace.SpanId = propagationContext.SpanId;
Expand Down
2 changes: 1 addition & 1 deletion src/Sentry/SentryHttpMessageHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ private void HandleResponse(HttpResponseMessage response, ISpan? span, string me
private void AddSentryTraceHeader(HttpRequestMessage request)
{
// Set trace header if it hasn't already been set
if (!request.Headers.Contains(SentryTraceHeader.HttpHeaderName) && _hub.GetTraceParent() is { } traceHeader)
if (!request.Headers.Contains(SentryTraceHeader.HttpHeaderName) && _hub.GetTraceHeader() is { } traceHeader)
{
request.Headers.Add(SentryTraceHeader.HttpHeaderName, traceHeader.ToString());
}
Expand Down
2 changes: 1 addition & 1 deletion src/Sentry/SentryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ public string? Dsn {
}
}

private Dsn? _parsedDsn;
internal Dsn? _parsedDsn;
internal Dsn ParsedDsn => _parsedDsn ??= Sentry.Dsn.Parse(Dsn!);

private readonly Lazy<string> _sentryBaseUrl;
Expand Down
48 changes: 24 additions & 24 deletions src/Sentry/SentryPropagationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,33 @@ internal class SentryPropagationContext
public SentryId TraceId { get; }
public SpanId SpanId { get; }
public SpanId? ParentSpanId { get; }
public bool? IsSampled { get; }
public DynamicSamplingContext? DynamicSamplingContext { get; set; }

private SentryPropagationContext(
private DynamicSamplingContext? _dynamicSamplingContext;
public DynamicSamplingContext? DynamicSamplingContext
{
get => _dynamicSamplingContext;
set
{
if (_dynamicSamplingContext is null)
{
_dynamicSamplingContext = value;
}
else
{
throw new Exception("should not do that.");
bitsandfoxes marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

internal SentryPropagationContext(
SentryId traceId,
SpanId parentSpanId,
bool? isSampled,
DynamicSamplingContext? dynamicSamplingContext)
DynamicSamplingContext? dynamicSamplingContext = null)
{
TraceId = traceId;
SpanId = SpanId.Create();
ParentSpanId = parentSpanId;
DynamicSamplingContext = dynamicSamplingContext;
IsSampled = isSampled;
}

public SentryPropagationContext()
Expand All @@ -31,28 +44,15 @@ public SentryPropagationContext()

public static SentryPropagationContext CreateFromHeaders(IDiagnosticLogger? logger, SentryTraceHeader? traceHeader, BaggageHeader? baggageHeader)
{
logger?.LogDebug("Creating a propagation context from headers.");

if (traceHeader == null)
{
logger?.LogInfo("Sentry trace header is null. Creating new Sentry Propagation Context.");
return new SentryPropagationContext();
}

try
{
DynamicSamplingContext? dynamicSamplingContext = null;
if (baggageHeader is not null)
{
dynamicSamplingContext = baggageHeader.CreateDynamicSamplingContext();
}

dynamicSamplingContext?.Items.TryGetValue("sampled", out var isSampled);
return new SentryPropagationContext(traceHeader.TraceId, traceHeader.SpanId, traceHeader.IsSampled, dynamicSamplingContext);
}
catch (Exception e)
{
logger?.LogError(
"Failed to create the 'SentryPropagationContext' from provided headers: '{0}', '{1}'. " +
"\nFalling back to new PropagationContext.", e, traceHeader, baggageHeader);
return new SentryPropagationContext();
}
var dynamicSamplingContext = baggageHeader?.CreateDynamicSamplingContext();
return new SentryPropagationContext(traceHeader.TraceId, traceHeader.SpanId, dynamicSamplingContext);
}
}
12 changes: 2 additions & 10 deletions src/Sentry/SentrySdk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -611,20 +611,12 @@ public static void BindException(Exception exception, ISpan span)
=> CurrentHub.GetSpan();

/// <summary>
/// Gets the Sentry trace header.
/// Gets the Sentry trace header of the parent that allows tracing across services
/// </summary>
[DebuggerStepThrough]
[Obsolete("This method will be removed in a future major version. Use the `GetTraceParent` instead.")]
public static SentryTraceHeader? GetTraceHeader()
=> CurrentHub.GetTraceHeader();

/// <summary>
/// Gets the Sentry trace header of the parent that allows tracing across services
/// </summary>
[DebuggerStepThrough]
public static SentryTraceHeader? GetTraceParent()
=> CurrentHub.GetTraceParent();

/// <summary>
/// Gets the Sentry "baggage" header that allows tracing across services
/// </summary>
Expand All @@ -639,7 +631,7 @@ public static void BindException(Exception exception, ISpan span)
/// If no "sentry-trace" header is provided a random trace ID and span ID is created.
/// </remarks>
[DebuggerStepThrough]
public static TransactionContext? ContinueTrace(
public static TransactionContext ContinueTrace(
SentryTraceHeader? traceHeader,
BaggageHeader? baggageHeader,
string? name = null,
Expand Down
Loading
Loading