From 1f3ed2a4c653c5ecacd221ec8ec60887c74a94bd Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Sun, 6 Dec 2020 13:15:21 +0100 Subject: [PATCH] Extracted Jager porpagation and W3C propgation in their own classes Signed-off-by: Tobias Stadler --- CMakeLists.txt | 3 + src/jaegertracing/Config.cpp | 12 +- src/jaegertracing/Config.h | 23 +- src/jaegertracing/ConfigTest.cpp | 17 +- src/jaegertracing/Constants.h.in | 2 +- src/jaegertracing/SpanContext.cpp | 66 +----- src/jaegertracing/SpanContext.h | 37 +--- src/jaegertracing/SpanContextTest.cpp | 69 +----- src/jaegertracing/TraceID.cpp | 38 +--- src/jaegertracing/TraceID.h | 36 +-- src/jaegertracing/TraceIDTest.cpp | 29 +-- src/jaegertracing/Tracer.cpp | 21 +- src/jaegertracing/Tracer.h | 26 ++- src/jaegertracing/TracerTest.cpp | 7 +- src/jaegertracing/propagation/HeadersConfig.h | 84 +------ .../propagation/JaegerPropagator.cpp | 17 ++ .../propagation/JaegerPropagator.h | 158 ++++++++++++++ src/jaegertracing/propagation/Propagator.h | 132 ++--------- .../propagation/W3CPropagator.cpp | 17 ++ src/jaegertracing/propagation/W3CPropagator.h | 206 ++++++++++++++++++ .../propagation/W3CPropagatorTest.cpp | 165 ++++++++++++++ src/jaegertracing/testutils/TracerUtil.cpp | 22 +- src/jaegertracing/testutils/TracerUtil.h | 4 +- 23 files changed, 701 insertions(+), 490 deletions(-) create mode 100644 src/jaegertracing/propagation/JaegerPropagator.cpp create mode 100644 src/jaegertracing/propagation/JaegerPropagator.h create mode 100644 src/jaegertracing/propagation/W3CPropagator.cpp create mode 100644 src/jaegertracing/propagation/W3CPropagator.h create mode 100644 src/jaegertracing/propagation/W3CPropagatorTest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cc07cff..59126138 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,8 @@ set(SRC src/jaegertracing/propagation/HeadersConfig.cpp src/jaegertracing/propagation/Injector.cpp src/jaegertracing/propagation/Propagator.cpp + src/jaegertracing/propagation/JaegerPropagator.cpp + src/jaegertracing/propagation/W3CPropagator.cpp src/jaegertracing/reporters/CompositeReporter.cpp src/jaegertracing/reporters/Config.cpp src/jaegertracing/reporters/InMemoryReporter.cpp @@ -332,6 +334,7 @@ if(BUILD_TESTING) src/jaegertracing/net/http/MethodTest.cpp src/jaegertracing/net/http/ResponseTest.cpp src/jaegertracing/propagation/PropagatorTest.cpp + src/jaegertracing/propagation/W3CPropagatorTest.cpp src/jaegertracing/reporters/ConfigTest.cpp src/jaegertracing/reporters/ReporterTest.cpp src/jaegertracing/samplers/SamplerTest.cpp diff --git a/src/jaegertracing/Config.cpp b/src/jaegertracing/Config.cpp index f3020df0..57a5f437 100644 --- a/src/jaegertracing/Config.cpp +++ b/src/jaegertracing/Config.cpp @@ -32,6 +32,17 @@ void Config::fromEnv() _disabled = disabled.second; } + const auto propagationFormat = + utils::EnvVariable::getStringVariable(kJAEGER_PROPAGATION_ENV_PROP); + if(!propagationFormat.empty()) { + if (propagationFormat == "w3c") { + _propagationFormat = propagation::Format::W3C; + } + else { + _propagationFormat = propagation::Format::JAEGER; + } + } + const auto serviceName = utils::EnvVariable::getStringVariable(kJAEGER_SERVICE_NAME_ENV_PROP); if (!serviceName.empty()) { @@ -62,7 +73,6 @@ void Config::fromEnv() } _reporter.fromEnv(); _sampler.fromEnv(); - _headers.fromEnv(); } } // namespace jaegertracing diff --git a/src/jaegertracing/Config.h b/src/jaegertracing/Config.h index 2c9f0a32..6e7a67ca 100644 --- a/src/jaegertracing/Config.h +++ b/src/jaegertracing/Config.h @@ -22,6 +22,7 @@ #include "jaegertracing/Tag.h" #include "jaegertracing/baggage/RestrictionsConfig.h" #include "jaegertracing/propagation/HeadersConfig.h" +#include "jaegertracing/propagation/Format.h" #include "jaegertracing/reporters/Config.h" #include "jaegertracing/samplers/Config.h" #include "jaegertracing/utils/YAML.h" @@ -34,6 +35,7 @@ class Config { static constexpr auto kJAEGER_SERVICE_NAME_ENV_PROP = "JAEGER_SERVICE_NAME"; static constexpr auto kJAEGER_TAGS_ENV_PROP = "JAEGER_TAGS"; static constexpr auto kJAEGER_JAEGER_DISABLED_ENV_PROP = "JAEGER_DISABLED"; + static constexpr auto kJAEGER_PROPAGATION_ENV_PROP = "JAEGER_PROPAGATION"; #ifdef JAEGERTRACING_WITH_YAML_CPP @@ -48,6 +50,8 @@ class Config { const auto disabled = utils::yaml::findOrDefault(configYAML, "disabled", false); + const auto propagationFormat = utils::yaml::findOrDefault( + configYAML, "propagation_format", "jaeger"); const auto samplerNode = configYAML["sampler"]; const auto sampler = samplers::Config::parse(samplerNode); const auto reporterNode = configYAML["reporter"]; @@ -57,8 +61,15 @@ class Config { const auto baggageRestrictionsNode = configYAML["baggage_restrictions"]; const auto baggageRestrictions = baggage::RestrictionsConfig::parse(baggageRestrictionsNode); - return Config( - disabled, sampler, reporter, headers, baggageRestrictions, serviceName); + return Config(disabled, + sampler, + reporter, + headers, + baggageRestrictions, + serviceName, + std::vector(), + propagationFormat == "w3c" ? propagation::Format::W3C + : propagation::Format::JAEGER); } #endif // JAEGERTRACING_WITH_YAML_CPP @@ -71,8 +82,11 @@ class Config { const baggage::RestrictionsConfig& baggageRestrictions = baggage::RestrictionsConfig(), const std::string& serviceName = "", - const std::vector& tags = std::vector()) + const std::vector& tags = std::vector(), + const propagation::Format propagationFormat = + propagation::Format::JAEGER) : _disabled(disabled) + , _propagationFormat(propagationFormat) , _serviceName(serviceName) , _tags(tags) , _sampler(sampler) @@ -84,6 +98,8 @@ class Config { bool disabled() const { return _disabled; } + propagation::Format propagationFormat() const { return _propagationFormat; } + const samplers::Config& sampler() const { return _sampler; } const reporters::Config& reporter() const { return _reporter; } @@ -103,6 +119,7 @@ class Config { private: bool _disabled; + propagation::Format _propagationFormat; std::string _serviceName; std::vector< Tag > _tags; samplers::Config _sampler; diff --git a/src/jaegertracing/ConfigTest.cpp b/src/jaegertracing/ConfigTest.cpp index a23915ca..ccd2ec69 100644 --- a/src/jaegertracing/ConfigTest.cpp +++ b/src/jaegertracing/ConfigTest.cpp @@ -94,18 +94,14 @@ TEST(Config, testZeroSamplingParam) } } -TEST(Config, testW3CTraceContextHeaderFormat) +TEST(Config, testPropagationFormat) { { constexpr auto kConfigYAML = R"cfg( -headers: - TraceContextHeaderFormat: w3c +propagation_format: w3c )cfg"; const auto config = Config::parse(YAML::Load(kConfigYAML)); - ASSERT_EQ(kW3CTraceContextHeaderName, - config.headers().traceContextHeaderName()); - ASSERT_EQ(propagation::Format::W3C, - config.headers().traceContextHeaderFormat()); + ASSERT_EQ(propagation::Format::W3C, config.propagationFormat()); } } @@ -197,12 +193,7 @@ TEST(Config, testFromEnv) testutils::EnvVariable::setEnv("JAEGER_PROPAGATION", "w3c"); config.fromEnv(); - ASSERT_EQ(kW3CTraceContextHeaderName, - config.headers().traceContextHeaderName()); - ASSERT_EQ(kW3CTraceStateHeaderName, - config.headers().traceStateHeaderName()); - ASSERT_EQ(propagation::Format::W3C, - config.headers().traceContextHeaderFormat()); + ASSERT_EQ(propagation::Format::W3C, config.propagationFormat()); testutils::EnvVariable::setEnv("JAEGER_AGENT_HOST", ""); testutils::EnvVariable::setEnv("JAEGER_AGENT_PORT", ""); diff --git a/src/jaegertracing/Constants.h.in b/src/jaegertracing/Constants.h.in index 97eb6dfc..a235cf59 100644 --- a/src/jaegertracing/Constants.h.in +++ b/src/jaegertracing/Constants.h.in @@ -32,7 +32,7 @@ static constexpr auto kSamplerParamTagKey = "sampler.param"; static constexpr auto kTraceContextHeaderName = "uber-trace-id"; static constexpr auto kTracerStateHeaderName = kTraceContextHeaderName; static constexpr auto kTraceBaggageHeaderPrefix = "uberctx-"; -static constexpr auto kW3CTraceContextHeaderName = "traceparent"; +static constexpr auto kW3CTraceParentHeaderName = "traceparent"; static constexpr auto kW3CTraceStateHeaderName = "tracestate"; static constexpr auto kSamplerTypeConst = "const"; static constexpr auto kSamplerTypeRemote = "remote"; diff --git a/src/jaegertracing/SpanContext.cpp b/src/jaegertracing/SpanContext.cpp index 67f74f00..effbf11a 100644 --- a/src/jaegertracing/SpanContext.cpp +++ b/src/jaegertracing/SpanContext.cpp @@ -20,7 +20,7 @@ namespace jaegertracing { -SpanContext SpanContext::parseJaegerFormat(std::istream& in) +SpanContext SpanContext::fromStream(std::istream& in) { SpanContext spanContext; spanContext._traceID = TraceID::fromStream(in); @@ -65,68 +65,4 @@ SpanContext SpanContext::parseJaegerFormat(std::istream& in) return spanContext; } -SpanContext SpanContext::parseW3CFormat(std::istream& in) -{ - char ch = '\0'; - if (!in.get(ch) || ch != '0') { - return SpanContext(); - } - - if (!in.get(ch) || ch != '0') { - return SpanContext(); - } - - if (!in.get(ch) || ch != '-') { - return SpanContext(); - } - - SpanContext spanContext; - spanContext._traceID = TraceID::fromStream(in, PropagationFormat::W3C); - if (!spanContext._traceID.isValid()) { - return SpanContext(); - } - - if (!in.get(ch) || ch != '-') { - return SpanContext(); - } - - constexpr auto kMaxUInt64Chars = static_cast(16); - auto buffer = utils::HexParsing::readSegment(in, kMaxUInt64Chars, '-'); - if (buffer.empty()) { - return SpanContext(); - } - spanContext._spanID = utils::HexParsing::decodeHex(buffer); - - if (!in.get(ch) || ch != '-') { - return SpanContext(); - } - - constexpr auto kMaxByteChars = static_cast(2); - buffer = utils::HexParsing::readSegment(in, kMaxByteChars, '-'); - if (buffer.empty() || buffer.size() != 2) { - return SpanContext(); - } - spanContext._flags = utils::HexParsing::decodeHex(buffer); - - in.clear(); - return spanContext; -} - -SpanContext SpanContext::fromStream(std::istream& in, PropagationFormat format) -{ - switch (format) { - case PropagationFormat::JAEGER: - return parseJaegerFormat(in); - case PropagationFormat::W3C: - return parseW3CFormat(in); - } - - return SpanContext(); -} - -SpanContext SpanContext::fromStream(std::istream& in) -{ - return fromStream(in, PropagationFormat::JAEGER); -} - } // namespace jaegertracing diff --git a/src/jaegertracing/SpanContext.h b/src/jaegertracing/SpanContext.h index 663c2cb1..117b36d8 100644 --- a/src/jaegertracing/SpanContext.h +++ b/src/jaegertracing/SpanContext.h @@ -27,19 +27,17 @@ #include #include "jaegertracing/Compilers.h" + #include "jaegertracing/TraceID.h" -#include "jaegertracing/propagation/Format.h" namespace jaegertracing { class SpanContext : public opentracing::SpanContext { public: using StrMap = std::unordered_map; - using PropagationFormat = propagation::Format; enum class Flag : unsigned char { kSampled = 1, kDebug = 2 }; - static SpanContext fromStream(std::istream& in, PropagationFormat format); static SpanContext fromStream(std::istream& in); SpanContext() @@ -146,13 +144,13 @@ class SpanContext : public opentracing::SpanContext { const std::string& debugID() const { return _debugID; } - const std::string& traceState() const { return _traceState; } - bool isSampled() const { return _flags & static_cast(Flag::kSampled); } + const std::string& traceState() const { return _traceState; } + bool isDebug() const { return _flags & static_cast(Flag::kDebug); @@ -165,32 +163,12 @@ class SpanContext : public opentracing::SpanContext { bool isValid() const { return _traceID.isValid() && _spanID != 0; } - template - void print(Stream& out, PropagationFormat format) const - { - switch (format) { - case PropagationFormat::JAEGER: - _traceID.print(out, PropagationFormat::JAEGER); - out << ':' << std::hex << _spanID << ':' << std::hex << _parentID - << ':' << std::hex << static_cast(_flags); - break; - case PropagationFormat::W3C: - out << "00"; - out << '-'; - _traceID.print(out, PropagationFormat::W3C); - out << '-'; - out << std::setw(16) << std::setfill('0') << std::hex << _spanID; - out << '-'; - out << std::setw(2) << std::setfill('0') << std::hex - << static_cast(_flags); - break; - } - } - template void print(Stream& out) const { - print(out, PropagationFormat::JAEGER); + _traceID.print(out); + out << ':' << std::hex << _spanID << ':' << std::hex << _parentID << ':' + << std::hex << static_cast(_flags); } void ForeachBaggageItem( @@ -229,9 +207,6 @@ class SpanContext : public opentracing::SpanContext { } private: - static SpanContext parseJaegerFormat(std::istream& in); - static SpanContext parseW3CFormat(std::istream& in); - TraceID _traceID; uint64_t _spanID; uint64_t _parentID; diff --git a/src/jaegertracing/SpanContextTest.cpp b/src/jaegertracing/SpanContextTest.cpp index f9d41e2f..6eef6b3c 100644 --- a/src/jaegertracing/SpanContextTest.cpp +++ b/src/jaegertracing/SpanContextTest.cpp @@ -24,8 +24,6 @@ namespace jaegertracing { namespace { -using PropagationFormat = propagation::Format; - struct FromStreamTestCase { std::string _input; bool _success; @@ -33,7 +31,7 @@ struct FromStreamTestCase { } // anonymous namespace -TEST(SpanContext, testFromStreamWithJaegerFormat) +TEST(SpanContext, testFromStream) { const FromStreamTestCase testCases[] = { { "", false }, @@ -59,7 +57,7 @@ TEST(SpanContext, testFromStreamWithJaegerFormat) { std::stringstream ss; ss << testCase._input; - spanContext = SpanContext::fromStream(ss, PropagationFormat::JAEGER); + spanContext = SpanContext::fromStream(ss); ASSERT_EQ(testCase._success, spanContext.isValid()) << "input=" << testCase._input; } @@ -75,67 +73,12 @@ TEST(SpanContext, testFromStreamWithJaegerFormat) } } -TEST(SpanContext, testFromStreamWithW3CFormat) -{ - const FromStreamTestCase testCases[] = { - { "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", true }, - { "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-00", true }, - { "00-11111111111111111111111111111111-2222222222222222-01", true }, - { "00-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-BBBBBBBBBBBBBBBB-01", true }, - { "", false }, - { "000af7651916cd43dd8448eb211c80319cb9c7c989f97918e101", false }, - { "000af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, - { "00-0af7651916cd43dd8448eb211c80319cb9c7c989f97918e1-01", false }, - { "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e101", false }, - { "000af7651916cd43dd8448eb211c80319cb9c7c989f97918e1-01", false }, - { "00-0af7651916cd43dd8448eb211c80319cb9c7c989f97918e101", false }, - { "01-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, - { "-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, - { "0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, - { "0-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, - { "000-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, - { "0k-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, - { "k0-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, - { "00-00000000000000000000000000000000-b9c7c989f97918e1-01", false }, - { "01-0af7651916cd43dd8448eb211c80319-b9c7c989f97918e1-01", false }, - { "01-0af7651916cd43dd8448eb211c80319cc-b9c7c989f97918e1-01", false }, - { "00-0af7651916cd43dd8448eb211c80319c-0000000000000000-01", false } - }; - - for (auto&& testCase : testCases) { - SpanContext spanContext; - { - std::stringstream ss; - ss << testCase._input; - spanContext = SpanContext::fromStream(ss, PropagationFormat::W3C); - ASSERT_EQ(testCase._success, spanContext.isValid()) - << "input=" << testCase._input; - } - } -} - -TEST(SpanContext, testJaegerFormatting) -{ - SpanContext spanContext(TraceID(255, 1), 2, 3, 1, SpanContext::StrMap()); - { - std::ostringstream oss; - spanContext.print(oss, PropagationFormat::JAEGER); - ASSERT_EQ("ff0000000000000001:2:3:1", oss.str()); - } - { - std::ostringstream oss; - oss << spanContext; - ASSERT_EQ("ff0000000000000001:2:3:1", oss.str()); - } -} - -TEST(SpanContext, testW3CFormatting) +TEST(SpanContext, testFormatting) { - SpanContext spanContext(TraceID(255, 1), 2, 3, 1, SpanContext::StrMap()); + SpanContext spanContext(TraceID(255, 255), 0, 0, 0, SpanContext::StrMap()); std::ostringstream oss; - spanContext.print(oss, PropagationFormat::W3C); - ASSERT_EQ("00-00000000000000ff0000000000000001-0000000000000002-01", - oss.str()); + oss << spanContext; + ASSERT_EQ("ff00000000000000ff:0:0:0", oss.str()); } TEST(SpanContext, testBaggage) diff --git a/src/jaegertracing/TraceID.cpp b/src/jaegertracing/TraceID.cpp index 107aaeb6..59a5ceb4 100644 --- a/src/jaegertracing/TraceID.cpp +++ b/src/jaegertracing/TraceID.cpp @@ -22,7 +22,7 @@ namespace jaegertracing { -TraceID TraceID::parseJaegerFormat(std::istream& in) +TraceID TraceID::fromStream(std::istream& in) { TraceID traceID; constexpr auto kMaxChars = static_cast(32); @@ -46,40 +46,4 @@ TraceID TraceID::parseJaegerFormat(std::istream& in) return traceID; } -TraceID TraceID::parseW3CFormat(std::istream& in) -{ - TraceID traceID; - constexpr auto kMaxChars = static_cast(32); - auto buffer = utils::HexParsing::readSegment(in, kMaxChars, '-'); - - if (buffer.empty() || buffer.size() != kMaxChars) { - return TraceID(); - } - - auto beginLowStr = std::end(buffer) - kMaxChars / 2; - const std::string highStr(std::begin(buffer), beginLowStr); - traceID._high = utils::HexParsing::decodeHex(highStr); - const std::string lowStr(beginLowStr, std::end(buffer)); - traceID._low = utils::HexParsing::decodeHex(lowStr); - - return traceID; -} - -TraceID TraceID::fromStream(std::istream& in, PropagationFormat format) -{ - switch (format) { - case PropagationFormat::JAEGER: - return parseJaegerFormat(in); - case PropagationFormat::W3C: - return parseW3CFormat(in); - } - - return TraceID(); -} - -TraceID TraceID::fromStream(std::istream& in) -{ - return fromStream(in, PropagationFormat::JAEGER); -} - } // namespace jaegertracing diff --git a/src/jaegertracing/TraceID.h b/src/jaegertracing/TraceID.h index e25f7bbf..867f0c29 100644 --- a/src/jaegertracing/TraceID.h +++ b/src/jaegertracing/TraceID.h @@ -21,15 +21,10 @@ #include #include -#include "jaegertracing/propagation/Format.h" - namespace jaegertracing { class TraceID { public: - using PropagationFormat = propagation::Format; - - static TraceID fromStream(std::istream& in, PropagationFormat format); static TraceID fromStream(std::istream& in); TraceID() @@ -45,30 +40,16 @@ class TraceID { bool isValid() const { return _high != 0 || _low != 0; } - template - void print(Stream& out, PropagationFormat format) const - { - switch (format) { - case PropagationFormat::JAEGER: - if (_high == 0) { - out << std::hex << _low; - } - else { - out << std::hex << _high << std::setw(16) << std::setfill('0') - << std::hex << _low; - } - break; - case PropagationFormat::W3C: - out << std::setw(16) << std::setfill('0') << std::hex << _high; - out << std::setw(16) << std::setfill('0') << std::hex << _low; - break; - } - } - template void print(Stream& out) const { - print(out, PropagationFormat::JAEGER); + if (_high == 0) { + out << std::hex << _low; + } + else { + out << std::hex << _high << std::setw(16) << std::setfill('0') + << std::hex << _low; + } } uint64_t high() const { return _high; } @@ -81,9 +62,6 @@ class TraceID { } private: - static TraceID parseJaegerFormat(std::istream& in); - static TraceID parseW3CFormat(std::istream& in); - uint64_t _high; uint64_t _low; }; diff --git a/src/jaegertracing/TraceIDTest.cpp b/src/jaegertracing/TraceIDTest.cpp index db690e72..ece21cfe 100644 --- a/src/jaegertracing/TraceIDTest.cpp +++ b/src/jaegertracing/TraceIDTest.cpp @@ -20,36 +20,11 @@ namespace jaegertracing { -using PropagationFormat = propagation::Format; - -TEST(TraceID, testPrintJaegerFormat) +TEST(TraceID, testPrint) { std::ostringstream oss; - TraceID(0, 10).print(oss, PropagationFormat::JAEGER); + oss << TraceID(0, 10); ASSERT_EQ("a", oss.str()); } -TEST(TraceID, testPrintW3CFormat) -{ - std::ostringstream oss; - TraceID(0, 10).print(oss, PropagationFormat::W3C); - ASSERT_EQ("0000000000000000000000000000000a", oss.str()); -} - -TEST(TraceID, testfromStreamJaegerFormat) -{ - std::stringstream ss; - ss << "a"; - auto traceID = TraceID::fromStream(ss, PropagationFormat::JAEGER); - ASSERT_EQ(TraceID(0, 10), traceID); -} - -TEST(TraceID, testfromStreamW3CFormat) -{ - std::stringstream ss; - ss << "0000000000000000000000000000000a"; - auto traceID = TraceID::fromStream(ss, PropagationFormat::JAEGER); - ASSERT_EQ(TraceID(0, 10), traceID); -} - } // namespace jaegertracing diff --git a/src/jaegertracing/Tracer.cpp b/src/jaegertracing/Tracer.cpp index b6037c00..ece94b51 100644 --- a/src/jaegertracing/Tracer.cpp +++ b/src/jaegertracing/Tracer.cpp @@ -18,6 +18,8 @@ #include "jaegertracing/Tracer.h" #include "jaegertracing/Reference.h" #include "jaegertracing/TraceID.h" +#include "jaegertracing/propagation/JaegerPropagator.h" +#include "jaegertracing/propagation/W3CPropagator.h" #include "jaegertracing/samplers/SamplingStatus.h" #include #include @@ -258,6 +260,22 @@ Tracer::make(const std::string& serviceName, } auto metrics = std::make_shared(statsFactory); + + TextMapPropagator* textPropagator; + HTTPHeaderPropagator* httpHeaderPropagator; + if (config.propagationFormat() == propagation::Format::W3C) { + textPropagator = + new propagation::W3CTextMapPropagator(config.headers(), metrics); + httpHeaderPropagator = + new propagation::W3CHTTPHeaderPropagator(config.headers(), metrics); + } + else { + textPropagator = + new propagation::JaegerTextMapPropagator(config.headers(), metrics); + httpHeaderPropagator = new propagation::JaegerHTTPHeaderPropagator( + config.headers(), metrics); + } + std::shared_ptr sampler( config.sampler().makeSampler(serviceName, *logger, *metrics)); std::shared_ptr reporter( @@ -267,7 +285,8 @@ Tracer::make(const std::string& serviceName, reporter, logger, metrics, - config.headers(), + textPropagator, + httpHeaderPropagator, config.tags(), options)); } diff --git a/src/jaegertracing/Tracer.h b/src/jaegertracing/Tracer.h index 8d204267..52709f3f 100644 --- a/src/jaegertracing/Tracer.h +++ b/src/jaegertracing/Tracer.h @@ -119,7 +119,7 @@ class Tracer : public opentracing::Tracer, return opentracing::make_expected_from_error( opentracing::invalid_span_context_error); } - _textPropagator.inject(*jaegerCtx, writer); + _textPropagator->inject(*jaegerCtx, writer); return opentracing::make_expected(); } @@ -132,7 +132,7 @@ class Tracer : public opentracing::Tracer, return opentracing::make_expected_from_error( opentracing::invalid_span_context_error); } - _httpHeaderPropagator.inject(*jaegerCtx, writer); + _httpHeaderPropagator->inject(*jaegerCtx, writer); return opentracing::make_expected(); } @@ -150,7 +150,7 @@ class Tracer : public opentracing::Tracer, opentracing::expected> Extract(const opentracing::TextMapReader& reader) const override { - const auto spanContext = _textPropagator.extract(reader); + const auto spanContext = _textPropagator->extract(reader); if (spanContext == SpanContext()) { return std::unique_ptr(); } @@ -161,7 +161,7 @@ class Tracer : public opentracing::Tracer, opentracing::expected> Extract(const opentracing::HTTPHeadersReader& reader) const override { - const auto spanContext = _httpHeaderPropagator.extract(reader); + const auto spanContext = _httpHeaderPropagator->extract(reader); if (spanContext == SpanContext()) { return std::unique_ptr(); } @@ -201,12 +201,20 @@ class Tracer : public opentracing::Tracer, } private: + using TextMapPropagator = + propagation::Propagator; + using HTTPHeaderPropagator = + propagation::Propagator; + Tracer(const std::string& serviceName, const std::shared_ptr& sampler, const std::shared_ptr& reporter, const std::shared_ptr& logger, const std::shared_ptr& metrics, - const propagation::HeadersConfig& headersConfig, + const TextMapPropagator* textPropagator, + const HTTPHeaderPropagator* httpHeaderPropagator, const std::vector& tags, int options) : _serviceName(serviceName) @@ -216,8 +224,8 @@ class Tracer : public opentracing::Tracer, , _metrics(metrics) , _logger(logger) , _randomNumberGenerator() - , _textPropagator(headersConfig, _metrics) - , _httpHeaderPropagator(headersConfig, _metrics) + , _textPropagator(textPropagator) + , _httpHeaderPropagator(httpHeaderPropagator) , _binaryPropagator(_metrics) , _tags() , _restrictionManager(new baggage::DefaultRestrictionManager(0)) @@ -294,8 +302,8 @@ class Tracer : public opentracing::Tracer, std::shared_ptr _logger; mutable std::mt19937_64 _randomNumberGenerator; mutable std::mutex _randomMutex; - propagation::TextMapPropagator _textPropagator; - propagation::HTTPHeaderPropagator _httpHeaderPropagator; + std::unique_ptr _textPropagator; + std::unique_ptr _httpHeaderPropagator; propagation::BinaryPropagator _binaryPropagator; std::vector _tags; std::unique_ptr _restrictionManager; diff --git a/src/jaegertracing/TracerTest.cpp b/src/jaegertracing/TracerTest.cpp index 64a0e923..a532c063 100644 --- a/src/jaegertracing/TracerTest.cpp +++ b/src/jaegertracing/TracerTest.cpp @@ -477,7 +477,8 @@ TEST(Tracer, testPropagationWithW3CHeaderAndFormat) oss << "00"; oss << '-'; oss << std::setw(16) << std::setfill('0') << std::hex - << spanContext.traceID().high() << std::hex + << spanContext.traceID().high(); + oss << std::setw(16) << std::setfill('0') << std::hex << spanContext.traceID().low(); oss << '-'; oss << std::setw(16) << std::setfill('0') << std::hex @@ -490,7 +491,7 @@ TEST(Tracer, testPropagationWithW3CHeaderAndFormat) ASSERT_TRUE( static_cast(tracer->Inject(span->context(), headerWriter))); ASSERT_EQ(1, headerMap.size()); - ASSERT_EQ(oss.str(), headerMap.at(kW3CTraceContextHeaderName)); + ASSERT_EQ(oss.str(), headerMap.at(kW3CTraceParentHeaderName)); ReaderMock headerReader(headerMap); auto result = tracer->Extract(headerReader); @@ -510,7 +511,7 @@ TEST(Tracer, testPropagationWithW3CTraceState) const auto tracer = std::static_pointer_cast(opentracing::Tracer::Global()); StrMap headerMap{ - { kW3CTraceContextHeaderName, + { kW3CTraceParentHeaderName, "00-00000000000000000000000000000001-0000000000000001-01" }, { kW3CTraceStateHeaderName, "foo=bar" } }; diff --git a/src/jaegertracing/propagation/HeadersConfig.h b/src/jaegertracing/propagation/HeadersConfig.h index 3d7a9fc5..4ae21355 100644 --- a/src/jaegertracing/propagation/HeadersConfig.h +++ b/src/jaegertracing/propagation/HeadersConfig.h @@ -18,8 +18,6 @@ #define JAEGERTRACING_PROPAGATION_HEADERSCONFIG_H #include "jaegertracing/Constants.h" -#include "jaegertracing/propagation/Format.h" -#include "jaegertracing/utils/EnvVariable.h" #include "jaegertracing/utils/YAML.h" #include @@ -28,9 +26,6 @@ namespace propagation { class HeadersConfig { public: - - static constexpr auto kJAEGER_PROPAGATION_ENV_PROP = "JAEGER_PROPAGATION"; - #ifdef JAEGERTRACING_WITH_YAML_CPP static HeadersConfig parse(const YAML::Node& configYAML) @@ -50,26 +45,17 @@ class HeadersConfig { const auto traceBaggageHeaderPrefix = utils::yaml::findOrDefault( configYAML, "traceBaggageHeaderPrefix", ""); - const auto traceStateHeaderName = - utils::yaml::findOrDefault( - configYAML, "TraceStateHeaderName", ""); - const auto traceContextHeaderFormat = - utils::yaml::findOrDefault( - configYAML, "TraceContextHeaderFormat", ""); - - return HeadersConfig( - jaegerDebugHeader, - jaegerBaggageHeader, - traceContextHeaderName, - traceBaggageHeaderPrefix, - traceStateHeaderName, - traceContextHeaderFormat == "w3c" ? Format::W3C : Format::JAEGER); + + return HeadersConfig(jaegerDebugHeader, + jaegerBaggageHeader, + traceContextHeaderName, + traceBaggageHeaderPrefix); } #endif // JAEGERTRACING_WITH_YAML_CPP HeadersConfig() - : HeadersConfig("", "", "", "", "", Format::JAEGER) + : HeadersConfig("", "", "", "") { } @@ -88,35 +74,6 @@ class HeadersConfig { , _traceBaggageHeaderPrefix(traceBaggageHeaderPrefix.empty() ? kTraceBaggageHeaderPrefix : traceBaggageHeaderPrefix) - , _traceContextHeaderFormat(Format::JAEGER) - { - } - - HeadersConfig(const std::string& jaegerDebugHeader, - const std::string& jaegerBaggageHeader, - const std::string& traceContextHeaderName, - const std::string& traceBaggageHeaderPrefix, - const std::string& traceStateHeaderName, - Format traceContextHeaderFormat) - : _jaegerDebugHeader(jaegerDebugHeader.empty() ? kJaegerDebugHeader - : jaegerDebugHeader) - , _jaegerBaggageHeader(jaegerBaggageHeader.empty() - ? kJaegerBaggageHeader - : jaegerBaggageHeader) - , _traceContextHeaderName(traceContextHeaderName.empty() - ? (traceContextHeaderFormat == Format::W3C - ? kW3CTraceContextHeaderName - : kTraceContextHeaderName) - : traceContextHeaderName) - , _traceBaggageHeaderPrefix(traceBaggageHeaderPrefix.empty() - ? kTraceBaggageHeaderPrefix - : traceBaggageHeaderPrefix) - , _traceStateHeaderName(traceStateHeaderName.empty() - ? (traceContextHeaderFormat == Format::W3C - ? kW3CTraceStateHeaderName - : "") - : traceStateHeaderName) - , _traceContextHeaderFormat(traceContextHeaderFormat) { } @@ -137,40 +94,11 @@ class HeadersConfig { return _traceContextHeaderName; } - const std::string& traceStateHeaderName() const - { - return _traceStateHeaderName; - } - - Format traceContextHeaderFormat() const - { - return _traceContextHeaderFormat; - } - - void fromEnv() - { - const auto propagationFormat = - utils::EnvVariable::getStringVariable(kJAEGER_PROPAGATION_ENV_PROP); - if (!propagationFormat.empty()) { - if (propagationFormat == "jaeger") { - _traceContextHeaderName = kTraceContextHeaderName; - _traceContextHeaderFormat = Format::JAEGER; - } - else if (propagationFormat == "w3c") { - _traceContextHeaderName = kW3CTraceContextHeaderName; - _traceStateHeaderName = kW3CTraceStateHeaderName; - _traceContextHeaderFormat = Format::W3C; - } - } - } - private: std::string _jaegerDebugHeader; std::string _jaegerBaggageHeader; std::string _traceContextHeaderName; std::string _traceBaggageHeaderPrefix; - std::string _traceStateHeaderName; - Format _traceContextHeaderFormat; }; } // namespace propagation diff --git a/src/jaegertracing/propagation/JaegerPropagator.cpp b/src/jaegertracing/propagation/JaegerPropagator.cpp new file mode 100644 index 00000000..fa13d67f --- /dev/null +++ b/src/jaegertracing/propagation/JaegerPropagator.cpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jaegertracing/propagation/JaegerPropagator.h" diff --git a/src/jaegertracing/propagation/JaegerPropagator.h b/src/jaegertracing/propagation/JaegerPropagator.h new file mode 100644 index 00000000..abe882ef --- /dev/null +++ b/src/jaegertracing/propagation/JaegerPropagator.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2020 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef JAEGERTRACING_PROPAGATION_JAEGERPROPAGATOR_H +#define JAEGERTRACING_PROPAGATION_JAEGERPROPAGATOR_H + +#include "jaegertracing/propagation/propagator.h" + +namespace jaegertracing { +namespace propagation { + +template +class JaegerPropagator : public Propagator { + public: + using Reader = ReaderType; + using Writer = WriterType; + using StrMap = SpanContext::StrMap; + + using Propagator::Propagator; + + protected: + SpanContext doExtract(const Reader& reader) const override + { + SpanContext ctx; + StrMap baggage; + const auto result = + reader.ForeachKey([this, &ctx, &baggage](const std::string& rawKey, + const std::string& value) { + const auto key = this->normalizeKey(rawKey); + if (key == this->_headerKeys.traceContextHeaderName()) { + const auto safeValue = this->decodeValue(value); + std::istringstream iss(safeValue); + if (!(iss >> ctx) || ctx == SpanContext()) { + return opentracing::make_expected_from_error( + opentracing::span_context_corrupted_error); + } + } + else if (key == this->_headerKeys.jaegerBaggageHeader()) { + for (auto&& pair : parseCommaSeparatedMap(value)) { + baggage[pair.first] = pair.second; + } + } + else { + const auto prefix = + this->_headerKeys.traceBaggageHeaderPrefix(); + if (key.size() >= prefix.size() && + key.substr(0, prefix.size()) == prefix) { + const auto safeKey = removeBaggageKeyPrefix(key); + const auto safeValue = this->decodeValue(value); + baggage[safeKey] = safeValue; + } + } + + return opentracing::make_expected(); + }); + + if (!result && + result.error() == opentracing::span_context_corrupted_error) { + this->_metrics->decodingErrors().inc(1); + return SpanContext(); + } + + return SpanContext( + ctx.traceID(), ctx.spanID(), ctx.parentID(), ctx.flags(), baggage); + } + + void doInject(const SpanContext& ctx, const Writer& writer) const override + { + std::ostringstream oss; + oss << ctx; + writer.Set(this->_headerKeys.traceContextHeaderName(), oss.str()); + ctx.forEachBaggageItem( + [this, &writer](const std::string& key, const std::string& value) { + const auto safeKey = addBaggageKeyPrefix(key); + const auto safeValue = this->encodeValue(value); + writer.Set(safeKey, safeValue); + return true; + }); + } + + private: + static StrMap parseCommaSeparatedMap(const std::string& escapedValue) + { + StrMap map; + std::istringstream iss(net::URI::queryUnescape(escapedValue)); + std::string piece; + while (std::getline(iss, piece, ',')) { + const auto eqPos = piece.find('='); + if (eqPos != std::string::npos) { + const auto key = piece.substr(0, eqPos); + const auto value = piece.substr(eqPos + 1); + map[key] = value; + } + } + return map; + } + + std::string addBaggageKeyPrefix(const std::string& key) const + { + return this->_headerKeys.traceBaggageHeaderPrefix() + key; + } + + std::string removeBaggageKeyPrefix(const std::string& key) const + { + return key.substr(this->_headerKeys.traceBaggageHeaderPrefix().size()); + } +}; + +using JaegerTextMapPropagator = + JaegerPropagator; + +class JaegerHTTPHeaderPropagator + : public JaegerPropagator { + public: + using JaegerPropagator::JaegerPropagator; + + protected: + std::string encodeValue(const std::string& str) const override + { + return net::URI::queryEscape(str); + } + + std::string decodeValue(const std::string& str) const override + { + return net::URI::queryUnescape(str); + } + + std::string normalizeKey(const std::string& rawKey) const override + { + std::string key; + key.reserve(rawKey.size()); + std::transform(std::begin(rawKey), + std::end(rawKey), + std::back_inserter(key), + [](char ch) { return std::tolower(ch); }); + return key; + } +}; + +} // namespace propagation +} // namespace jaegertracing + +#endif // JAEGERTRACING_PROPAGATION_JAEGERPROPAGATOR_H diff --git a/src/jaegertracing/propagation/Propagator.h b/src/jaegertracing/propagation/Propagator.h index 840e69d3..1d785c47 100644 --- a/src/jaegertracing/propagation/Propagator.h +++ b/src/jaegertracing/propagation/Propagator.h @@ -40,7 +40,6 @@ class Propagator : public Extractor, public Injector { public: using Reader = ReaderType; using Writer = WriterType; - using StrMap = SpanContext::StrMap; Propagator() : _headerKeys() @@ -59,54 +58,21 @@ class Propagator : public Extractor, public Injector { SpanContext extract(const Reader& reader) const override { - SpanContext ctx; - StrMap baggage; std::string debugID; - std::string traceState; - const auto result = reader.ForeachKey( - [this, &ctx, &debugID, &baggage, &traceState]( - const std::string& rawKey, const std::string& value) { + const auto result = + reader.ForeachKey([this, &debugID](const std::string& rawKey, + const std::string& value) { const auto key = normalizeKey(rawKey); - if (key == _headerKeys.traceContextHeaderName()) { - const auto safeValue = decodeValue(value); - std::istringstream iss(safeValue); - ctx = SpanContext::fromStream( - iss, _headerKeys.traceContextHeaderFormat()); - if (!iss || ctx == SpanContext()) { - return opentracing::make_expected_from_error( - opentracing::span_context_corrupted_error); - } - } - else if (key == _headerKeys.jaegerDebugHeader()) { + if (key == _headerKeys.jaegerDebugHeader()) { debugID = value; } - else if (key == _headerKeys.jaegerBaggageHeader()) { - for (auto&& pair : parseCommaSeparatedMap(value)) { - baggage[pair.first] = pair.second; - } - } - else if (key == _headerKeys.traceStateHeaderName()) { - traceState = value; - } - else { - const auto prefix = _headerKeys.traceBaggageHeaderPrefix(); - if (key.size() >= prefix.size() && - key.substr(0, prefix.size()) == prefix) { - const auto safeKey = removeBaggageKeyPrefix(key); - const auto safeValue = decodeValue(value); - baggage[safeKey] = safeValue; - } - } + return opentracing::make_expected(); }); - if (!result && - result.error() == opentracing::span_context_corrupted_error) { - _metrics->decodingErrors().inc(1); - return SpanContext(); - } - - if (!ctx.traceID().isValid() && debugID.empty() && baggage.empty()) { + SpanContext ctx = doExtract(reader); + if (!ctx.traceID().isValid() && ctx.baggage().empty() && + debugID.empty()) { return SpanContext(); } @@ -119,30 +85,21 @@ class Propagator : public Extractor, public Injector { ctx.spanID(), ctx.parentID(), flags, - baggage, + ctx.baggage(), debugID, - traceState); + ctx.traceState()); } void inject(const SpanContext& ctx, const Writer& writer) const override { - std::ostringstream oss; - ctx.print(oss, _headerKeys.traceContextHeaderFormat()); - writer.Set(_headerKeys.traceContextHeaderName(), oss.str()); - ctx.forEachBaggageItem( - [this, &writer](const std::string& key, const std::string& value) { - const auto safeKey = addBaggageKeyPrefix(key); - const auto safeValue = encodeValue(value); - writer.Set(safeKey, safeValue); - return true; - }); - if (!_headerKeys.traceStateHeaderName().empty() && - !ctx.traceState().empty()) { - writer.Set(_headerKeys.traceStateHeaderName(), ctx.traceState()); - } + doInject(ctx, writer); } protected: + virtual SpanContext doExtract(const Reader& reader) const = 0; + + virtual void doInject(const SpanContext& ctx, const Writer& writer) const = 0; + virtual std::string encodeValue(const std::string& str) const { return str; @@ -158,69 +115,10 @@ class Propagator : public Extractor, public Injector { return rawKey; } - private: - static StrMap parseCommaSeparatedMap(const std::string& escapedValue) - { - StrMap map; - std::istringstream iss(net::URI::queryUnescape(escapedValue)); - std::string piece; - while (std::getline(iss, piece, ',')) { - const auto eqPos = piece.find('='); - if (eqPos != std::string::npos) { - const auto key = piece.substr(0, eqPos); - const auto value = piece.substr(eqPos + 1); - map[key] = value; - } - } - return map; - } - - std::string addBaggageKeyPrefix(const std::string& key) const - { - return _headerKeys.traceBaggageHeaderPrefix() + key; - } - - std::string removeBaggageKeyPrefix(const std::string& key) const - { - return key.substr(_headerKeys.traceBaggageHeaderPrefix().size()); - } - HeadersConfig _headerKeys; std::shared_ptr _metrics; }; -using TextMapPropagator = Propagator; - -class HTTPHeaderPropagator - : public Propagator { - public: - using Propagator::Propagator; - - protected: - std::string encodeValue(const std::string& str) const override - { - return net::URI::queryEscape(str); - } - - std::string decodeValue(const std::string& str) const override - { - return net::URI::queryUnescape(str); - } - - std::string normalizeKey(const std::string& rawKey) const override - { - std::string key; - key.reserve(rawKey.size()); - std::transform(std::begin(rawKey), - std::end(rawKey), - std::back_inserter(key), - [](char ch) { return std::tolower(ch); }); - return key; - } -}; - class BinaryPropagator : public Extractor, public Injector { public: diff --git a/src/jaegertracing/propagation/W3CPropagator.cpp b/src/jaegertracing/propagation/W3CPropagator.cpp new file mode 100644 index 00000000..2562e9cd --- /dev/null +++ b/src/jaegertracing/propagation/W3CPropagator.cpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jaegertracing/propagation/W3CPropagator.h" diff --git a/src/jaegertracing/propagation/W3CPropagator.h b/src/jaegertracing/propagation/W3CPropagator.h new file mode 100644 index 00000000..81e56327 --- /dev/null +++ b/src/jaegertracing/propagation/W3CPropagator.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2020 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef JAEGERTRACING_PROPAGATION_W3CPROPAGATOR_H +#define JAEGERTRACING_PROPAGATION_W3CPROPAGATOR_H + +#include "jaegertracing/propagation/propagator.h" +#include "jaegertracing/utils/HexParsing.h" + +namespace jaegertracing { +namespace propagation { + +template +class W3CPropagator : public Propagator { + public: + using Reader = ReaderType; + using Writer = WriterType; + using StrMap = SpanContext::StrMap; + + using Propagator::Propagator; + + protected: + SpanContext doExtract(const Reader& reader) const override + { + SpanContext ctx; + std::string traceState; + const auto result = reader.ForeachKey( + [this, &ctx, &traceState](const std::string& rawKey, + const std::string& value) { + const auto key = this->normalizeKey(rawKey); + if (key == kW3CTraceParentHeaderName) { + const auto safeValue = this->decodeValue(value); + std::istringstream iss(safeValue); + ctx = readTraceParent(iss); + if (!iss || ctx == SpanContext()) { + return opentracing::make_expected_from_error( + opentracing::span_context_corrupted_error); + } + } + else if (key == kW3CTraceStateHeaderName) { + traceState = this->decodeValue(value); + } + + return opentracing::make_expected(); + }); + + if (!result && + result.error() == opentracing::span_context_corrupted_error) { + this->_metrics->decodingErrors().inc(1); + return SpanContext(); + } + + return SpanContext(ctx.traceID(), + ctx.spanID(), + ctx.parentID(), + ctx.flags(), + StrMap(), + "", + traceState); + } + + void doInject(const SpanContext& ctx, const Writer& writer) const override + { + std::ostringstream oss; + writeTraceParent(oss, ctx); + writer.Set(kW3CTraceParentHeaderName, oss.str()); + if (!ctx.traceState().empty()) { + writer.Set(kW3CTraceStateHeaderName, ctx.traceState()); + } + } + + private: + SpanContext readTraceParent(std::istream& in) const + { + char ch = '\0'; + if (!in.get(ch) || ch != '0') { + return SpanContext(); + } + + if (!in.get(ch) || ch != '0') { + return SpanContext(); + } + + if (!in.get(ch) || ch != '-') { + return SpanContext(); + } + + auto traceID = readTraceID(in); + if (!traceID.isValid()) { + return SpanContext(); + } + + if (!in.get(ch) || ch != '-') { + return SpanContext(); + } + + constexpr auto kMaxUInt64Chars = static_cast(16); + auto buffer = utils::HexParsing::readSegment(in, kMaxUInt64Chars, '-'); + if (buffer.empty()) { + return SpanContext(); + } + auto spanID = utils::HexParsing::decodeHex(buffer); + + if (!in.get(ch) || ch != '-') { + return SpanContext(); + } + + constexpr auto kMaxByteChars = static_cast(2); + buffer = utils::HexParsing::readSegment(in, kMaxByteChars, '-'); + if (buffer.empty() || buffer.size() != 2) { + return SpanContext(); + } + auto flags = utils::HexParsing::decodeHex(buffer); + + in.clear(); + + return SpanContext(traceID, spanID, 0, flags, StrMap()); + } + + TraceID readTraceID(std::istream& in) const + { + TraceID traceID; + constexpr auto kMaxChars = static_cast(32); + auto buffer = utils::HexParsing::readSegment(in, kMaxChars, '-'); + + if (buffer.empty() || buffer.size() != kMaxChars) { + return TraceID(); + } + + auto beginLowStr = std::end(buffer) - kMaxChars / 2; + const std::string highStr(std::begin(buffer), beginLowStr); + auto high = utils::HexParsing::decodeHex(highStr); + const std::string lowStr(beginLowStr, std::end(buffer)); + auto low = utils::HexParsing::decodeHex(lowStr); + + return TraceID(high, low); + } + + void writeTraceParent(std::ostream& out, const SpanContext& ctx) const + { + out << "00"; + out << '-'; + writeTraceID(out, ctx.traceID()); + out << '-'; + out << std::setw(16) << std::setfill('0') << std::hex << ctx.spanID(); + out << '-'; + out << std::setw(2) << std::setfill('0') << std::hex + << static_cast(ctx.flags()); + } + + void writeTraceID(std::ostream& out, const TraceID& traceID) const + { + out << std::setw(16) << std::setfill('0') << std::hex << traceID.high(); + out << std::setw(16) << std::setfill('0') << std::hex << traceID.low(); + } +}; + +using W3CTextMapPropagator = W3CPropagator; + +class W3CHTTPHeaderPropagator + : public W3CPropagator { + public: + using W3CPropagator::W3CPropagator; + + protected: + std::string encodeValue(const std::string& str) const override + { + return net::URI::queryEscape(str); + } + + std::string decodeValue(const std::string& str) const override + { + return net::URI::queryUnescape(str); + } + + std::string normalizeKey(const std::string& rawKey) const override + { + std::string key; + key.reserve(rawKey.size()); + std::transform(std::begin(rawKey), + std::end(rawKey), + std::back_inserter(key), + [](char ch) { return std::tolower(ch); }); + return key; + } +}; + +} // namespace propagation +} // namespace jaegertracing + +#endif // JAEGERTRACING_PROPAGATION_W3CPROPAGATOR_H diff --git a/src/jaegertracing/propagation/W3CPropagatorTest.cpp b/src/jaegertracing/propagation/W3CPropagatorTest.cpp new file mode 100644 index 00000000..9708966d --- /dev/null +++ b/src/jaegertracing/propagation/W3CPropagatorTest.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2020 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jaegertracing/propagation/W3CPropagator.h" +#include + +namespace jaegertracing { +namespace propagation { + +using StrMap = std::unordered_map; + +template +struct WriterMock : public BaseWriter { + explicit WriterMock(StrMap& keyValuePairs) + : _keyValuePairs(keyValuePairs) + { + } + + opentracing::expected + Set(opentracing::string_view key, + opentracing::string_view value) const override + { + _keyValuePairs[key] = value; + return opentracing::make_expected(); + } + + StrMap& _keyValuePairs; +}; + +template +struct ReaderMock : public BaseReader { + using Function = + std::function; + + explicit ReaderMock(const StrMap& keyValuePairs) + : _keyValuePairs(keyValuePairs) + { + } + + opentracing::expected ForeachKey( + std::function(opentracing::string_view, + opentracing::string_view)> f) + const override + { + for (auto&& pair : _keyValuePairs) { + const auto result = f(pair.first, pair.second); + if (!result) { + return result; + } + } + return opentracing::make_expected(); + } + + const StrMap& _keyValuePairs; +}; + +struct ExtractTestCase { + std::string _input; + bool _success; +}; + +TEST(W3CPropagator, testExtract) +{ + const ExtractTestCase testCases[] = { + { "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", true }, + { "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-00", true }, + { "00-11111111111111111111111111111111-2222222222222222-01", true }, + { "00-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-BBBBBBBBBBBBBBBB-01", true }, + { "", false }, + { "000af7651916cd43dd8448eb211c80319cb9c7c989f97918e101", false }, + { "000af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, + { "00-0af7651916cd43dd8448eb211c80319cb9c7c989f97918e1-01", false }, + { "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e101", false }, + { "000af7651916cd43dd8448eb211c80319cb9c7c989f97918e1-01", false }, + { "00-0af7651916cd43dd8448eb211c80319cb9c7c989f97918e101", false }, + { "01-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, + { "-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, + { "0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, + { "0-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, + { "000-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, + { "0k-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, + { "k0-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01", false }, + { "00-00000000000000000000000000000000-b9c7c989f97918e1-01", false }, + { "01-0af7651916cd43dd8448eb211c80319-b9c7c989f97918e1-01", false }, + { "01-0af7651916cd43dd8448eb211c80319cc-b9c7c989f97918e1-01", false }, + { "00-0af7651916cd43dd8448eb211c80319c-0000000000000000-01", false } + }; + + W3CTextMapPropagator textMapPropagator; + W3CHTTPHeaderPropagator httpHeaderPropagator; + for (auto&& testCase : testCases) { + SpanContext spanContext; + { + StrMap map; + map.emplace(kW3CTraceParentHeaderName, testCase._input); + + spanContext = textMapPropagator.extract( + ReaderMock(map)); + ASSERT_EQ(testCase._success, spanContext.isValid()) + << "input=" << testCase._input; + + spanContext = httpHeaderPropagator.extract( + ReaderMock(map)); + ASSERT_EQ(testCase._success, spanContext.isValid()) + << "input=" << testCase._input; + } + } + + StrMap map; + map.emplace(kW3CTraceParentHeaderName, + "00-00000000000000ff0000000000000001-0000000000000002-01"); + map.emplace(kW3CTraceStateHeaderName, "foo=bar"); + + SpanContext spanContext = + textMapPropagator.extract(ReaderMock(map)); + ASSERT_EQ(true, spanContext.isValid()); + ASSERT_EQ("foo=bar", spanContext.traceState()); + + spanContext = httpHeaderPropagator.extract( + ReaderMock(map)); + ASSERT_EQ(true, spanContext.isValid()); + ASSERT_EQ("foo=bar", spanContext.traceState()); +} + +TEST(W3CPropagator, testInject) +{ + SpanContext spanContext( + TraceID(255, 1), 2, 3, 1, SpanContext::StrMap(), "", "foo=bar"); + + StrMap textMap; + WriterMock textMapWriter(textMap); + + W3CTextMapPropagator textMapPropagator; + textMapPropagator.inject(spanContext, textMapWriter); + + ASSERT_EQ("00-00000000000000ff0000000000000001-0000000000000002-01", + textMap.at(kW3CTraceParentHeaderName)); + ASSERT_EQ("foo=bar", textMap.at(kW3CTraceStateHeaderName)); + + StrMap httpHeaderMap; + WriterMock httpHeaderWriter(httpHeaderMap); + + W3CHTTPHeaderPropagator httpHeaderPropagator; + httpHeaderPropagator.inject(spanContext, httpHeaderWriter); + + ASSERT_EQ("00-00000000000000ff0000000000000001-0000000000000002-01", + httpHeaderMap.at(kW3CTraceParentHeaderName)); + ASSERT_EQ("foo=bar", textMap.at(kW3CTraceStateHeaderName)); +} + +} // namespace propagation +} // namespace jaegertracing diff --git a/src/jaegertracing/testutils/TracerUtil.cpp b/src/jaegertracing/testutils/TracerUtil.cpp index 370dfc41..8e649b4a 100644 --- a/src/jaegertracing/testutils/TracerUtil.cpp +++ b/src/jaegertracing/testutils/TracerUtil.cpp @@ -31,7 +31,8 @@ namespace jaegertracing { namespace testutils { namespace TracerUtil { -std::shared_ptr installGlobalTracer(PropagationFormat format) +std::shared_ptr +installGlobalTracer(propagation::Format propagationFormat) { std::unique_ptr handle(new ResourceHandle()); handle->_mockAgent->start(); @@ -49,8 +50,11 @@ std::shared_ptr installGlobalTracer(PropagationFormat format) reporters::Config::Clock::duration(), false, handle->_mockAgent->spanServerAddress().authority()), - propagation::HeadersConfig("", "", "", "", "", format), - baggage::RestrictionsConfig()); + propagation::HeadersConfig("", "", "", ""), + baggage::RestrictionsConfig(), + "", + std::vector(), + propagationFormat); auto tracer = Tracer::make("test-service", config, logging::nullLogger()); opentracing::Tracer::InitGlobal(tracer); @@ -59,7 +63,7 @@ std::shared_ptr installGlobalTracer(PropagationFormat format) std::shared_ptr installGlobalTracer() { - return installGlobalTracer(PropagationFormat::JAEGER); + return installGlobalTracer(propagation::Format::JAEGER); } std::shared_ptr buildTracer(const std::string& endpoint) @@ -68,13 +72,13 @@ std::shared_ptr buildTracer(const std::string& endpoint) Config config( false, samplers::Config("const", - 1, - samplingServerURLStream.str(), - 0, - samplers::Config::Clock::duration()), + 1, + samplingServerURLStream.str(), + 0, + samplers::Config::Clock::duration()), reporters::Config(0, std::chrono::milliseconds(100), - false, "", endpoint), + false, "", endpoint), propagation::HeadersConfig(), baggage::RestrictionsConfig()); diff --git a/src/jaegertracing/testutils/TracerUtil.h b/src/jaegertracing/testutils/TracerUtil.h index 3aa635e2..ab94ed78 100644 --- a/src/jaegertracing/testutils/TracerUtil.h +++ b/src/jaegertracing/testutils/TracerUtil.h @@ -27,8 +27,6 @@ namespace jaegertracing { namespace testutils { namespace TracerUtil { -using PropagationFormat = propagation::Format; - struct ResourceHandle { ResourceHandle() : _mockAgent(testutils::MockAgent::make()) @@ -43,7 +41,7 @@ struct ResourceHandle { std::shared_ptr _mockAgent; }; -std::shared_ptr installGlobalTracer(PropagationFormat format); +std::shared_ptr installGlobalTracer(propagation::Format format); std::shared_ptr installGlobalTracer(); std::shared_ptr buildTracer(const std::string& endpoint);