diff --git a/README.md b/README.md index 18e83c01..d1d6146c 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,21 @@ JAEGER_SAMPLER_PARAM | The sampler parameter (double) JAEGER_SAMPLING_ENDPOINT | The url for the remote sampling conf when using sampler type remote. Default is http://127.0.0.1:5778/sampling JAEGER_TAGS | A comma separated list of `name = value` tracer level tags, which get added to all reported spans. The value can also refer to an environment variable using the format `${envVarName:default}`, where the `:default` is optional, and identifies a value to be used if the environment variable cannot be found +### SelfRef +Jaeger Tracer supports an additional reference type call 'SelfRef'. +It returns an opentracing::SpanReference which can be passed to Tracer::StartSpan +to influence the SpanContext of the newly created span. Specifically, the new span inherits the traceID +and spanID from the passed SELF reference. It can be used to pass externally generated IDs to the tracer, +with the purpose of recording spans from data generated elsewhere (e.g. from logs), or by augmenting the +data of the existing span (Jaeger backend will merge multiple instances of the spans with the same IDs). +Must be the lone reference, can be used only for root spans. + +Usage example: +``` + jaegertracing::SpanContext customCtx { {1, 2}, 3, 0, 0, jaegertracing::SpanContext::StrMap() }; // TraceId and SpanID must be != 0 + auto span = tracer->StartSpan("spanName", { jaegertracing::SelfRef(&customCtx) }); +``` + ## License [Apache 2.0 License](./LICENSE). diff --git a/src/jaegertracing/Tracer.cpp b/src/jaegertracing/Tracer.cpp index 1fb6087a..b6037c00 100644 --- a/src/jaegertracing/Tracer.cpp +++ b/src/jaegertracing/Tracer.cpp @@ -33,6 +33,9 @@ using SystemClock = Tracer::SystemClock; using SteadyClock = Tracer::SteadyClock; using TimePoints = std::tuple; +// An extension of opentracing::SpanReferenceType enum. See jaegertracing::SelfRef(). +const static int SpanReferenceType_JaegerSpecific_SelfRef = 99; + TimePoints determineStartTimes(const opentracing::StartSpanOptions& options) { if (options.start_system_timestamp == SystemClock::time_point() && @@ -67,7 +70,12 @@ Tracer::StartSpanWithOptions(string_view operationName, try { const auto result = analyzeReferences(options.references); const auto* parent = result._parent; + const auto* self = result._self; const auto& references = result._references; + if (self && (parent || !references.empty())) + { + throw std::invalid_argument("Self and references are exclusive. Only one of them can be specified"); + } std::vector samplerTags; auto newTrace = false; @@ -75,11 +83,19 @@ Tracer::StartSpanWithOptions(string_view operationName, if (!parent || !parent->isValid()) { newTrace = true; auto highID = static_cast(0); - if (_options & kGen128BitOption) { - highID = randomID(); + auto lowID = static_cast(0); + if (self) { + highID = self->traceID().high(); + lowID = self->traceID().low(); + } + else { + if (_options & kGen128BitOption) { + highID = randomID(); + } + lowID = randomID(); } - const TraceID traceID(highID, randomID()); - const auto spanID = traceID.low(); + const TraceID traceID(highID, lowID); + const auto spanID = self ? self->spanID() : traceID.low(); const auto parentID = 0; auto flags = static_cast(0); if (parent && parent->isDebugIDContainerOnly()) { @@ -123,6 +139,11 @@ Tracer::StartSpanWithOptions(string_view operationName, options.tags, newTrace, references); + } catch (const std::exception& ex) { + std::ostringstream oss; + oss << "Error occurred in Tracer::StartSpanWithOptions: " << ex.what(); + utils::ErrorUtil::logError(*_logger, oss.str()); + return nullptr; } catch (...) { utils::ErrorUtil::logError( *_logger, "Error occurred in Tracer::StartSpanWithOptions"); @@ -194,6 +215,12 @@ Tracer::analyzeReferences(const std::vector& references) const continue; } + if (static_cast(ref.first) == SpanReferenceType_JaegerSpecific_SelfRef) + { + result._self = ctx; + continue; // not a reference + } + result._references.emplace_back(Reference(*ctx, ref.first)); if (!hasParent) { @@ -245,4 +272,8 @@ Tracer::make(const std::string& serviceName, options)); } +opentracing::SpanReference SelfRef(const opentracing::SpanContext* span_context) noexcept { + return {static_cast(SpanReferenceType_JaegerSpecific_SelfRef), span_context}; +} + } // namespace jaegertracing diff --git a/src/jaegertracing/Tracer.h b/src/jaegertracing/Tracer.h index b0619696..8d204267 100644 --- a/src/jaegertracing/Tracer.h +++ b/src/jaegertracing/Tracer.h @@ -273,11 +273,13 @@ class Tracer : public opentracing::Tracer, struct AnalyzedReferences { AnalyzedReferences() : _parent(nullptr) + , _self(nullptr) , _references() { } const SpanContext* _parent; + const SpanContext* _self; std::vector _references; }; @@ -301,6 +303,15 @@ class Tracer : public opentracing::Tracer, int _options; }; + +// jaegertracing::SelfRef() returns an opentracing::SpanReference which can be passed to Tracer::StartSpan +// to influence the SpanContext of the newly created span. Specifically, the new span inherits the traceID +// and spanID from the passed SELF reference. It can be used to pass externally generated IDs to the tracer, +// with the purpose of recording spans from data generated elsewhere (e.g. from logs), or by augmenting the +// data of the existing span (Jaeger backend will merge multiple instances of the spans with the same IDs). +// Must be the lone reference, can be used only for root spans +opentracing::SpanReference SelfRef(const opentracing::SpanContext* span_context) noexcept; + } // namespace jaegertracing #endif // JAEGERTRACING_TRACER_H diff --git a/src/jaegertracing/TracerTest.cpp b/src/jaegertracing/TracerTest.cpp index 4a5a0057..edafdf84 100644 --- a/src/jaegertracing/TracerTest.cpp +++ b/src/jaegertracing/TracerTest.cpp @@ -490,4 +490,61 @@ TEST(Tracer, testTracerTags) ASSERT_EQ(std::string("test-service"), jaegerTracer->serviceName()); } +TEST(Tracer, testTracerSimpleChild) +{ + const auto handle = testutils::TracerUtil::installGlobalTracer(); + const auto tracer = std::static_pointer_cast(opentracing::Tracer::Global()); + { + auto spanRoot = tracer->StartSpan("test-simple-root"); + ASSERT_TRUE(spanRoot); + auto spanChild = tracer->StartSpan("test-simple-child", + { opentracing::ChildOf(&spanRoot->context()) }); + ASSERT_TRUE(spanChild); + } + tracer->Close(); +} + +TEST(Tracer, testTracerSpanSelfRef) +{ + const auto handle = testutils::TracerUtil::installGlobalTracer(); + const auto tracer = std::static_pointer_cast(opentracing::Tracer::Global()); + { + const jaegertracing::SpanContext spanSelfContext { {1, 2}, 3, 0, 0, jaegertracing::SpanContext::StrMap() }; + auto spanRoot = tracer->StartSpan("test-root-self-ref", {jaegertracing::SelfRef(&spanSelfContext)}); + ASSERT_TRUE(spanRoot); + auto jaegerSpanRoot = dynamic_cast(*spanRoot.get()); + ASSERT_EQ(jaegerSpanRoot.context().traceID(), jaegertracing::TraceID(1, 2)); + ASSERT_EQ(jaegerSpanRoot.context().spanID(), 3); + + auto spanChild = tracer->StartSpan("test-child-self-ref", + { opentracing::ChildOf(&spanRoot->context()) }); + ASSERT_TRUE(spanChild); + auto jaegerSpanChild = dynamic_cast(*spanChild.get()); + ASSERT_EQ(jaegerSpanChild.context().traceID(), jaegertracing::TraceID(1, 2)); + ASSERT_NE(jaegerSpanChild.context().spanID(), 3); + } + tracer->Close(); +} + +TEST(Tracer, testTracerSpanSelfRefWithOtherRefs) +{ + const auto handle = testutils::TracerUtil::installGlobalTracer(); + const auto tracer = std::static_pointer_cast(opentracing::Tracer::Global()); + { + const jaegertracing::SpanContext spanSelfContext { {1, 2}, 3, 0, 0, jaegertracing::SpanContext::StrMap() }; + auto spanRoot = tracer->StartSpan("test-root-self-ref", {jaegertracing::SelfRef(&spanSelfContext)}); + ASSERT_TRUE(spanRoot); + auto jaegerSpanRoot = dynamic_cast(*spanRoot.get()); + ASSERT_EQ(jaegerSpanRoot.context().traceID(), jaegertracing::TraceID(1, 2)); + ASSERT_EQ(jaegerSpanRoot.context().spanID(), 3); + + const jaegertracing::SpanContext spanSelfContext2 { {1, 2}, 4, 0, 0, jaegertracing::SpanContext::StrMap() }; + auto spanChild = tracer->StartSpan("test-child-self-ref", + { opentracing::ChildOf(&spanRoot->context()), jaegertracing::SelfRef(&spanSelfContext2) } + ); + ASSERT_FALSE(spanChild); + } + tracer->Close(); +} + } // namespace jaegertracing