-
Notifications
You must be signed in to change notification settings - Fork 305
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Selective Http Trace and Baggage Propagation #1853
Comments
Couldn't you do this? public async Task<string> CallThirdPartyServiceAndReturnResponse(Uri requestUri)
{
// Turn off flow of Activity & Baggage for this ExecutionContext
using var flow = ExecutionContext.SuppressFlow();
// Make the call with no trace or baggage to inject
return await this.httpClient.GetStringAsync(requestUri);
} The nice thing about that is it works (in theory) for all things not just HttpClient. Same thing but calling some message queue: public async Task PostMessageToThirdPartyService(Uri requestUri)
{
// Turn off flow of Activity & Baggage for this ExecutionContext
using var flow = ExecutionContext.SuppressFlow();
// Post message with no trace or baggage to inject
await this.myAwesomeMessageService.PostMessageAsync(requestUri);
}
|
From what I can tell from testing this, it does stop activity from being created, however, the runtime code does not honor that and still propagates the trace data. |
So ultimately, the issue is that I need to disable the runtime propagation, but if I do that (with the switches), then the Http instrumentation doesn't kick in, because it's based on the diagnostic listener that's generated by the |
Ya it will still create an If you wanted to stop the You could probably do something like this: // At call site
using var scope = MySampler.SuppressActivityCreation();
await httpClient.DoSomethingAsync();
// Set as OTel sampler
internal sealed class MySampler : Sampler
{
private static readonly AsyncLocal<bool> SuppressActivity = new AsyncLocal<bool>();
private readonly Sampler innerSampler;
public MySampler(Sampler innerSampler)
{
this.innerSampler = innerSampler ?? throw new ArgumentNullException(nameof(innerSampler));
}
public static IDisposable SuppressActivityCreation()
{
var previousValue = SuppressActivity.Value;
SuppressActivity.Value = true;
return new MySamplerScope(previousValue);
}
public override SamplingResult ShouldSample(in SamplingParameters samplingParameters)
{
if (SuppressActivity.Value)
{
return new SamplingResult(SamplingDecision.Drop);
}
return this.innerSampler.ShouldSample(in samplingParameters);
}
private sealed class MySamplerScope : IDisposable
{
private readonly bool previousValue;
public MySamplerScope(bool previousValue)
{
this.previousValue = previousValue;
}
public void Dispose()
{
SuppressActivity.Value = this.previousValue;
}
}
} I didn't test any of that just an idea! |
I think there are two fundamental problems:
Having a propagator configurable per endpoint might solve both. We can try to extend class ConfigurablePropagator: Propagator {
public static readonly AsyncLocal<string> Endpoint = new AsyncLocal<string>();
public override void Inject(...) {
propagators[Endpoint.Value].Inject(...)
}
}
DistributedContextPropagator Current = DistributedContextPropagator.CreateNoOutputPropagator(); // I hope it works
Sdk.SetDefaultTextMapPropagator(new ConfigurablePropagator(....));
ConfigurablePropagator.Endpoint = "https://external-no-baggage-prop.com";
await httpClient.SendAsync()...
ConditionalPropagator.Endpoint = null; UPDATE: I assume it should be possible to implement a customizeable DistributedContextPropagator and give .NET a custom propagator. |
@CodeBlanch I'm saying that isn't happening. The propagation happens at the DiagnosticHandler level in the runtime. It's not even touching otel. So it's not creating the Activity, but is still propagating the context.
JS and go, you have to add the propagation handler from otel to the specific HTTP client. Since dotnet does this in the runtime, there's no way to turn it off. It happens even if you don't have otel installed at all. |
This sounds super useful to me. Just yesterday I wrote a I think the main use case should be opt-in instead of opt-out. I don't think it's reasonable to map all of the possible (transitive) external domains. I would also be happy if this was something I could explicitly attach to an HttpClient/Handler, or configure with a named client. My |
Looking for some feedback on a change to the HttpClient instrumentation package I've been playing with.
Ultimately, I'm trying to get to a point where you can choose which HttpClient's will have trace/baggage propagation and which won't. With the ultimate goal of stopping trace/baggage leakage to domains you don't control.
I originally thought about domain allow/deny lists, but I'm not sure that's the right approach. So then I pivoted to adding a handler instead.
Right now, TracePropagation happens in 2 places.
The DiagnosticHandler added by the runtime
The HttpClient instrumentation package listening to a Diagnostic source that is written to by 1
You can disable 1 by using the following 2 switches:
This has the effect of disabling propagation for the entire application. Further, it also stops the generation of the outbound HTTP span.
In an ideal world, you'd be able to do this at a HttpClient level, and selective choose:
The scenario where this is useful is where you're using a third party API which you want to track the performance of, but you don't want them to receive baggage and trace details.
What I've been toying with is adding something to the Http Instrumentation package that allows you to "turn off" instrumentation, then add it back it in incrementally.
Then have 2 handlers such that you can do..
Then add that an extension like
(Names TBC)
The issue I see right now is that the
DiagnosticListener
is the way we listen to the http calls, and that also does propagation.So I could make it so that Handler generates the
Activity
directly, and ignore the diagnostic listener. In effect the diagnostic listener would only be relevant for "Auto instrumented" stuff coming out of the runtime. The alternative is to have the handler only generate diagnostics when it should be traced, and not in other scenarios. Or I use a different diagnostic name.So is this something worthwhile for people? is the approach viable?
The text was updated successfully, but these errors were encountered: