From c4f902134a2f373374c5378c6381b1a57221415b Mon Sep 17 00:00:00 2001 From: DJ Gregor Date: Tue, 8 Mar 2022 16:15:19 -0500 Subject: [PATCH] Add support for span links to Jaeger export. --- CHANGELOG.md | 2 ++ .../exporters/jaeger/recordable.h | 2 ++ exporters/jaeger/src/recordable.cc | 28 ++++++++++++++- exporters/jaeger/src/thrift_sender.cc | 1 + .../jaeger/test/jaeger_recordable_test.cc | 35 +++++++++++++++++++ 5 files changed, 67 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6997b4012..52c30cfea8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ Increment the: ## [Unreleased] +* [EXPORTER] Jaeger Exporter - Populate Span Links ([#1251](https://github.com/open-telemetry/opentelemetry-cpp/pull/1251)) + ## [1.2.0] 2022-01-31 * [CI] Continuous benchmark tests as part of the CI ([#1174](https://github.com/open-telemetry/opentelemetry-cpp/pull/1174)) diff --git a/exporters/jaeger/include/opentelemetry/exporters/jaeger/recordable.h b/exporters/jaeger/include/opentelemetry/exporters/jaeger/recordable.h index d7551bfa07..98e1e61317 100644 --- a/exporters/jaeger/include/opentelemetry/exporters/jaeger/recordable.h +++ b/exporters/jaeger/include/opentelemetry/exporters/jaeger/recordable.h @@ -58,6 +58,7 @@ class JaegerRecordable final : public sdk::trace::Recordable std::vector Tags() noexcept { return std::move(tags_); } std::vector ResourceTags() noexcept { return std::move(resource_tags_); } std::vector Logs() noexcept { return std::move(logs_); } + std::vector References() noexcept { return std::move(references_); } const std::string &ServiceName() const noexcept { return service_name_; } void SetIdentity(const opentelemetry::trace::SpanContext &span_context, @@ -109,6 +110,7 @@ class JaegerRecordable final : public sdk::trace::Recordable std::vector tags_; std::vector resource_tags_; std::vector logs_; + std::vector references_; std::string service_name_; }; diff --git a/exporters/jaeger/src/recordable.cc b/exporters/jaeger/src/recordable.cc index 58ef6873e0..c4a61a5d22 100644 --- a/exporters/jaeger/src/recordable.cc +++ b/exporters/jaeger/src/recordable.cc @@ -193,7 +193,33 @@ void JaegerRecordable::SetInstrumentationLibrary( void JaegerRecordable::AddLink(const trace::SpanContext &span_context, const common::KeyValueIterable &attributes) noexcept { - // TODO: convert link to SpanRefernece + // Note: "The Link’s attributes cannot be represented in Jaeger explicitly." + // -- https://opentelemetry.io/docs/reference/specification/trace/sdk_exporters/jaeger/#links + // + // This implementation does not (currently) implement the optional conversion to span logs. + + thrift::SpanRef reference; + + reference.__set_refType(thrift::SpanRefType::FOLLOWS_FROM); + + // IDs should be converted to big endian before transmission. + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/jaeger.md#ids +#if JAEGER_IS_LITTLE_ENDIAN == 1 + reference.__set_traceIdHigh( + otel_bswap_64(*(reinterpret_cast(span_context.trace_id().Id().data())))); + reference.__set_traceIdLow( + otel_bswap_64(*(reinterpret_cast(span_context.trace_id().Id().data()) + 1))); + reference.__set_spanId( + otel_bswap_64(*(reinterpret_cast(span_context.span_id().Id().data())))); +#else + reference.__set_traceIdLow( + *(reinterpret_cast(span_context.trace_id().Id().data()))); + reference.__set_traceIdHigh( + *(reinterpret_cast(span_context.trace_id().Id().data()) + 1)); + reference.__set_spanId(*(reinterpret_cast(span_context.span_id().Id().data()))); +#endif + + references_.push_back(reference); } void JaegerRecordable::SetStatus(trace::StatusCode code, nostd::string_view description) noexcept diff --git a/exporters/jaeger/src/thrift_sender.cc b/exporters/jaeger/src/thrift_sender.cc index 548f90770a..46f0dcd5aa 100644 --- a/exporters/jaeger/src/thrift_sender.cc +++ b/exporters/jaeger/src/thrift_sender.cc @@ -40,6 +40,7 @@ int ThriftSender::Append(std::unique_ptr &&span) noexcept auto jaeger_span = std::unique_ptr(span->Span()); jaeger_span->__set_tags(span->Tags()); jaeger_span->__set_logs(span->Logs()); + jaeger_span->__set_references(span->References()); const uint32_t span_size = CalcSizeOfSerializedThrift(*jaeger_span); if (span_size > max_span_bytes) diff --git a/exporters/jaeger/test/jaeger_recordable_test.cc b/exporters/jaeger/test/jaeger_recordable_test.cc index b496db9028..4a0a1f74b7 100644 --- a/exporters/jaeger/test/jaeger_recordable_test.cc +++ b/exporters/jaeger/test/jaeger_recordable_test.cc @@ -21,6 +21,8 @@ using namespace opentelemetry::exporter::jaeger; using namespace opentelemetry::sdk::instrumentationlibrary; using std::vector; +using Attributes = std::initializer_list>; + TEST(JaegerSpanRecordable, SetIdentity) { JaegerRecordable rec; @@ -297,3 +299,36 @@ TEST(JaegerSpanRecordable, SetResource) } } } + +TEST(JaegerSpanRecordable, AddLink) +{ + JaegerRecordable rec; + + int64_t trace_id_val[2] = {0x0000000000000000, 0x1000000000000000}; + int64_t span_id_val = 0x2000000000000000; + + const trace::TraceId trace_id{ + nostd::span(reinterpret_cast(trace_id_val), 16)}; + + const trace::SpanId span_id( + nostd::span(reinterpret_cast(&span_id_val), 8)); + + const trace::SpanContext span_context{trace_id, span_id, + trace::TraceFlags{trace::TraceFlags::kIsSampled}, true}; + rec.AddLink(span_context, common::KeyValueIterableView({{"attr1", "string"}})); + + auto references = rec.References(); + EXPECT_EQ(references.size(), 1); + + auto reference = references.front(); + +#if JAEGER_IS_LITTLE_ENDIAN == 1 + EXPECT_EQ(reference.traceIdLow, otel_bswap_64(trace_id_val[1])); + EXPECT_EQ(reference.traceIdHigh, otel_bswap_64(trace_id_val[0])); + EXPECT_EQ(reference.spanId, otel_bswap_64(span_id_val)); +#else + EXPECT_EQ(reference.traceIdLow, trace_id_val[0]); + EXPECT_EQ(reference.traceIdHigh, trace_id_val[1]); + EXPECT_EQ(reference.spanId, span_id_val); +#endif +}