-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Propagate tracestate header in the OpenTelemetry tracer #22693
Propagate tracestate header in the OpenTelemetry tracer #22693
Conversation
Signed-off-by: Alex Ellis <ellisonjtk@gmail.com>
Signed-off-by: Alex Ellis <ellisonjtk@gmail.com>
Signed-off-by: Alex Ellis <ellisonjtk@gmail.com>
Signed-off-by: Alex Ellis <ellisonjtk@gmail.com>
key: "service.name" | ||
value: | ||
string_value: "unknown_service:envoy" | ||
instrumentation_library_spans: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be resource_spans:
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think as written it's OK, since instrumentation_library_spans
is the child field of resource_spans
, but now that I think about it, this should really be scope_spans
with that other PR. This is the classic dueling PRs though, where with name change, this test would only pass once the other is submitted...
Happy to fix once the other PR is in, or if this one is merged first I can update this code in the other PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Speaking of that PR :) Updated this with scope_spans
to match the new behavior. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Not really related to this PR but interested in how to leverage the config at https://github.com/envoyproxy/envoy/blob/main/test/extensions/tracers/opentelemetry/opentelemetry_tracer_impl_test.cc#L337-L357. Not clear from the test code where this is configured.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I definitely think it could use a little refactoring to be clearer (especially the bytes setting). I was currently using it to verify the final span that the Tracer exports, but so far I've only added the exact proto matching with this config for a few of the tests (you'll see sendMessageRaw_(_, _)
in others instead of sendMessageRaw_(Grpc::ProtoBufferEqIgnoreRepeatedFieldOrdering(request_proto), _)
). For legibility, I think it would also be helpful to only test the specific fields for each test to help reduce the busyness of each expectation.
/assign-from @envoyproxy/first-pass-reviewers |
@envoyproxy/first-pass-reviewers assignee is @tonya11en |
Signed-off-by: Alex Ellis <ellisonjtk@gmail.com>
Signed-off-by: Alex Ellis <ellisonjtk@gmail.com>
Signed-off-by: Alex Ellis <ellisonjtk@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, thanks, just a few minor feedback items.
/wait
// See https://www.w3.org/TR/trace-context/#processing-model-for-working-with-trace-context | ||
absl::string_view tracestate = ""; | ||
// TODO: what if tracestate is in multiple headers? Spec says we should combine, but Envoy | ||
// currently only surfaces the first seen. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See get
, which returns a GetResult
with all header values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for that pointer! Did a little digging, and it looks like ConnectionManagerImpl::ActiveStream::traceRequest
calls startSpan
with its RequestHeaderMapPtr request_headers_
(the RequestHeaderMap
containing the get
). Driver::startSpan
is defined with just Tracing::TraceContext
though, which only has getByKey
and forEach
.
With that in mind, I added some handling for this (and a test) with iteration over all the headers. Doesn't seem very efficient to me, but I think this works for the multiple headers case. Happy to improve if you have any suggestions 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe fix TraceContext
to deal with the appropriate header-specific aggregation behavior. I think any tracer interacting with tracestate will need this behavior. I think in most places that we see header get-by-key and the value is singular and not aggregated, there is some code smell that we haven't fully thought through the valid wire combinations.
TEST(SpanContextExtractorTest, ExtractSpanContextWithTracestate) { | ||
Http::TestRequestHeaderMapImpl request_headers{ | ||
{"traceparent", fmt::format("{}-{}-{}-{}", version, trace_id, parent_id, trace_flags)}, | ||
{"tracestate", "sample-tracestate"}}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there one for missing traceparent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah there isn't, good call! Technically it was already covered via the missing traceparent test above, but I think it's worthwhile to explicitly add one for it for legibility. I also fleshed out the comment in the extractor, mentioning that we are already checking for the existence of the traceparent header.
@@ -174,6 +176,9 @@ Tracing::SpanPtr Tracer::startSpan(const Tracing::Config& config, const std::str | |||
new_span.setId(Hex::uint64ToHex(span_id)); | |||
// Respect the previous span's sampled flag. | |||
new_span.setSampled(previous_span_context.sampled()); | |||
if (!previous_span_context.tracestate().empty()) { | |||
new_span.setTracestate(std::string{previous_span_context.tracestate()}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this tested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, via ParseSpanContextFromHeadersTest
.
In Driver::startSpan
in opentelemetry_tracer_impl.cc
, if there is a propagation header present, it'll call this fn, Tracer::startSpan
with the previous span context. Since we're manually adding the traceparent
propagation header (and tracestate
) in the the test and then calling driver_->startSpan
, the tracestate
in the header is passed through in the previous_span_context
here.
Signed-off-by: Alex Ellis <ellisonjtk@gmail.com>
Signed-off-by: Alex Ellis <ellisonjtk@gmail.com>
Signed-off-by: Alex Ellis <ellisonjtk@gmail.com>
This ready to merge @htuch @AlexanderEllis ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks will merge as it looks like comments have been addressed.
Commit Message: Propagate tracestate header in the OpenTelemetry tracer
Additional Description: OTLP Spans include the tracestate from the
tracestate
header. We can propagate that information from the headers to the Span. For an initial cut, we can just store whatever incoming tracestate header is in the span. In the future, it may make sense to add more handling to update the tracestate, but I don't believe we currently do any tracestate updates in Envoy.Risk Level: Low
Testing: Basic tests
Part of #9958