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/README.md b/README.md index 36881bb9..6cfb5635 100644 --- a/README.md +++ b/README.md @@ -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 JAEGER_REPORTER_LOG_SPANS | Whether the reporter should also log the spans JAEGER_REPORTER_MAX_QUEUE_SIZE | The reporter's maximum queue size JAEGER_REPORTER_FLUSH_INTERVAL | The reporter's flush interval (ms) diff --git a/src/jaegertracing/Config.cpp b/src/jaegertracing/Config.cpp index 9dc9e68f..f82541ed 100644 --- a/src/jaegertracing/Config.cpp +++ b/src/jaegertracing/Config.cpp @@ -37,6 +37,23 @@ void Config::fromEnv() if (traceId128Bit.first) { _traceId128Bit = traceId128Bit.second; } + + const auto propagationFormat = + utils::EnvVariable::getStringVariable(kJAEGER_PROPAGATION_ENV_PROP); + if (!propagationFormat.empty()) { + if (propagationFormat == "w3c") { + _propagationFormat = propagation::Format::W3C; + } + else if (propagationFormat == "jaeger") { + _propagationFormat = propagation::Format::JAEGER; + } + else { + std::cerr << "ERROR: unknown propagation format '" + << propagationFormat + << "', falling back to jaeger propagation format"; + _propagationFormat = propagation::Format::JAEGER; + } + } const auto serviceName = utils::EnvVariable::getStringVariable(kJAEGER_SERVICE_NAME_ENV_PROP); diff --git a/src/jaegertracing/Config.h b/src/jaegertracing/Config.h index 186246a4..012307b1 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" @@ -35,6 +36,7 @@ class Config { static constexpr auto kJAEGER_TAGS_ENV_PROP = "JAEGER_TAGS"; static constexpr auto kJAEGER_JAEGER_DISABLED_ENV_PROP = "JAEGER_DISABLED"; static constexpr auto kJAEGER_JAEGER_TRACEID_128BIT_ENV_PROP = "JAEGER_TRACEID_128BIT"; + static constexpr auto kJAEGER_PROPAGATION_ENV_PROP = "JAEGER_PROPAGATION"; #ifdef JAEGERTRACING_WITH_YAML_CPP @@ -49,8 +51,26 @@ class Config { const auto disabled = utils::yaml::findOrDefault(configYAML, "disabled", false); + const auto traceId128Bit = utils::yaml::findOrDefault(configYAML, "traceid_128bit", false); + + const auto strPropagationFormat = utils::yaml::findOrDefault( + configYAML, "propagation_format", "jaeger"); + 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; + } + const auto samplerNode = configYAML["sampler"]; const auto sampler = samplers::Config::parse(samplerNode); const auto reporterNode = configYAML["reporter"]; @@ -60,8 +80,15 @@ class Config { const auto baggageRestrictionsNode = configYAML["baggage_restrictions"]; const auto baggageRestrictions = baggage::RestrictionsConfig::parse(baggageRestrictionsNode); - return Config( - disabled, traceId128Bit, sampler, reporter, headers, baggageRestrictions, serviceName); + return Config(disabled, + traceId128Bit, + sampler, + reporter, + headers, + baggageRestrictions, + serviceName, + std::vector(), + propagationFormat); } #endif // JAEGERTRACING_WITH_YAML_CPP @@ -75,9 +102,12 @@ 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) , _traceId128Bit(traceId128Bit) + , _propagationFormat(propagationFormat) , _serviceName(serviceName) , _tags(tags) , _sampler(sampler) @@ -91,6 +121,8 @@ class Config { bool traceId128Bit() const { return _traceId128Bit; } + propagation::Format propagationFormat() const { return _propagationFormat; } + const samplers::Config& sampler() const { return _sampler; } const reporters::Config& reporter() const { return _reporter; } @@ -111,6 +143,7 @@ class Config { private: bool _disabled; bool _traceId128Bit; + 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 3e3562d5..15e91d22 100644 --- a/src/jaegertracing/ConfigTest.cpp +++ b/src/jaegertracing/ConfigTest.cpp @@ -96,6 +96,17 @@ TEST(Config, testZeroSamplingParam) } } +TEST(Config, testPropagationFormat) +{ + { + constexpr auto kConfigYAML = R"cfg( +propagation_format: w3c +)cfg"; + const auto config = Config::parse(YAML::Load(kConfigYAML)); + ASSERT_EQ(propagation::Format::W3C, config.propagationFormat()); + } +} + #endif // JAEGERTRACING_WITH_YAML_CPP TEST(Config, testFromEnv) @@ -186,6 +197,11 @@ TEST(Config, testFromEnv) ASSERT_EQ(std::string("host33:445"), config.reporter().localAgentHostPort()); + testutils::EnvVariable::setEnv("JAEGER_PROPAGATION", "w3c"); + + config.fromEnv(); + ASSERT_EQ(propagation::Format::W3C, config.propagationFormat()); + testutils::EnvVariable::setEnv("JAEGER_AGENT_HOST", ""); testutils::EnvVariable::setEnv("JAEGER_AGENT_PORT", ""); testutils::EnvVariable::setEnv("JAEGER_ENDPOINT", ""); @@ -198,6 +214,7 @@ TEST(Config, testFromEnv) testutils::EnvVariable::setEnv("JAEGER_TAGS", ""); testutils::EnvVariable::setEnv("JAEGER_DISABLED", ""); testutils::EnvVariable::setEnv("JAEGER_TRACE_ID_128BIT", ""); + testutils::EnvVariable::setEnv("JAEGER_PROPAGATION", ""); } } // namespace jaegertracing diff --git a/src/jaegertracing/Constants.h.in b/src/jaegertracing/Constants.h.in index c5b90f55..a235cf59 100644 --- a/src/jaegertracing/Constants.h.in +++ b/src/jaegertracing/Constants.h.in @@ -32,6 +32,8 @@ 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 kW3CTraceParentHeaderName = "traceparent"; +static constexpr auto kW3CTraceStateHeaderName = "tracestate"; static constexpr auto kSamplerTypeConst = "const"; static constexpr auto kSamplerTypeRemote = "remote"; static constexpr auto kSamplerTypeProbabilistic = "probabilistic"; diff --git a/src/jaegertracing/SpanContext.h b/src/jaegertracing/SpanContext.h index 4055e4e5..84a197e0 100644 --- a/src/jaegertracing/SpanContext.h +++ b/src/jaegertracing/SpanContext.h @@ -54,13 +54,15 @@ class SpanContext : public opentracing::SpanContext { uint64_t parentID, unsigned char flags, const StrMap& baggage, - const std::string& debugID = "") + const std::string& debugID = "", + const std::string& traceState = "") : _traceID(traceID) , _spanID(spanID) , _parentID(parentID) , _flags(flags) , _baggage(baggage) , _debugID(debugID) + , _traceState(traceState) , _mutex() { } @@ -72,6 +74,7 @@ class SpanContext : public opentracing::SpanContext { , _flags(ctx._flags) , _baggage(ctx._baggage) , _debugID(ctx._debugID) + , _traceState(ctx._traceState) { } @@ -90,6 +93,7 @@ class SpanContext : public opentracing::SpanContext { swap(_flags, ctx._flags); swap(_baggage, ctx._baggage); swap(_debugID, ctx._debugID); + swap(_traceState, ctx._traceState); } friend void swap(SpanContext& lhs, SpanContext& rhs) { lhs.swap(rhs); } @@ -105,8 +109,13 @@ class SpanContext : public opentracing::SpanContext { SpanContext withBaggage(const StrMap& baggage) const { std::lock_guard lock(_mutex); - return SpanContext( - _traceID, _spanID, _parentID, _flags, baggage, _debugID); + return SpanContext(_traceID, + _spanID, + _parentID, + _flags, + baggage, + _debugID, + _traceState); } template @@ -140,6 +149,8 @@ class SpanContext : public opentracing::SpanContext { return _flags & static_cast(Flag::kSampled); } + const std::string& traceState() const { return _traceState; } + bool isDebug() const { return _flags & static_cast(Flag::kDebug); @@ -187,7 +198,8 @@ class SpanContext : public opentracing::SpanContext { } return lhs._traceID == rhs._traceID && lhs._spanID == rhs._spanID && lhs._parentID == rhs._parentID && lhs._flags == rhs._flags && - lhs._debugID == rhs._debugID; + lhs._debugID == rhs._debugID && + lhs._traceState == rhs._traceState; } friend bool operator!=(const SpanContext& lhs, const SpanContext& rhs) @@ -202,6 +214,7 @@ class SpanContext : public opentracing::SpanContext { unsigned char _flags; StrMap _baggage; std::string _debugID; + std::string _traceState; mutable std::mutex _mutex; // Protects _baggage. }; diff --git a/src/jaegertracing/Tracer.cpp b/src/jaegertracing/Tracer.cpp index b6037c00..72025490 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,25 @@ Tracer::make(const std::string& serviceName, } auto metrics = std::make_shared(statsFactory); + + std::shared_ptr textPropagator; + std::shared_ptr httpHeaderPropagator; + if (config.propagationFormat() == propagation::Format::W3C) { + textPropagator = std::shared_ptr( + new propagation::W3CTextMapPropagator(config.headers(), metrics)); + httpHeaderPropagator = std::shared_ptr( + new propagation::W3CHTTPHeaderPropagator(config.headers(), + metrics)); + } + else { + textPropagator = std::shared_ptr( + new propagation::JaegerTextMapPropagator(config.headers(), + metrics)); + httpHeaderPropagator = std::shared_ptr( + new propagation::JaegerHTTPHeaderPropagator(config.headers(), + metrics)); + } + std::shared_ptr sampler( config.sampler().makeSampler(serviceName, *logger, *metrics)); std::shared_ptr reporter( @@ -267,7 +288,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 65c611a0..da33b8d2 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 std::shared_ptr &textPropagator, + const std::shared_ptr &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::shared_ptr _textPropagator; + std::shared_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 b5263ef1..3359e5b2 100644 --- a/src/jaegertracing/TracerTest.cpp +++ b/src/jaegertracing/TracerTest.cpp @@ -464,6 +464,73 @@ TEST(Tracer, testPropagation) tracer->Close(); } +TEST(Tracer, testPropagationWithW3CHeaderAndFormat) +{ + const auto handle = + testutils::TracerUtil::installGlobalTracerW3CPropagation(); + const auto tracer = + std::static_pointer_cast(opentracing::Tracer::Global()); + const std::unique_ptr span(static_cast( + tracer->StartSpanWithOptions("test-inject", {}).release())); + const auto spanContext = span->context(); + + std::ostringstream oss; + oss << "00"; + oss << '-'; + oss << std::setw(16) << std::setfill('0') << 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 + << spanContext.spanID(); + oss << '-'; + oss << (spanContext.isSampled() ? "01" : "00"); + + StrMap headerMap; + WriterMock headerWriter(headerMap); + ASSERT_TRUE( + static_cast(tracer->Inject(span->context(), headerWriter))); + ASSERT_EQ(1, headerMap.size()); + ASSERT_EQ(oss.str(), headerMap.at(kW3CTraceParentHeaderName)); + + ReaderMock headerReader(headerMap); + auto result = tracer->Extract(headerReader); + ASSERT_TRUE(static_cast(result)); + std::unique_ptr extractedCtx( + static_cast(result->release())); + ASSERT_TRUE(static_cast(extractedCtx)); + ASSERT_EQ(span->context(), *extractedCtx); + + tracer->Close(); +} + +TEST(Tracer, testPropagationWithW3CTraceState) +{ + const auto handle = + testutils::TracerUtil::installGlobalTracerW3CPropagation(); + const auto tracer = + std::static_pointer_cast(opentracing::Tracer::Global()); + StrMap headerMap{ + { kW3CTraceParentHeaderName, + "00-00000000000000000000000000000001-0000000000000001-01" }, + { kW3CTraceStateHeaderName, "foo=bar" } + }; + + ReaderMock headerReader(headerMap); + auto result = tracer->Extract(headerReader); + std::unique_ptr ctx( + static_cast(result->release())); + ASSERT_EQ("foo=bar", ctx->traceState()); + + headerMap.clear(); + + WriterMock headerWriter(headerMap); + tracer->Inject(*ctx, headerWriter); + ASSERT_EQ(2, headerMap.size()); + ASSERT_EQ("foo=bar", headerMap.at(kW3CTraceStateHeaderName)); +} + TEST(Tracer, testTracerTags) { std::vector tags; diff --git a/src/jaegertracing/propagation/Format.cpp b/src/jaegertracing/propagation/Format.cpp new file mode 100644 index 00000000..f2e4b103 --- /dev/null +++ b/src/jaegertracing/propagation/Format.cpp @@ -0,0 +1,18 @@ + +/* + * Copyright (c) 2020 The Jaeger Authors + * + * 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/Format.h" diff --git a/src/jaegertracing/propagation/Format.h b/src/jaegertracing/propagation/Format.h new file mode 100644 index 00000000..cedafb00 --- /dev/null +++ b/src/jaegertracing/propagation/Format.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 The Jaeger Authors + * + * 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_FORMAT_H +#define JAEGERTRACING_PROPAGATION_FORMAT_H + +namespace jaegertracing { +namespace propagation { + +enum Format { JAEGER, W3C }; + +} // namespace propagation +} // namespace jaegertracing + +#endif // JAEGERTRACING_PROPAGATION_FORMAT_H \ No newline at end of file diff --git a/src/jaegertracing/propagation/JaegerPropagator.cpp b/src/jaegertracing/propagation/JaegerPropagator.cpp new file mode 100644 index 00000000..35394aea --- /dev/null +++ b/src/jaegertracing/propagation/JaegerPropagator.cpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 The Jaeger Authors + * + * 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..b46bf07d --- /dev/null +++ b/src/jaegertracing/propagation/JaegerPropagator.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2020 The Jaeger Authors + * + * 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 bf04be81..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,48 +58,21 @@ class Propagator : public Extractor, public Injector { SpanContext extract(const Reader& reader) const override { - SpanContext ctx; - StrMap baggage; std::string debugID; - const auto result = reader.ForeachKey( - [this, &ctx, &debugID, &baggage](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); - if (!(iss >> ctx) || 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 { - 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(); } @@ -113,25 +85,21 @@ class Propagator : public Extractor, public Injector { ctx.spanID(), ctx.parentID(), flags, - baggage, - debugID); + ctx.baggage(), + debugID, + ctx.traceState()); } void inject(const SpanContext& ctx, const Writer& writer) const override { - std::ostringstream oss; - oss << ctx; - 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; - }); + 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; @@ -147,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..bf8fb57c --- /dev/null +++ b/src/jaegertracing/propagation/W3CPropagator.cpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 The Jaeger Authors + * + * 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..a7345fcb --- /dev/null +++ b/src/jaegertracing/propagation/W3CPropagator.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2020 The Jaeger Authors + * + * 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..4eb9715a --- /dev/null +++ b/src/jaegertracing/propagation/W3CPropagatorTest.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2020 The Jaeger Authors + * + * 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 ffc3cbeb..f2726e65 100644 --- a/src/jaegertracing/testutils/TracerUtil.cpp +++ b/src/jaegertracing/testutils/TracerUtil.cpp @@ -1,94 +1,102 @@ -/* - * Copyright (c) 2017 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/testutils/TracerUtil.h" -#include "jaegertracing/Config.h" -#include "jaegertracing/Logging.h" -#include "jaegertracing/Tracer.h" -#include "jaegertracing/baggage/RestrictionsConfig.h" -#include "jaegertracing/net/IPAddress.h" -#include "jaegertracing/propagation/HeadersConfig.h" -#include "jaegertracing/reporters/Config.h" -#include "jaegertracing/samplers/Config.h" -#include -#include -#include - -namespace jaegertracing { -namespace testutils { -namespace TracerUtil { - -std::shared_ptr installGlobalTracer(bool traceId128Bit) -{ - std::unique_ptr handle(new ResourceHandle()); - handle->_mockAgent->start(); - std::ostringstream samplingServerURLStream; - samplingServerURLStream - << "http://" << handle->_mockAgent->samplingServerAddress().authority(); - Config config( - false, - traceId128Bit, - samplers::Config("const", - 1, - samplingServerURLStream.str(), - 0, - samplers::Config::Clock::duration()), - reporters::Config(0, - reporters::Config::Clock::duration(), - false, - handle->_mockAgent->spanServerAddress().authority()), - propagation::HeadersConfig(), - baggage::RestrictionsConfig()); - - auto tracer = Tracer::make("test-service", config, logging::nullLogger()); - opentracing::Tracer::InitGlobal(tracer); - return std::move(handle); -} - -std::shared_ptr installGlobalTracer() -{ - return installGlobalTracer(false); -} - -std::shared_ptr installGlobalTracer128Bit() -{ - return installGlobalTracer(true); -} - -std::shared_ptr buildTracer(const std::string& endpoint) -{ - std::ostringstream samplingServerURLStream; - Config config( - false, - false, - samplers::Config("const", - 1, - samplingServerURLStream.str(), - 0, - samplers::Config::Clock::duration()), - reporters::Config(0, - std::chrono::milliseconds(100), - false, "", endpoint), - propagation::HeadersConfig(), - baggage::RestrictionsConfig()); - - auto tracer = Tracer::make("test-service", config, logging::nullLogger()); - return tracer; -} - -} // namespace TracerUtil -} // namespace testutils -} // namespace jaegertracing +/* + * Copyright (c) 2017 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/testutils/TracerUtil.h" +#include "jaegertracing/Config.h" +#include "jaegertracing/Logging.h" +#include "jaegertracing/Tracer.h" +#include "jaegertracing/baggage/RestrictionsConfig.h" +#include "jaegertracing/net/IPAddress.h" +#include "jaegertracing/propagation/HeadersConfig.h" +#include "jaegertracing/reporters/Config.h" +#include "jaegertracing/samplers/Config.h" +#include +#include +#include + +namespace jaegertracing { +namespace testutils { +namespace TracerUtil { + +std::shared_ptr installGlobalTracer(bool traceId128Bit, propagation::Format propagationFormat) +{ + std::unique_ptr handle(new ResourceHandle()); + handle->_mockAgent->start(); + std::ostringstream samplingServerURLStream; + samplingServerURLStream + << "http://" << handle->_mockAgent->samplingServerAddress().authority(); + Config config( + false, + traceId128Bit, + samplers::Config("const", + 1, + samplingServerURLStream.str(), + 0, + samplers::Config::Clock::duration()), + reporters::Config(0, + reporters::Config::Clock::duration(), + false, + handle->_mockAgent->spanServerAddress().authority()), + propagation::HeadersConfig(), + baggage::RestrictionsConfig(), + "", + std::vector(), + propagationFormat); + + auto tracer = Tracer::make("test-service", config, logging::nullLogger()); + opentracing::Tracer::InitGlobal(tracer); + return std::move(handle); +} + +std::shared_ptr installGlobalTracer() +{ + return installGlobalTracer(false, propagation::Format::JAEGER); +} + +std::shared_ptr installGlobalTracer128Bit() +{ + return installGlobalTracer(true, propagation::Format::JAEGER); +} + +std::shared_ptr installGlobalTracerW3CPropagation() +{ + return installGlobalTracer(false, propagation::Format::W3C); +} + +std::shared_ptr buildTracer(const std::string& endpoint) +{ + std::ostringstream samplingServerURLStream; + Config config( + false, + false, + samplers::Config("const", + 1, + samplingServerURLStream.str(), + 0, + samplers::Config::Clock::duration()), + reporters::Config(0, + std::chrono::milliseconds(100), + false, "", endpoint), + propagation::HeadersConfig(), + baggage::RestrictionsConfig()); + + auto tracer = Tracer::make("test-service", config, logging::nullLogger()); + return tracer; +} + +} // namespace TracerUtil +} // namespace testutils +} // namespace jaegertracing diff --git a/src/jaegertracing/testutils/TracerUtil.h b/src/jaegertracing/testutils/TracerUtil.h index 020a7534..8a012910 100644 --- a/src/jaegertracing/testutils/TracerUtil.h +++ b/src/jaegertracing/testutils/TracerUtil.h @@ -20,6 +20,7 @@ #include #include "jaegertracing/Tracer.h" +#include "jaegertracing/propagation/Format.h" #include "jaegertracing/testutils/MockAgent.h" namespace jaegertracing { @@ -42,6 +43,7 @@ struct ResourceHandle { std::shared_ptr installGlobalTracer(); std::shared_ptr installGlobalTracer128Bit(); +std::shared_ptr installGlobalTracerW3CPropagation(); std::shared_ptr buildTracer(const std::string& endpoint); } // namespace TracerUtil