Open stevejgordon opened 10 months ago
Could you override this in the HttpClientFactory?
builder.Services.AddOpenTelemetry()
.WithTracing(tpb =>
{
tpb.AddOtlpExporter(o => {
o.HttpClientFactory = () => {
return new HttpClient( ... );
};
});
});
@martinjt Thanks for the suggestion. I hadn't discovered that hook, and indeed, that does let me solve the issue when using http/protobuf
. It's a bit involved, though, so I would still propose the logic be updated to accept this directly. Again, happy to contribute that via a PR unless there's a specific reason we don't want to do this.
I'll be honest; I'm not sure what happens in grpc/protobuf
scenario where two entries with the same key are defined in the gRPC metadata. I don't know enough about the protocol or the .NET implementation to know what goes over the wire.
I think that changing headers that have been added should require that extra work.
I do think that it should be handled better. So saying "you cannot amend existing headers" in that exception would be better. Like adding an Auth header for instance.
Also, maybe having an option that allows a delegate to the HeadersCollection might be an option?
Either way, I don't think this is an easy fix. We ended up using resource attributes for your usecase instead and extracting that anonymous metadata at ingest.
One other option would be allowing the OtlpExporter to be more extensible by exposing some of the inner elements to allow new derived types to be created. I'd be interested to see how other languages are handling it.
@martinjt I'm not sure I agree.
The consumer provider headers are added first, and then the SDK adds its standard headers, just User-Agent
right now. If a user has explicitly provided a header, then it seems reasonable to assume that is preferred over anything the SDK wants to add.
Either way, I don't think this is an easy fix.
Unless I'm missing something, the fix is that the actions passed in should check for an existing key before adding it. In the case of the BaseOtlpHttpExportClient
, this is a small change to the ctor:
this.Headers = options.GetHeaders<Dictionary<string, string>>((d, k, v) => d.TryAdd(k, v));
One other problem I foresee with resolving it via the handler approach is that it complicates scenarios for the distro where the consumer of that might want to provide their own HttpClient
factory.
@stevejgordon It would be good to get this clarification from spec itself. Spec does not outline how this conflict should be handled.
@vishweshbankwar, Can you point me to the best place to raise this? I'd assumed it was more an implementation detail of the agent but I'm happy to raise it somewhere more central.
Bug Report
Affected Package(s):
Runtime version:
net8.0
)Symptom
Including a
User-Agent
header inOtlpExporterOptions
produces an exception with the HTTP exporter and an undesired behaviour for the GRPC exporter.What is the expected behavior?
If consuming code provides a
User-Agent
header, this should be preferred over the value fromOtlpExporterOptions.StandardHeaders
.What is the actual behavior?
When the agent is configured to use the
http/protobuf
protocol, anArgumentException
is thrown due to an attempt to add a duplicate key.When the agent is configured to use the
grpc/protobuf
protocol, no exception is thrown, however, theUser-Agent
header fromOtlpExporterOptions.StandardHeaders
will also be added to the metadata.Reproduce
Add a custom
User-Agent
header when adding an OTLP exporter to aTracerProviderBuilder
, as follows:Run the application with at least one span being created and sent to the backend.
Additional Context
This specific scenario of setting the
User-Agent
header is likely rare. In our case, we are starting work on an Elastic OTel Agent Distro and would like to update the header to include our version information (in addition to the Otel SDK version info). Having reviewed the current code, this could also occur if any furtherOtlpExporterOptions.StandardHeaders
are added in the future, which conflict with those set on the options by a consumer.I would propose updating the implementation such that if any header from
OtlpExporterOptions.StandardHeaders
is already defined on the consumer-providedHeaders
, then the code should not attempt to add the standard header.I'm opening this issue to discuss, as this is a blocker for our work. I would be happy to contribute a PR to fix this.