diff --git a/opentracing-shim/include/span_context_shim.h b/opentracing-shim/include/span_context_shim.h index d615d56d0b..f0493a983f 100644 --- a/opentracing-shim/include/span_context_shim.h +++ b/opentracing-shim/include/span_context_shim.h @@ -21,7 +21,7 @@ class SpanContextShim final : public opentracing::SpanContext explicit SpanContextShim(const opentelemetry::trace::SpanContext& context, const BaggagePtr& baggage) : context_(context), baggage_(baggage) {} inline const opentelemetry::trace::SpanContext& context() const { return context_; } - inline const BaggagePtr& baggage() const { return baggage_; } + inline const BaggagePtr baggage() const { return baggage_; } SpanContextShim newWithKeyValue(nostd::string_view key, nostd::string_view value) const noexcept; bool BaggageItem(nostd::string_view key, std::string& value) const noexcept; // Overrides diff --git a/opentracing-shim/include/span_shim.h b/opentracing-shim/include/span_shim.h index 72b7349c89..238738228f 100644 --- a/opentracing-shim/include/span_shim.h +++ b/opentracing-shim/include/span_shim.h @@ -40,7 +40,7 @@ class SpanShim : public opentracing::Span inline const opentracing::Tracer& tracer() const noexcept override { return tracer_; }; private: - void logImpl(opentracing::SystemTime timestamp, nostd::span fields) noexcept; + void logImpl(nostd::span fields, const opentracing::SystemTime* const timestamp) noexcept; const TracerShim& tracer_; SpanPtr span_; diff --git a/opentracing-shim/src/span_shim.cc b/opentracing-shim/src/span_shim.cc index fedd3575cf..1f1be112c4 100644 --- a/opentracing-shim/src/span_shim.cc +++ b/opentracing-shim/src/span_shim.cc @@ -67,14 +67,18 @@ void SpanShim::SetBaggageItem(opentracing::string_view restricted_key, opentraci { // Creates a new SpanContext Shim with a new OpenTelemetry Baggage containing the specified // Baggage key/value pair, and sets it as the current instance for this Span Shim. + if (restricted_key.empty() || value.empty()) return; + const std::lock_guard guard(context_lock_); - context_ = context_.newWithKeyValue(restricted_key.data(), value.data());; + context_ = context_.newWithKeyValue(restricted_key.data(), value.data()); } std::string SpanShim::BaggageItem(opentracing::string_view restricted_key) const noexcept { // Returns the value for the specified key in the OpenTelemetry Baggage // of the current SpanContext Shim, or null if none exists. + if (restricted_key.empty()) return ""; + const std::lock_guard guard(context_lock_); std::string value; return context_.BaggageItem(restricted_key.data(), value) ? value : ""; @@ -84,24 +88,24 @@ void SpanShim::Log(std::initializer_list fields) noexcept { // If an explicit timestamp is specified, a conversion MUST // be done to match the OpenTracing and OpenTelemetry units. - logImpl(opentracing::SystemTime::min(), fields); + logImpl(fields, nullptr); } void SpanShim::Log(opentracing::SystemTime timestamp, std::initializer_list fields) noexcept { // If an explicit timestamp is specified, a conversion MUST // be done to match the OpenTracing and OpenTelemetry units. - logImpl(timestamp, fields); + logImpl(fields, ×tamp); } void SpanShim::Log(opentracing::SystemTime timestamp, const std::vector& fields) noexcept { // If an explicit timestamp is specified, a conversion MUST // be done to match the OpenTracing and OpenTelemetry units. - logImpl(timestamp, fields); + logImpl(fields, ×tamp); } -void SpanShim::logImpl(opentracing::SystemTime timestamp, nostd::span fields) noexcept +void SpanShim::logImpl(nostd::span fields, const opentracing::SystemTime* const timestamp) noexcept { // The Add Event’s name parameter MUST be the value with the event key // in the pair set, or else fallback to use the log literal string. @@ -143,9 +147,9 @@ void SpanShim::logImpl(opentracing::SystemTime timestamp, nostd::spanAddEvent(name, timestamp, attributes); + span_->AddEvent(name, *timestamp, attributes); } else { diff --git a/opentracing-shim/test/shim_mocks.h b/opentracing-shim/test/shim_mocks.h index 2842c35db0..1a74ae1f49 100644 --- a/opentracing-shim/test/shim_mocks.h +++ b/opentracing-shim/test/shim_mocks.h @@ -6,13 +6,72 @@ #pragma once #include +#include +#include +#include +#include #include #include +#include -namespace baggage = opentelemetry::baggage; -namespace context = opentelemetry::context; -namespace nostd = opentelemetry::nostd; +namespace trace_api = opentelemetry::trace; +namespace baggage = opentelemetry::baggage; +namespace common = opentelemetry::common; +namespace context = opentelemetry::context; +namespace nostd = opentelemetry::nostd; + +struct MockSpan final : public trace_api::Span +{ + void SetAttribute(nostd::string_view key, + const common::AttributeValue& value) noexcept override + { + attribute_ = {key.data(), value}; + } + + void AddEvent(nostd::string_view name, + common::SystemTimestamp timestamp, + const common::KeyValueIterable& attributes) noexcept override + { + std::unordered_map attribute_map; + attribute_map.reserve(attributes.size()); + attributes.ForEachKeyValue([&attribute_map](nostd::string_view key, const common::AttributeValue& value){ + attribute_map.emplace(key.data(), value); + return true; + }); + event_ = {name.data(), timestamp, attribute_map}; + } + + void AddEvent(nostd::string_view name, + const common::KeyValueIterable& attributes) noexcept override + { + AddEvent(name, {}, attributes); + } + + void AddEvent(nostd::string_view name, + common::SystemTimestamp timestamp) noexcept override {} + + void AddEvent(nostd::string_view name) noexcept override {} + + void SetStatus(trace_api::StatusCode code, nostd::string_view description) noexcept override + { + status_ = {code, description.data()}; + } + + void UpdateName(nostd::string_view name) noexcept override { name_ = name.data(); } + + void End(const trace_api::EndSpanOptions& options) noexcept override { options_ = options; } + + bool IsRecording() const noexcept override { return false; } + + trace_api::SpanContext GetContext() const noexcept override { return trace_api::SpanContext(false, false); } + + std::pair attribute_; + std::tuple> event_; + std::pair status_; + std::string name_; + trace_api::EndSpanOptions options_; +}; struct MockPropagator : public context::propagation::TextMapPropagator { diff --git a/opentracing-shim/test/span_shim_test.cc b/opentracing-shim/test/span_shim_test.cc new file mode 100644 index 0000000000..4d6cebd80b --- /dev/null +++ b/opentracing-shim/test/span_shim_test.cc @@ -0,0 +1,184 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "span_shim.h" +#include "tracer_shim.h" +#include "shim_mocks.h" + +#include + +namespace trace_api = opentelemetry::trace; +namespace baggage = opentelemetry::baggage; +namespace nostd = opentelemetry::nostd; +namespace shim = opentelemetry::opentracingshim; + +class SpanShimTest : public testing::Test +{ +public: + nostd::unique_ptr span_shim; + MockSpan* mock_span; + +protected: + virtual void SetUp() + { + mock_span = new MockSpan(); + auto span = nostd::shared_ptr(mock_span); + auto tracer = shim::TracerShim::createTracerShim(); + auto tracer_shim = dynamic_cast(tracer.get()); + auto baggage = baggage::Baggage::GetDefault()->Set("baggage", "item"); + span_shim = nostd::unique_ptr( + new shim::SpanShim(*tracer_shim, span, baggage)); + } + + virtual void TearDown() + { + span_shim.reset(); + } +}; + +TEST_F(SpanShimTest, HandleError) +{ + span_shim->handleError(true); + ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kError); + span_shim->handleError("true"); + ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kError); + span_shim->handleError(false); + ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kOk); + span_shim->handleError("false"); + ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kOk); + span_shim->handleError(nullptr); + ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kUnset); +} + +TEST_F(SpanShimTest, FinishWithOptions) +{ + opentracing::FinishSpanOptions options; + options.finish_steady_timestamp = opentracing::SteadyTime::clock::now(); + ASSERT_NE(mock_span->options_.end_steady_time, options.finish_steady_timestamp); + span_shim->FinishWithOptions(options); + ASSERT_EQ(mock_span->options_.end_steady_time, options.finish_steady_timestamp); +} + +TEST_F(SpanShimTest, SetOperationName) +{ + ASSERT_NE(mock_span->name_, "foo"); + span_shim->SetOperationName("foo"); + ASSERT_EQ(mock_span->name_, "foo"); +} + +TEST_F(SpanShimTest, SetTag_Normal) +{ + ASSERT_NE(mock_span->attribute_.first, "foo"); + span_shim->SetTag("foo", "bar"); + ASSERT_EQ(mock_span->attribute_.first, "foo"); + ASSERT_STREQ(nostd::get(mock_span->attribute_.second), "bar"); +} + +TEST_F(SpanShimTest, SetTag_Error) +{ + ASSERT_NE(mock_span->attribute_.first, "error"); + span_shim->SetTag("error", true); + ASSERT_NE(mock_span->attribute_.first, "error"); + span_shim->SetTag("error", "false"); + ASSERT_NE(mock_span->attribute_.first, "error"); + span_shim->SetTag("error", nullptr); + ASSERT_NE(mock_span->attribute_.first, "error"); +} + +TEST_F(SpanShimTest, BaggageItem) +{ + ASSERT_EQ(span_shim->BaggageItem({}), ""); + ASSERT_EQ(span_shim->BaggageItem(""), ""); + ASSERT_EQ(span_shim->BaggageItem("invalid"), ""); + ASSERT_EQ(span_shim->BaggageItem("baggage"), "item"); +} + +TEST_F(SpanShimTest, SetBaggageItem) +{ + span_shim->SetBaggageItem("new", "entry"); + ASSERT_EQ(span_shim->BaggageItem("new"), "entry"); + ASSERT_EQ(span_shim->BaggageItem("baggage"), "item"); + span_shim->SetBaggageItem("empty", ""); + ASSERT_EQ(span_shim->BaggageItem("empty"), ""); + span_shim->SetBaggageItem("no value", {}); + ASSERT_EQ(span_shim->BaggageItem("no value"), ""); +} + +TEST_F(SpanShimTest, Log_NoEvent) +{ + std::string name; + common::SystemTimestamp timestamp; + std::unordered_map attributes; + + span_shim->Log({{"test", 42}}); + std::tie(name, timestamp, attributes) = mock_span->event_; + + ASSERT_EQ(name, "log"); + ASSERT_EQ(timestamp, common::SystemTimestamp{}); + ASSERT_EQ(attributes.size(), 1); + ASSERT_EQ(nostd::get(attributes["test"]), 42); +} + +TEST_F(SpanShimTest, Log_NoEvent_Timestamp) +{ + std::string name; + common::SystemTimestamp timestamp; + std::unordered_map attributes; + + auto logtime = opentracing::SystemTime::time_point::clock::now(); + span_shim->Log(logtime, {{"foo", "bar"}}); + std::tie(name, timestamp, attributes) = mock_span->event_; + + ASSERT_EQ(name, "log"); + ASSERT_EQ(timestamp, common::SystemTimestamp{logtime}); + ASSERT_EQ(attributes.size(), 1); + ASSERT_STREQ(nostd::get(attributes["foo"]), "bar"); +} + +TEST_F(SpanShimTest, Log_Event) +{ + std::string name; + common::SystemTimestamp timestamp; + std::unordered_map attributes; + + auto logtime = opentracing::SystemTime::time_point::clock::now(); + std::initializer_list> fields{ + {"event", "test!"}, {"foo", opentracing::string_view{"bar"}}, + {"error.kind", 42}, {"message","hello"}, {"stack","overflow"}}; + span_shim->Log(logtime, fields); + std::tie(name, timestamp, attributes) = mock_span->event_; + + ASSERT_EQ(name, "test!"); + ASSERT_EQ(timestamp, common::SystemTimestamp{logtime}); + ASSERT_EQ(attributes.size(), 5); + ASSERT_STREQ(nostd::get(attributes["event"]), "test!"); + ASSERT_EQ(nostd::get(attributes["foo"]), nostd::string_view{"bar"}); + ASSERT_EQ(nostd::get(attributes["error.kind"]), 42); + ASSERT_STREQ(nostd::get(attributes["message"]), "hello"); + ASSERT_STREQ(nostd::get(attributes["stack"]), "overflow"); +} + +TEST_F(SpanShimTest, Log_Error) +{ + std::string name; + common::SystemTimestamp timestamp; + std::unordered_map attributes; + + auto logtime = opentracing::SystemTime::time_point::clock::now(); + std::vector> fields{ + {"event", "error"}, {"foo", opentracing::string_view{"bar"}}, + {"error.kind", 42}, {"message","hello"}, {"stack","overflow"}}; + span_shim->Log(logtime, fields); + std::tie(name, timestamp, attributes) = mock_span->event_; + + ASSERT_EQ(name, "exception"); + ASSERT_EQ(timestamp, common::SystemTimestamp{logtime}); + ASSERT_EQ(attributes.size(), 5); + ASSERT_STREQ(nostd::get(attributes["event"]), "error"); + ASSERT_EQ(nostd::get(attributes["foo"]), nostd::string_view{"bar"}); + ASSERT_EQ(nostd::get(attributes["exception.type"]), 42); + ASSERT_STREQ(nostd::get(attributes["exception.message"]), "hello"); + ASSERT_STREQ(nostd::get(attributes["exception.stacktrace"]), "overflow"); +}