Added Support for W3C traceparent/tracestate propagation#255
Added Support for W3C traceparent/tracestate propagation#255yurishkuro merged 14 commits intojaegertracing:masterfrom tobiasstadler:w3c-traceparent
Conversation
Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
|
✅ Build jaeger-client-cpp 165 completed (commit 50d272a82a by @tobiasstadler) |
yurishkuro
left a comment
There was a problem hiding this comment.
Is there support for environment variable JAEGER_PROPAGATION? Per https://www.jaegertracing.io/docs/1.21/client-features/, "w3c" lowercase value is how this propagator can be selected.
| jaegerBaggageHeader, | ||
| traceContextHeaderName, | ||
| traceBaggageHeaderPrefix, | ||
| traceContextHeaderFormat == "W3C" ? Format::W3C : Format::JAEGER); |
There was a problem hiding this comment.
Q: why is this uppercase "W3C"? Where would the value come from?
There was a problem hiding this comment.
Via the configuration file, e.g.
headers:
TraceContextHeaderFormat: w3c
src/jaegertracing/Constants.h.in
Outdated
| static constexpr auto kSamplerParamTagKey = "sampler.param"; | ||
| static constexpr auto kTraceContextHeaderName = "uber-trace-id"; | ||
| static constexpr auto kTracerStateHeaderName = kTraceContextHeaderName; | ||
| static constexpr auto kW3CTraceContextHeaderName = "traceparent"; |
There was a problem hiding this comment.
I take it you're only supporting traceparent, but not tracestate. This makes it non-compliant propagator. At minimum it should pass on the tracestate unchanged, as was done in the Java client https://github.com/jaegertracing/jaeger-client-java/blob/5831d9ed7b465971d6c5211e3f56371cc083541a/jaeger-core/src/main/java/io/jaegertracing/internal/propagation/TraceContextCodec.java
There was a problem hiding this comment.
I will look into it
…docs/1.21/client-features/, Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
…ables Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
I implemented support for it |
|
✅ Build jaeger-client-cpp 166 completed (commit 596f828f95 by @tobiasstadler) |
|
✅ Build jaeger-client-cpp 167 completed (commit cf6a8948fb by @tobiasstadler) |
| const std::string& jaegerBaggageHeader, | ||
| const std::string& traceContextHeaderName, | ||
| const std::string& traceBaggageHeaderPrefix, | ||
| const std::string& traceStateHeaderName, |
There was a problem hiding this comment.
I find this rather confusing. The traceContextHeaderName setting is already somewhat dubious as it allows to change uber-trace-id header (which is a header defined by the Jaeger propagation spec) to something completely custom that is not covered by any spec (but still uses Jaeger header syntax - ¯\_(ツ)_/¯). Extending the same override capability to tracestate header, which is the official header of W3C spec, is in the same dubious category. I would rather not do that.
Note that it is a coincidence that "traceState" in traceContextHeaderName is the same term as W3C Trace Context - they are actually unrelated.
There was a problem hiding this comment.
Inalso find it kind of dubiose but tried to stick with the existing design. It is fine for me to „hardcore“ the name
| [this, &ctx, &debugID, &baggage, &traceState]( | ||
| const std::string& rawKey, const std::string& value) { | ||
| const auto key = normalizeKey(rawKey); | ||
| if (key == _headerKeys.traceContextHeaderName()) { |
There was a problem hiding this comment.
could we split the default Jaeger propagation header handling from traceparent handling? I.e. do not overload overridable traceContextHeaderName() use case with W3C propagation at all.
In all other Jaeger SDKs, the default Jaeger propagator and W3C propagator are implemented as independent classes.
There was a problem hiding this comment.
I will have a look.
To be sure, if a user selects the w3c format but not jaeger format, should only the two w3c headers be supported or also e.g. jaeger-debug-id?
There was a problem hiding this comment.
It's kind of up to you. Strictly speaking, the two extra headers jaeger-debug-id and jaeger-baggage are features of the default Jaeger propagator, so if you instead configure the B3 propagator they might be either supported on not, depending on the Jaeger client implementation. But I think it's a nice-to-have to support jaeger-debug-id in the W3C propagator since it provides an additional debugging capability to the users.
Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
|
✅ Build jaeger-client-cpp 168 completed (commit 8b60484b8d by @tobiasstadler) |
|
✅ Build jaeger-client-cpp 169 completed (commit 6cd47258eb by @tobiasstadler) |
| { | ||
| { | ||
| constexpr auto kConfigYAML = R"cfg( | ||
| propagation_format: w3c |
There was a problem hiding this comment.
Is the format of the config file documented somewhere?
There was a problem hiding this comment.
No, because I don't know where. Should I put it in examples/config.yml.
There was a problem hiding this comment.
I don't know either. Looks like it's not documented in the README, would be good to have a reference to examples/, and then include all properties in that sample config (comment them out if necessary). But this could be done via separate PR.
yurishkuro
left a comment
There was a problem hiding this comment.
@mdouaihy mind taking a look?
src/jaegertracing/Tracer.cpp
Outdated
| HTTPHeaderPropagator* httpHeaderPropagator; | ||
| if (config.propagationFormat() == propagation::Format::W3C) { | ||
| textPropagator = | ||
| new propagation::W3CTextMapPropagator(config.headers(), metrics); |
There was a problem hiding this comment.
Are headers() needed for W3C? If different headers are used it ceases to be W3C format.
There was a problem hiding this comment.
They are needed for the jaeger-debug-id header, but they are not used for the trace parent and tracestate headers. These two headers are constants.
src/jaegertracing/Tracer.h
Outdated
| const std::shared_ptr<logging::Logger>& logger, | ||
| const std::shared_ptr<metrics::Metrics>& metrics, | ||
| const propagation::HeadersConfig& headersConfig, | ||
| const TextMapPropagator* textPropagator, |
There was a problem hiding this comment.
my C++ is quite rusty, but why is it that the other composable objects above are captured via shared_ptr and propagators via raw pointer?
There was a problem hiding this comment.
Mine is rusty too, but I changed it to shared_ptr.
|
|
||
| /* | ||
| * Copyright (c) 2020 Uber Technologies, Inc. | ||
| * |
There was a problem hiding this comment.
| /* | |
| * Copyright (c) 2020 Uber Technologies, Inc. | |
| * | |
| /* | |
| * Copyright (c) 2020 The Jaeger Authors | |
| * |
| @@ -0,0 +1,28 @@ | |||
| /* | |||
| * Copyright (c) 2020 Uber Technologies, Inc. | |||
There was a problem hiding this comment.
| * Copyright (c) 2020 Uber Technologies, Inc. | |
| * Copyright (c) 2020 The Jaeger Authors |
| @@ -0,0 +1,17 @@ | |||
| /* | |||
| * Copyright (c) 2020 Uber Technologies, Inc. | |||
There was a problem hiding this comment.
| * Copyright (c) 2020 Uber Technologies, Inc. | |
| * Copyright (c) 2020 The Jaeger Authors |
| @@ -0,0 +1,158 @@ | |||
| /* | |||
| * Copyright (c) 2020 Uber Technologies, Inc. | |||
There was a problem hiding this comment.
| * Copyright (c) 2020 Uber Technologies, Inc. | |
| * Copyright (c) 2020 The Jaeger Authors |
|
Hi @tobiasstadler , Thank you for this work. I tried to use your PR with nginx-opentracing. here is changes.
Can you help me share how can I debug the issue (I am new for CPP world)? |
Hi, |
|
@tobiasstadler thank you. Now I see the headers. Waiting when it could be merged :) |
src/jaegertracing/TracerTest.cpp
Outdated
| std::ostringstream oss; | ||
| oss << "00"; | ||
| oss << '-'; | ||
| oss << std::setw(16) << std::setfill('0') << std::hex |
There was a problem hiding this comment.
@tobiasstadler Can you help me understand why there are 0 in the first half of the trace id? Is there limitations of Jaeger?
There was a problem hiding this comment.
Yes, the jaeger client only generates 64bit trace ids. See #254.
Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
|
✅ Build jaeger-client-cpp 170 completed (commit 66de646a9b by @tobiasstadler) |
|
I checked W3C doc. It has next:
UPDATE: I found that it is Golang library capitalize all incoming HTTP headers. |
|
@tobiasstadler thanks for your hard work! Is there anything stopping this from being merged? |
|
@seabaylea The PR needs to be reviewed by one of the maintainers |
|
@miry @yurishkuro would it be possible to get this reviewed? |
|
@tobiasstadler I am not part of the core contributors. But I am testing your changes with ingress-nginx in our clusters. |
|
@miry if you're actually using this, could you provide some feedback please, and if possible some testing results? We do not have active maintainers of this library anymore, and my C++ is very rusty. |
@yurishkuro Good point. We have in pipeline to run load tests and compare with original ingress-nginx.
I have exactly the same situation. |
|
I did limited testing on my local machine. real world testing is appreciated. |
| JAEGER_AGENT_HOST | The hostname for communicating with agent via UDP | ||
| JAEGER_AGENT_PORT | The port for communicating with agent via UDP | ||
| JAEGER_ENDPOINT | The traces endpoint, in case the client should connect directly to the Collector, like http://jaeger-collector:14268/api/traces | ||
| JAEGER_PROPAGATION | The propagation format used by the tracer. Supported values are jaeger and w3c |
There was a problem hiding this comment.
Maybe we can align the documentation across programming languages. Can you use instead:
Comma separated list of formats to use for propagating the trace context. Defaults to the standard Jaeger format. Valid values are jaeger, and w3c
There was a problem hiding this comment.
I would suggest not doing this in this PR, because supporting more than one format simultaneously is actually non-trivial, and not even clearly defined semantically, e.g.
- do we include one or both formats in the outgoing requests?
- what to do if incoming request has both formats? Especially if they are conflicting?
src/jaegertracing/Config.cpp
Outdated
| _propagationFormat = propagation::Format::W3C; | ||
| } | ||
| else { | ||
| _propagationFormat = propagation::Format::JAEGER; |
There was a problem hiding this comment.
I think we should validate that propagationFormat contains the expected value (jaeger). Otherwise, either throw an exception, log or do nothing.
src/jaegertracing/Config.h
Outdated
| baggageRestrictions, | ||
| serviceName, | ||
| std::vector<Tag>(), | ||
| propagationFormat == "w3c" ? propagation::Format::W3C |
There was a problem hiding this comment.
We need to validate that propagationFormat contains the expected format (jaeger).
There was a problem hiding this comment.
otherwise, we could send TOTO and the system will accept it.
There was a problem hiding this comment.
We should at least fall back to jaeger format if none was provided.
@yurishkuro What do you think?
There was a problem hiding this comment.
fallback on empty value is fine.
Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
|
❌ Build jaeger-client-cpp 177 failed (commit 8848375e1b by @tobiasstadler) |
Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
|
✅ Build jaeger-client-cpp 181 completed (commit 475ea9af40 by @tobiasstadler) |
src/jaegertracing/Config.h
Outdated
| propagation::Format propagationFormat; | ||
| if (strPropagationFormat == "w3c") { | ||
| propagationFormat = propagation::Format::W3C; | ||
| } | ||
| else if (strPropagationFormat == "jaeger") { | ||
| propagationFormat = propagation::Format::JAEGER; | ||
| } | ||
| else { | ||
| std::cerr << "ERROR: unknown propagation format '" | ||
| << strPropagationFormat | ||
| << "', falling back to jaeger propagation format"; | ||
| propagationFormat = propagation::Format::JAEGER; | ||
| } |
There was a problem hiding this comment.
seems like this could be simplified a bit
| propagation::Format propagationFormat; | |
| if (strPropagationFormat == "w3c") { | |
| propagationFormat = propagation::Format::W3C; | |
| } | |
| else if (strPropagationFormat == "jaeger") { | |
| propagationFormat = propagation::Format::JAEGER; | |
| } | |
| else { | |
| std::cerr << "ERROR: unknown propagation format '" | |
| << strPropagationFormat | |
| << "', falling back to jaeger propagation format"; | |
| propagationFormat = propagation::Format::JAEGER; | |
| } | |
| auto propagationFormat = propagation::Format::JAEGER; | |
| if (strPropagationFormat == "w3c") { | |
| propagationFormat = propagation::Format::W3C; | |
| } | |
| else if (strPropagationFormat != "jaeger") { | |
| std::cerr << "ERROR: unknown propagation format '" | |
| << strPropagationFormat | |
| << "', falling back to jaeger propagation format"; | |
| } |
There was a problem hiding this comment.
also, the same logic is repeated in Config::fromEnv(), can we combine them into a shared util function?
src/jaegertracing/TracerTest.cpp
Outdated
| oss << std::setw(16) << std::setfill('0') << std::hex | ||
| << spanContext.spanID(); | ||
| oss << '-'; | ||
| oss << (spanContext.isSampled() ? "01" : "00"); |
There was a problem hiding this comment.
I have a conceptual problem with the above code - it is essentially testing production code with a copy of the same production code. A preferred test for these is to instantiate SpanContext with known IDs and then compare its serialized form with a known string. It makes the test both simpler and more reliable.
| @@ -1,94 +1,102 @@ | |||
| /* | |||
There was a problem hiding this comment.
NB: this diff is due to fixing line endings from Win to Unix (+1)
Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
Signed-off-by: Tobias Stadler <ts.stadler@gmx.de>
|
✅ Build jaeger-client-cpp 182 completed (commit b4ff338d1a by @tobiasstadler) |
|
🎉 |
|
👍 |
|
Thank You @yurishkuro! |
|
This is awesome! Can we get a new version (like 0.6.1) released with the latest changes? |
|
released v0.7.0 |
Which problem is this PR solving?
The cpp client does not support injection/extracting the W3C trace parent header. I implemented support for it.
Fixes #160