Skip to content

Commit 78ea963

Browse files
Alek86lrouquette
authored andcommitted
An extension of enum opentracing::SpanReferenceType, for a new Span. (jaegertracing#206)
* An extension of enum opentracing::SpanReferenceType, for a new Span. Only to copy traceID and (for non-root spans) spanID, because spanID for root spans == traceID.low() Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com> * 1) Renamed useTheseIDs to SelfRef, for consistency between different lang implementations of Jaeger client 2) SpanId is always taken from the SelfRef context Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com> * Seems like on some compilers jaegertracing::SpanContext::StrMap(initializer_list) is explicit Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com> * Temporarily commented out the new unit test case body Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com> * SelfRef only used for creating root spans and can be passed as the only reference to enforce this rule Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com> * Apparently std::exception ctor with a const char* is not standard Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com> * Updates in README and code comments as per reviewer's request Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com> * Added a testTracer subtest with no selfref to check the github CI result Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com> * Removed test changes Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com> * Added 2 unittests - a simple span child and a simple self ref Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com> * Added child span to selfref unittest, small changes in new tests Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com> * Show better log if sef ref is used with other references Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com> * Change in error log if selfref is used with another ref Signed-off-by: Oleksandr Bukaiev <bukaevav@gmail.com>
1 parent 9e1b39c commit 78ea963

File tree

4 files changed

+118
-4
lines changed

4 files changed

+118
-4
lines changed

README.md

+15
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,21 @@ JAEGER_SAMPLER_PARAM | The sampler parameter (double)
107107
JAEGER_SAMPLING_ENDPOINT | The url for the remote sampling conf when using sampler type remote. Default is http://127.0.0.1:5778/sampling
108108
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
109109

110+
### SelfRef
111+
Jaeger Tracer supports an additional reference type call 'SelfRef'.
112+
It returns an opentracing::SpanReference which can be passed to Tracer::StartSpan
113+
to influence the SpanContext of the newly created span. Specifically, the new span inherits the traceID
114+
and spanID from the passed SELF reference. It can be used to pass externally generated IDs to the tracer,
115+
with the purpose of recording spans from data generated elsewhere (e.g. from logs), or by augmenting the
116+
data of the existing span (Jaeger backend will merge multiple instances of the spans with the same IDs).
117+
Must be the lone reference, can be used only for root spans.
118+
119+
Usage example:
120+
```
121+
jaegertracing::SpanContext customCtx { {1, 2}, 3, 0, 0, jaegertracing::SpanContext::StrMap() }; // TraceId and SpanID must be != 0
122+
auto span = tracer->StartSpan("spanName", { jaegertracing::SelfRef(&customCtx) });
123+
```
124+
110125
## License
111126

112127
[Apache 2.0 License](./LICENSE).

src/jaegertracing/Tracer.cpp

+35-4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ using SystemClock = Tracer::SystemClock;
3333
using SteadyClock = Tracer::SteadyClock;
3434
using TimePoints = std::tuple<SystemClock::time_point, SteadyClock::time_point>;
3535

36+
// An extension of opentracing::SpanReferenceType enum. See jaegertracing::SelfRef().
37+
const static int SpanReferenceType_JaegerSpecific_SelfRef = 99;
38+
3639
TimePoints determineStartTimes(const opentracing::StartSpanOptions& options)
3740
{
3841
if (options.start_system_timestamp == SystemClock::time_point() &&
@@ -67,19 +70,32 @@ Tracer::StartSpanWithOptions(string_view operationName,
6770
try {
6871
const auto result = analyzeReferences(options.references);
6972
const auto* parent = result._parent;
73+
const auto* self = result._self;
7074
const auto& references = result._references;
75+
if (self && (parent || !references.empty()))
76+
{
77+
throw std::invalid_argument("Self and references are exclusive. Only one of them can be specified");
78+
}
7179

7280
std::vector<Tag> samplerTags;
7381
auto newTrace = false;
7482
SpanContext ctx;
7583
if (!parent || !parent->isValid()) {
7684
newTrace = true;
7785
auto highID = static_cast<uint64_t>(0);
78-
if (_options & kGen128BitOption) {
79-
highID = randomID();
86+
auto lowID = static_cast<uint64_t>(0);
87+
if (self) {
88+
highID = self->traceID().high();
89+
lowID = self->traceID().low();
90+
}
91+
else {
92+
if (_options & kGen128BitOption) {
93+
highID = randomID();
94+
}
95+
lowID = randomID();
8096
}
81-
const TraceID traceID(highID, randomID());
82-
const auto spanID = traceID.low();
97+
const TraceID traceID(highID, lowID);
98+
const auto spanID = self ? self->spanID() : traceID.low();
8399
const auto parentID = 0;
84100
auto flags = static_cast<unsigned char>(0);
85101
if (parent && parent->isDebugIDContainerOnly()) {
@@ -123,6 +139,11 @@ Tracer::StartSpanWithOptions(string_view operationName,
123139
options.tags,
124140
newTrace,
125141
references);
142+
} catch (const std::exception& ex) {
143+
std::ostringstream oss;
144+
oss << "Error occurred in Tracer::StartSpanWithOptions: " << ex.what();
145+
utils::ErrorUtil::logError(*_logger, oss.str());
146+
return nullptr;
126147
} catch (...) {
127148
utils::ErrorUtil::logError(
128149
*_logger, "Error occurred in Tracer::StartSpanWithOptions");
@@ -194,6 +215,12 @@ Tracer::analyzeReferences(const std::vector<OpenTracingRef>& references) const
194215
continue;
195216
}
196217

218+
if (static_cast<int>(ref.first) == SpanReferenceType_JaegerSpecific_SelfRef)
219+
{
220+
result._self = ctx;
221+
continue; // not a reference
222+
}
223+
197224
result._references.emplace_back(Reference(*ctx, ref.first));
198225

199226
if (!hasParent) {
@@ -245,4 +272,8 @@ Tracer::make(const std::string& serviceName,
245272
options));
246273
}
247274

275+
opentracing::SpanReference SelfRef(const opentracing::SpanContext* span_context) noexcept {
276+
return {static_cast<opentracing::SpanReferenceType>(SpanReferenceType_JaegerSpecific_SelfRef), span_context};
277+
}
278+
248279
} // namespace jaegertracing

src/jaegertracing/Tracer.h

+11
Original file line numberDiff line numberDiff line change
@@ -273,11 +273,13 @@ class Tracer : public opentracing::Tracer,
273273
struct AnalyzedReferences {
274274
AnalyzedReferences()
275275
: _parent(nullptr)
276+
, _self(nullptr)
276277
, _references()
277278
{
278279
}
279280

280281
const SpanContext* _parent;
282+
const SpanContext* _self;
281283
std::vector<Reference> _references;
282284
};
283285

@@ -301,6 +303,15 @@ class Tracer : public opentracing::Tracer,
301303
int _options;
302304
};
303305

306+
307+
// jaegertracing::SelfRef() returns an opentracing::SpanReference which can be passed to Tracer::StartSpan
308+
// to influence the SpanContext of the newly created span. Specifically, the new span inherits the traceID
309+
// and spanID from the passed SELF reference. It can be used to pass externally generated IDs to the tracer,
310+
// with the purpose of recording spans from data generated elsewhere (e.g. from logs), or by augmenting the
311+
// data of the existing span (Jaeger backend will merge multiple instances of the spans with the same IDs).
312+
// Must be the lone reference, can be used only for root spans
313+
opentracing::SpanReference SelfRef(const opentracing::SpanContext* span_context) noexcept;
314+
304315
} // namespace jaegertracing
305316

306317
#endif // JAEGERTRACING_TRACER_H

src/jaegertracing/TracerTest.cpp

+57
Original file line numberDiff line numberDiff line change
@@ -490,4 +490,61 @@ TEST(Tracer, testTracerTags)
490490
ASSERT_EQ(std::string("test-service"), jaegerTracer->serviceName());
491491
}
492492

493+
TEST(Tracer, testTracerSimpleChild)
494+
{
495+
const auto handle = testutils::TracerUtil::installGlobalTracer();
496+
const auto tracer = std::static_pointer_cast<Tracer>(opentracing::Tracer::Global());
497+
{
498+
auto spanRoot = tracer->StartSpan("test-simple-root");
499+
ASSERT_TRUE(spanRoot);
500+
auto spanChild = tracer->StartSpan("test-simple-child",
501+
{ opentracing::ChildOf(&spanRoot->context()) });
502+
ASSERT_TRUE(spanChild);
503+
}
504+
tracer->Close();
505+
}
506+
507+
TEST(Tracer, testTracerSpanSelfRef)
508+
{
509+
const auto handle = testutils::TracerUtil::installGlobalTracer();
510+
const auto tracer = std::static_pointer_cast<Tracer>(opentracing::Tracer::Global());
511+
{
512+
const jaegertracing::SpanContext spanSelfContext { {1, 2}, 3, 0, 0, jaegertracing::SpanContext::StrMap() };
513+
auto spanRoot = tracer->StartSpan("test-root-self-ref", {jaegertracing::SelfRef(&spanSelfContext)});
514+
ASSERT_TRUE(spanRoot);
515+
auto jaegerSpanRoot = dynamic_cast<jaegertracing::Span&>(*spanRoot.get());
516+
ASSERT_EQ(jaegerSpanRoot.context().traceID(), jaegertracing::TraceID(1, 2));
517+
ASSERT_EQ(jaegerSpanRoot.context().spanID(), 3);
518+
519+
auto spanChild = tracer->StartSpan("test-child-self-ref",
520+
{ opentracing::ChildOf(&spanRoot->context()) });
521+
ASSERT_TRUE(spanChild);
522+
auto jaegerSpanChild = dynamic_cast<jaegertracing::Span&>(*spanChild.get());
523+
ASSERT_EQ(jaegerSpanChild.context().traceID(), jaegertracing::TraceID(1, 2));
524+
ASSERT_NE(jaegerSpanChild.context().spanID(), 3);
525+
}
526+
tracer->Close();
527+
}
528+
529+
TEST(Tracer, testTracerSpanSelfRefWithOtherRefs)
530+
{
531+
const auto handle = testutils::TracerUtil::installGlobalTracer();
532+
const auto tracer = std::static_pointer_cast<Tracer>(opentracing::Tracer::Global());
533+
{
534+
const jaegertracing::SpanContext spanSelfContext { {1, 2}, 3, 0, 0, jaegertracing::SpanContext::StrMap() };
535+
auto spanRoot = tracer->StartSpan("test-root-self-ref", {jaegertracing::SelfRef(&spanSelfContext)});
536+
ASSERT_TRUE(spanRoot);
537+
auto jaegerSpanRoot = dynamic_cast<jaegertracing::Span&>(*spanRoot.get());
538+
ASSERT_EQ(jaegerSpanRoot.context().traceID(), jaegertracing::TraceID(1, 2));
539+
ASSERT_EQ(jaegerSpanRoot.context().spanID(), 3);
540+
541+
const jaegertracing::SpanContext spanSelfContext2 { {1, 2}, 4, 0, 0, jaegertracing::SpanContext::StrMap() };
542+
auto spanChild = tracer->StartSpan("test-child-self-ref",
543+
{ opentracing::ChildOf(&spanRoot->context()), jaegertracing::SelfRef(&spanSelfContext2) }
544+
);
545+
ASSERT_FALSE(spanChild);
546+
}
547+
tracer->Close();
548+
}
549+
493550
} // namespace jaegertracing

0 commit comments

Comments
 (0)