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

Option for making ASP.NET Core spans root? #1773

Closed
martinothamar opened this issue Aug 12, 2022 · 1 comment
Closed

Option for making ASP.NET Core spans root? #1773

martinothamar opened this issue Aug 12, 2022 · 1 comment
Labels
comp:extensions.enrichment.aspnetcore Things related to OpenTelemetry.Extensions.Enrichment.AspNetCore enhancement New feature or request

Comments

@martinothamar
Copy link

Option for making ASP.NET Core spans root?

In microservices architecture, it's common to have a gateway API/backend-for-frontend type API which handles authentication and whatnot and does fanout of requests to downstream microservices. Our gateway API handles requests from both users of a web-portal and external clients (APIs, background workers etc).

We want all requests to the gateway API to be root spans (not attached to a client-controlled trace context), but there is no easy way to accomplish it currently. But here's how I made it work

_ = Sdk.SuppressInstrumentation; // Just to trigger static constructor. The static constructor in Sdk initializes Propagators.DefaultTextMapPropagator which we depend on below
Sdk.SetDefaultTextMapPropagator(new OtelPropagator(Propagators.DefaultTextMapPropagator));
DistributedContextPropagator.Current = new AspNetCorePropagator();

internal sealed class OtelPropagator : TextMapPropagator
{
    private readonly TextMapPropagator inner;

    public OtelPropagator(TextMapPropagator inner) => this.inner = inner;

    public override ISet<string> Fields => inner.Fields;

    public override PropagationContext Extract<T>(PropagationContext context, T carrier, Func<T, string, IEnumerable<string>> getter)
    {
        if (carrier is HttpRequest req)
            return default;
        return inner.Extract(context, carrier, getter);
    }

    public override void Inject<T>(PropagationContext context, T carrier, Action<T, string, string> setter) =>
        inner.Inject(context, carrier, setter);
}

internal sealed class AspNetCorePropagator : DistributedContextPropagator
{
    private readonly DistributedContextPropagator inner;

    public AspNetCorePropagator() => this.inner = CreateDefaultPropagator();

    public override IReadOnlyCollection<string> Fields => inner.Fields;

    public override IEnumerable<KeyValuePair<string, string?>>? ExtractBaggage(object? carrier, PropagatorGetterCallback? getter)
    {
        if (carrier is IHeaderDictionary)
            return null;

        return inner.ExtractBaggage(carrier, getter);
    }


    public override void ExtractTraceIdAndState(object? carrier, PropagatorGetterCallback? getter, out string? traceId, out string? traceState)
    {
        if (carrier is IHeaderDictionary)
        {
            traceId = null;
            traceState = null;
            return;
        }

        inner.ExtractTraceIdAndState(carrier, getter, out traceId, out traceState);
    }

    public override void Inject(Activity? activity, object? carrier, PropagatorSetterCallback? setter) =>
        inner.Inject(activity, carrier, setter);
}

The System.Diagnostics.DistributedContextPropagator is to prevent ASP.NET Core from intializing Activity with parent from request trace context, while using the TextMapPropagator in a similar manner for the AspNetCore.Instrumentation package. Since parent can't be changed after an Activity has been created, this is the only way to do it AFAIK. Are there other options that I'm overlooking?

We could always create our own AspNetCore instrumentation, but that seems less then ideal as well.

I would think that this was a pretty common use case for APIs where you can't let external clients dictate the organization of traces, but couldn't find any related issue. We use tempo for trace storage currently where one should prevent traces from getting too large

@martinothamar martinothamar added the enhancement New feature or request label Aug 12, 2022
@vishweshbankwar vishweshbankwar transferred this issue from open-telemetry/opentelemetry-dotnet May 14, 2024
@Kielek Kielek added the comp:extensions.enrichment.aspnetcore Things related to OpenTelemetry.Extensions.Enrichment.AspNetCore label May 17, 2024
@martinjt
Copy link
Member

martinjt commented Jun 2, 2024

Unfortunately that is the only way.

@martinjt martinjt closed this as completed Jun 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp:extensions.enrichment.aspnetcore Things related to OpenTelemetry.Extensions.Enrichment.AspNetCore enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants