-
Notifications
You must be signed in to change notification settings - Fork 126
Added Support for W3C traceparent/tracestate propagation #255
Added Support for W3C traceparent/tracestate propagation #255
Conversation
Signed-off-by: Tobias Stadler <[email protected]>
✅ Build jaeger-client-cpp 165 completed (commit 50d272a82a by @tobiasstadler) |
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 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: why is this uppercase "W3C"? Where would the value come from?
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.
Via the configuration file, e.g.
headers:
TraceContextHeaderFormat: w3c
src/jaegertracing/Constants.h.in
Outdated
@@ -31,6 +31,7 @@ static constexpr auto kSamplerTypeTagKey = "sampler.type"; | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will look into it
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.
done
…docs/1.21/client-features/, Signed-off-by: Tobias Stadler <[email protected]>
…ables Signed-off-by: Tobias Stadler <[email protected]>
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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](const std::string& rawKey, | ||
const std::string& value) { | ||
[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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 <[email protected]>
Signed-off-by: Tobias Stadler <[email protected]>
Signed-off-by: Tobias Stadler <[email protected]>
Signed-off-by: Tobias Stadler <[email protected]>
✅ 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the format of the config file documented somewhere?
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.
No, because I don't know where. Should I put it in examples/config.yml.
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 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.
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.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are headers() needed for W3C? If different headers are used it ceases to be W3C format.
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.
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
Tracer(const std::string& serviceName, | ||
const std::shared_ptr<samplers::Sampler>& sampler, | ||
const std::shared_ptr<reporters::Reporter>& reporter, | ||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mine is rusty too, but I changed it to shared_ptr.
|
||
/* | ||
* Copyright (c) 2020 Uber Technologies, Inc. | ||
* |
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.
/* | |
* 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind, I found PR #254
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.
Yes, the jaeger client only generates 64bit trace ids. See #254.
Signed-off-by: Tobias Stadler <[email protected]>
Signed-off-by: Tobias Stadler <[email protected]>
✅ 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. |
@@ -104,6 +104,7 @@ JAEGER_DISABLED _(not recommended)_ | Instructs the Configuration to return a no | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should validate that propagationFormat contains the expected value (jaeger). Otherwise, either throw an exception, log or do nothing.
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.
@yurishkuro What do you think?
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.
Done
src/jaegertracing/Config.h
Outdated
baggageRestrictions, | ||
serviceName, | ||
std::vector<Tag>(), | ||
propagationFormat == "w3c" ? propagation::Format::W3C |
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.
We need to validate that propagationFormat contains the expected format (jaeger).
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.
otherwise, we could send TOTO and the system will accept it.
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fallback on empty value is fine.
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.
Done
Signed-off-by: Tobias Stadler <[email protected]>
Signed-off-by: Tobias Stadler <[email protected]>
❌ Build jaeger-client-cpp 177 failed (commit 8848375e1b by @tobiasstadler) |
Signed-off-by: Tobias Stadler <[email protected]>
✅ 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also, the same logic is repeated in Config::fromEnv()
, can we combine them into a shared util function?
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.
done
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
done
@@ -1,94 +1,102 @@ | |||
/* |
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.
NB: this diff is due to fixing line endings from Win to Unix (+1)
Signed-off-by: Tobias Stadler <[email protected]>
Signed-off-by: Tobias Stadler <[email protected]>
✅ 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