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

Document StartOrContinueTrace (vs StartTransaction) #3838

Open
jamescrosswell opened this issue Dec 10, 2024 · 3 comments
Open

Document StartOrContinueTrace (vs StartTransaction) #3838

jamescrosswell opened this issue Dec 10, 2024 · 3 comments
Milestone

Comments

@jamescrosswell
Copy link
Collaborator

jamescrosswell commented Dec 10, 2024

Originally posted by @jamescrosswell in #3836

The SDK includes a StartOrContinueTrace method that returns a transaction context but doesn't use that context to start a new transaction...

/// <summary>
/// Starts or continues a Sentry trace.
/// </summary>
public static void StartOrContinueTrace(this HttpContext httpContext)
{
var options = SentrySdk.CurrentOptions;
var traceHeader = TryGetSentryTraceHeader(httpContext, options);
var baggageHeader = TryGetBaggageHeader(httpContext, options);
var method = httpContext.Request.HttpMethod;
var path = httpContext.Request.Path;
var transactionName = $"{method} {path}";
const string operation = "http.server";
SentrySdk.ContinueTrace(traceHeader, baggageHeader, transactionName, operation);
}
/// <summary>
/// Starts a new Sentry transaction that encompasses the currently executing HTTP request.
/// </summary>
public static ITransactionTracer StartSentryTransaction(this HttpContext httpContext)
{
var method = httpContext.Request.HttpMethod;
var path = httpContext.Request.Path;
var options = SentrySdk.CurrentOptions;
var traceHeader = TryGetSentryTraceHeader(httpContext, options);
var baggageHeader = TryGetBaggageHeader(httpContext, options);
var transactionName = $"{method} {path}";
const string transactionOperation = "http.server";
var transactionContext = SentrySdk.ContinueTrace(traceHeader, baggageHeader, transactionName, transactionOperation);
transactionContext.NameSource = TransactionNameSource.Url;
var customSamplingContext = new Dictionary<string, object?>(3, StringComparer.Ordinal)
{
["__HttpMethod"] = method,
["__HttpPath"] = path,
["__HttpContext"] = httpContext,
};
// Set the Dynamic Sampling Context from the baggage header, if it exists.
var dynamicSamplingContext = baggageHeader?.CreateDynamicSamplingContext();
if (traceHeader is not null && baggageHeader is null)
{
// We received a sentry-trace header without a baggage header, which indicates the request
// originated from an older SDK that doesn't support dynamic sampling.
// Set DynamicSamplingContext.Empty to "freeze" the DSC on the transaction.
// See:
// https://develop.sentry.dev/sdk/performance/dynamic-sampling-context/#freezing-dynamic-sampling-context
// https://develop.sentry.dev/sdk/performance/dynamic-sampling-context/#unified-propagation-mechanism
dynamicSamplingContext = DynamicSamplingContext.Empty;
}
var transaction = SentrySdk.StartTransaction(transactionContext, customSamplingContext, dynamicSamplingContext);
transaction.Contexts.Trace.Origin = AspNetOrigin;
SentrySdk.ConfigureScope(scope => scope.Transaction = transaction);
httpContext.Items[HttpContextTransactionItemName] = transaction;
if (options?.SendDefaultPii is true)
{
transaction.Request.Cookies = string.Join("; ", httpContext.Request.Cookies.AllKeys.Select(x => $"{x}={httpContext.Request.Cookies[x]?.Value}"));
}
return transaction;
}

Under the hood, this propagates trace headers even when performance is disabled:

var propagationContext = SentryPropagationContext.CreateFromHeaders(_options.DiagnosticLogger, traceHeader, baggageHeader);
ConfigureScope(scope => scope.PropagationContext = propagationContext);

Later this information gets used when forming headers for outbound requests:

public SentryTraceHeader GetTraceHeader()
{
if (GetSpan()?.GetTraceHeader() is { } traceHeader)
{
return traceHeader;
}
// With either tracing disabled or no active span on the current scope we fall back to the propagation context
var propagationContext = CurrentScope.PropagationContext;
// In either case, we must not append a sampling decision.
return new SentryTraceHeader(propagationContext.TraceId, propagationContext.SpanId, null);
}

That intent should be clearly documented in the summary for the StartOrContinueTrace method.

@jamescrosswell jamescrosswell added this to the 5.0.0 milestone Dec 10, 2024
@bitsandfoxes
Copy link
Contributor

If I remember correctly this was part of Tracing without Performance and allows users to start or continue a trace without having to rely on transactions. I actually don't know about the current state of this feature, maybe @cleptric has some insights?

@cleptric
Copy link
Member

https://docs.sentry.io/platforms/dotnet/tracing/trace-propagation/custom-instrumentation/#step-1-extract-incoming-tracing-information explains how the API should be used. It's important that the SDK updates the PropagationContext under the hood, so even if tracing is disabled, all events emitted still have the same, propagated trace id attached.

@jamescrosswell
Copy link
Collaborator Author

I see, so this just stores the sentry-trace and baggage in the propagation context so that it can be extracted later to form headers for any downstream requests.

Maybe sufficient to document this in the public facing API so that SDK users can more easily understand which methods they should be calling then.

Thanks @cleptric @bitsandfoxes !

@jamescrosswell jamescrosswell changed the title Remove StartOrContinueTrace and/or rename StartTransaction Document StartOrContinueTrace (vs StartTransaction) Dec 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Development

No branches or pull requests

3 participants