From 2973baaf476a92e9d11d55e82f1dad78fefe6de1 Mon Sep 17 00:00:00 2001 From: Johannes Tax Date: Mon, 8 Jun 2020 16:52:41 -0700 Subject: [PATCH 01/42] Add a minimal tracer example (#86) --- api/include/opentelemetry/core/timestamp.h | 10 +++ api/include/opentelemetry/plugin/tracer.h | 2 +- api/include/opentelemetry/trace/noop.h | 2 +- api/include/opentelemetry/trace/span.h | 10 ++- examples/CMakeLists.txt | 1 + examples/plugin/plugin/tracer.cc | 2 +- examples/simple/BUILD | 25 ++++++ examples/simple/CMakeLists.txt | 6 ++ examples/simple/foo_library/foo_library.cc | 33 ++++++++ examples/simple/foo_library/foo_library.h | 3 + examples/simple/main.cc | 29 +++++++ examples/simple/stdout_exporter.h | 52 +++++++++++++ .../opentelemetry/sdk/trace/exporter.h | 3 +- .../sdk}/trace/simple_processor.h | 0 .../opentelemetry/sdk/trace/tracer_provider.h | 2 +- sdk/src/trace/.tracer.cc.swp | Bin 0 -> 12288 bytes sdk/src/trace/span.cc | 45 ++++++++++- sdk/src/trace/span.h | 3 +- sdk/src/trace/tracer_provider.cc | 2 +- sdk/test/trace/simple_processor_test.cc | 4 +- sdk/test/trace/tracer_provider_test.cc | 2 +- sdk/test/trace/tracer_test.cc | 71 +++++++++++++++--- 22 files changed, 280 insertions(+), 27 deletions(-) create mode 100644 examples/simple/BUILD create mode 100644 examples/simple/CMakeLists.txt create mode 100644 examples/simple/foo_library/foo_library.cc create mode 100644 examples/simple/foo_library/foo_library.h create mode 100644 examples/simple/main.cc create mode 100644 examples/simple/stdout_exporter.h rename sdk/{src => include/opentelemetry/sdk}/trace/simple_processor.h (100%) create mode 100644 sdk/src/trace/.tracer.cc.swp diff --git a/api/include/opentelemetry/core/timestamp.h b/api/include/opentelemetry/core/timestamp.h index 5fea58d535..7ab7da6f5d 100644 --- a/api/include/opentelemetry/core/timestamp.h +++ b/api/include/opentelemetry/core/timestamp.h @@ -42,6 +42,11 @@ class SystemTimestamp return std::chrono::nanoseconds{nanos_since_epoch_}; } + bool operator==(const SystemTimestamp &other) const noexcept + { + return nanos_since_epoch_ == other.nanos_since_epoch_; + } + private: int64_t nanos_since_epoch_; }; @@ -79,6 +84,11 @@ class SteadyTimestamp return std::chrono::nanoseconds{nanos_since_epoch_}; } + bool operator==(const SteadyTimestamp &other) const noexcept + { + return nanos_since_epoch_ == other.nanos_since_epoch_; + } + private: int64_t nanos_since_epoch_; }; diff --git a/api/include/opentelemetry/plugin/tracer.h b/api/include/opentelemetry/plugin/tracer.h index b2199a07bf..4f00be0c32 100644 --- a/api/include/opentelemetry/plugin/tracer.h +++ b/api/include/opentelemetry/plugin/tracer.h @@ -39,7 +39,7 @@ class Span final : public trace::Span void UpdateName(nostd::string_view name) noexcept override { span_->UpdateName(name); } - void End() noexcept override { span_->End(); } + void End(const trace::EndSpanOptions &options = {}) noexcept override { span_->End(); } bool IsRecording() const noexcept override { return span_->IsRecording(); } diff --git a/api/include/opentelemetry/trace/noop.h b/api/include/opentelemetry/trace/noop.h index 0c3ef15c69..82b10b9a71 100644 --- a/api/include/opentelemetry/trace/noop.h +++ b/api/include/opentelemetry/trace/noop.h @@ -38,7 +38,7 @@ class NoopSpan final : public Span void UpdateName(nostd::string_view /*name*/) noexcept override {} - void End() noexcept override {} + void End(const EndSpanOptions &options = {}) noexcept override {} bool IsRecording() const noexcept override { return false; } diff --git a/api/include/opentelemetry/trace/span.h b/api/include/opentelemetry/trace/span.h index 7d323b7207..f7b0aebd94 100644 --- a/api/include/opentelemetry/trace/span.h +++ b/api/include/opentelemetry/trace/span.h @@ -44,6 +44,11 @@ struct StartSpanOptions SpanKind kind = SpanKind::kInternal; }; +struct EndSpanOptions +{ + core::SteadyTimestamp end_steady_time; +}; + class Tracer; /** @@ -132,10 +137,7 @@ class Span // Mark the end of the Span. Only the timing of the first End call for a given Span will // be recorded, and implementations are free to ignore all further calls. - virtual void End() noexcept = 0; - - // TODO - // virtual void End(EndSpanOptions&& opts) noexcept = 0; + virtual void End(const EndSpanOptions &options = {}) noexcept = 0; // TODO // SpanContext context() const noexcept = 0; diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 7d5453f66d..dcb04ccf4e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(plugin) +add_subdirectory(simple) diff --git a/examples/plugin/plugin/tracer.cc b/examples/plugin/plugin/tracer.cc index 6cf63af118..18ab36a03b 100644 --- a/examples/plugin/plugin/tracer.cc +++ b/examples/plugin/plugin/tracer.cc @@ -38,7 +38,7 @@ class Span final : public trace::Span void UpdateName(nostd::string_view /*name*/) noexcept override {} - void End() noexcept override {} + void End(const trace::EndSpanOptions &options) noexcept override {} bool IsRecording() const noexcept override { return true; } diff --git a/examples/simple/BUILD b/examples/simple/BUILD new file mode 100644 index 0000000000..34583e2eac --- /dev/null +++ b/examples/simple/BUILD @@ -0,0 +1,25 @@ +cc_library( + name = "foo_library", + srcs = [ + "foo_library/foo_library.cc", + ], + hdrs = [ + "foo_library/foo_library.h", + ], + deps = [ + "//api", + ], +) + +cc_binary( + name = "example_simple", + srcs = [ + "main.cc", + "stdout_exporter.h", + ], + deps = [ + ":foo_library", + "//api", + "//sdk/src/trace", + ], +) diff --git a/examples/simple/CMakeLists.txt b/examples/simple/CMakeLists.txt new file mode 100644 index 0000000000..4b0ab35f74 --- /dev/null +++ b/examples/simple/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(foo_library foo_library/foo_library.cc) +target_link_libraries(foo_library ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) + +add_executable(example_simple main.cc) +target_link_libraries(example_simple ${CMAKE_THREAD_LIBS_INIT} foo_library + opentelemetry_trace) diff --git a/examples/simple/foo_library/foo_library.cc b/examples/simple/foo_library/foo_library.cc new file mode 100644 index 0000000000..0990b85ced --- /dev/null +++ b/examples/simple/foo_library/foo_library.cc @@ -0,0 +1,33 @@ +#include "opentelemetry/trace/provider.h" + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; + +namespace +{ +nostd::shared_ptr get_tracer() +{ + auto provider = trace::Provider::GetTracerProvider(); + return provider->GetTracer("foo_library"); +} + +void f1() +{ + auto span = get_tracer()->StartSpan("f1"); +} + +void f2() +{ + auto span = get_tracer()->StartSpan("f2"); + + f1(); + f1(); +} +} // namespace + +void foo_library() +{ + auto span = get_tracer()->StartSpan("library"); + + f2(); +} diff --git a/examples/simple/foo_library/foo_library.h b/examples/simple/foo_library/foo_library.h new file mode 100644 index 0000000000..7ac75c0e50 --- /dev/null +++ b/examples/simple/foo_library/foo_library.h @@ -0,0 +1,3 @@ +#pragma once + +void foo_library(); diff --git a/examples/simple/main.cc b/examples/simple/main.cc new file mode 100644 index 0000000000..af03d2e6db --- /dev/null +++ b/examples/simple/main.cc @@ -0,0 +1,29 @@ +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" + +// Using an exporter that simply dumps span data to stdout. +#include "stdout_exporter.h" + +#include "foo_library/foo_library.h" + +namespace +{ +void initTracer() +{ + auto exporter = std::unique_ptr(new StdoutExporter); + auto processor = std::shared_ptr( + new sdktrace::SimpleSpanProcessor(std::move(exporter))); + auto provider = nostd::shared_ptr(new sdktrace::TracerProvider(processor)); + trace::Provider::SetTracerProvider(provider); +} +} // namespace + +int main() +{ + // Removing this line will leave OT initialized with the default noop + // tracer, thus being effectively deactivated. + initTracer(); + + foo_library(); +} diff --git a/examples/simple/stdout_exporter.h b/examples/simple/stdout_exporter.h new file mode 100644 index 0000000000..6a58c5b8d6 --- /dev/null +++ b/examples/simple/stdout_exporter.h @@ -0,0 +1,52 @@ +#pragma once + +#include "opentelemetry/sdk/trace/exporter.h" +#include "opentelemetry/sdk/trace/span_data.h" + +#include + +namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace sdktrace = opentelemetry::sdk::trace; + +class StdoutExporter final : public sdktrace::SpanExporter +{ + std::unique_ptr MakeRecordable() noexcept + { + return std::unique_ptr(new sdktrace::SpanData); + } + + sdktrace::ExportResult Export( + const nostd::span> &spans) noexcept + { + for (auto &recordable : spans) + { + auto span = std::unique_ptr( + static_cast(recordable.release())); + + if (span != nullptr) + { + char trace_id[32] = {0}; + char span_id[16] = {0}; + char parent_span_id[16] = {0}; + + span->GetTraceId().ToLowerBase16(trace_id); + span->GetSpanId().ToLowerBase16(span_id); + span->GetParentSpanId().ToLowerBase16(parent_span_id); + + std::cout << "{" + << "\n name : " << span->GetName() + << "\n trace_id : " << std::string(trace_id, 32) + << "\n span_id : " << std::string(span_id, 16) + << "\n parent_span_id: " << std::string(parent_span_id, 16) + << "\n start : " << span->GetStartTime().time_since_epoch().count() + << "\n duration : " << span->GetDuration().count() << "\n}" + << "\n"; + } + } + + return sdktrace::ExportResult::kSuccess; + } + + void Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept {} +}; diff --git a/sdk/include/opentelemetry/sdk/trace/exporter.h b/sdk/include/opentelemetry/sdk/trace/exporter.h index d517c572b2..ec5473edb8 100644 --- a/sdk/include/opentelemetry/sdk/trace/exporter.h +++ b/sdk/include/opentelemetry/sdk/trace/exporter.h @@ -48,7 +48,8 @@ class SpanExporter * @param spans a span of unique pointers to span recordables */ virtual ExportResult Export( - nostd::span> &spans) noexcept = 0; + const nostd::span> + &spans) noexcept = 0; /** * Shut down the exporter. diff --git a/sdk/src/trace/simple_processor.h b/sdk/include/opentelemetry/sdk/trace/simple_processor.h similarity index 100% rename from sdk/src/trace/simple_processor.h rename to sdk/include/opentelemetry/sdk/trace/simple_processor.h diff --git a/sdk/include/opentelemetry/sdk/trace/tracer_provider.h b/sdk/include/opentelemetry/sdk/trace/tracer_provider.h index 322d2fcb59..d78fed02fc 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer_provider.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer_provider.h @@ -43,7 +43,7 @@ class TracerProvider final : public opentelemetry::trace::TracerProvider private: opentelemetry::sdk::AtomicSharedPtr processor_; - opentelemetry::nostd::shared_ptr tracer_; + std::shared_ptr tracer_; }; } // namespace trace } // namespace sdk diff --git a/sdk/src/trace/.tracer.cc.swp b/sdk/src/trace/.tracer.cc.swp new file mode 100644 index 0000000000000000000000000000000000000000..6bb638cf102cbd590d4f77c2a27f76904ae8110b GIT binary patch literal 12288 zcmeI2&2Q937>6gl^#h8^jYBmAm3ph)7z(W-Cq&|76GiHVlmx1Zg5}t=tlRaBJ2OsF ztyYzKs?-YgR#iRqfW!syM{qAHaDXd7<}rfIDUCpdP4@tz&HbiZ8xU( zuw$PdJ>r@knmow&e{gwccUuvv)Ch{QrOJ_y4{38M_Pq z1e@R+a01MN55YdL7d+d`*i+yGa>uizIj56%D&90nhOCwmyX1O5QNgP%bI)WHGp z;629fgX`cYa2Z?zp8yYh3?5;w55Yg+HuxL-2CjlW=m7z~1TL>xKo=Px17v^+EOMOG9UpUE=~&En3)A_}fwi!OmKe?0BnS$beqV?%w|chBCyeqm2v+h)&h?PG z?9VXvHs>P;e1o8DI%u|-^!l}#ac#V{qFt*)m5bS!TM>2<4qhC!^yb3W89MB0gM|o! zSY?@#L2xdTiOPatK}ew^D+b?B745dr<%lx~;6zWuGiGpc`V!LN*O57t?AazX9rb-&9;yfy>DwE_V zI10fHh4nUAW>*cBT^niZ20J_G$PZT$cGQ6DSS^vkv21xITu(9MazHkI?Y4_=Wos;N zP*&CIKbMQE+R{dqxhn`a#pSJ}=e9#G2)q5%t5xZZ7VnPm#wsnm?FT58UE2e-Fbp?l z3d1nN-O^*jZCXmk0K+G4e-GTK%ZTUDdkJ6gzOzwJJ wj^Mj09(^}brv5rk$D<@()x;f;uf~e3%F;L-ns@znj5`|JbsWs1{M4@Tzt=MKSpWb4 literal 0 HcmV?d00001 diff --git a/sdk/src/trace/span.cc b/sdk/src/trace/span.cc index 7b4937bb86..fbe2923dcf 100644 --- a/sdk/src/trace/span.cc +++ b/sdk/src/trace/span.cc @@ -7,11 +7,45 @@ namespace sdk { namespace trace { + +using opentelemetry::core::SteadyTimestamp; +using opentelemetry::core::SystemTimestamp; + +namespace +{ +SystemTimestamp NowOrGiven(const SystemTimestamp &system) +{ + if (system == SystemTimestamp()) + { + return SystemTimestamp(std::chrono::system_clock::now()); + } + else + { + return system; + } +} + +SteadyTimestamp NowOrGiven(const SteadyTimestamp &steady) +{ + if (steady == SteadyTimestamp()) + { + return SteadyTimestamp(std::chrono::steady_clock::now()); + } + else + { + return steady; + } +} +} // namespace + Span::Span(std::shared_ptr &&tracer, std::shared_ptr processor, nostd::string_view name, const trace_api::StartSpanOptions &options) noexcept - : tracer_{std::move(tracer)}, processor_{processor}, recordable_{processor_->MakeRecordable()} + : tracer_{std::move(tracer)}, + processor_{processor}, + recordable_{processor_->MakeRecordable()}, + start_steady_time{options.start_steady_time} { (void)options; if (recordable_ == nullptr) @@ -20,6 +54,9 @@ Span::Span(std::shared_ptr &&tracer, } processor_->OnStart(*recordable_); recordable_->SetName(name); + + recordable_->SetStartTime(NowOrGiven(options.start_system_time)); + start_steady_time = NowOrGiven(options.start_steady_time); } Span::~Span() @@ -67,13 +104,17 @@ void Span::UpdateName(nostd::string_view name) noexcept recordable_->SetName(name); } -void Span::End() noexcept +void Span::End(const trace_api::EndSpanOptions &options) noexcept { std::lock_guard lock_guard{mu_}; if (recordable_ == nullptr) { return; } + + recordable_->SetDuration( + std::chrono::steady_clock::time_point(NowOrGiven(options.end_steady_time)) - + std::chrono::steady_clock::time_point(start_steady_time)); processor_->OnEnd(std::move(recordable_)); recordable_.reset(); } diff --git a/sdk/src/trace/span.h b/sdk/src/trace/span.h index 3fd1bb4af7..e1a6f2084a 100644 --- a/sdk/src/trace/span.h +++ b/sdk/src/trace/span.h @@ -35,7 +35,7 @@ class Span final : public trace_api::Span void UpdateName(nostd::string_view name) noexcept override; - void End() noexcept override; + void End(const trace_api::EndSpanOptions &options = {}) noexcept override; bool IsRecording() const noexcept override; @@ -46,6 +46,7 @@ class Span final : public trace_api::Span std::shared_ptr processor_; mutable std::mutex mu_; std::unique_ptr recordable_; + opentelemetry::core::SteadyTimestamp start_steady_time; }; } // namespace trace } // namespace sdk diff --git a/sdk/src/trace/tracer_provider.cc b/sdk/src/trace/tracer_provider.cc index 18e3dc99f9..3268207510 100644 --- a/sdk/src/trace/tracer_provider.cc +++ b/sdk/src/trace/tracer_provider.cc @@ -13,7 +13,7 @@ opentelemetry::nostd::shared_ptr TracerProvider::G nostd::string_view library_name, nostd::string_view library_version) noexcept { - return tracer_; + return opentelemetry::nostd::shared_ptr(tracer_); } void TracerProvider::SetProcessor(std::shared_ptr processor) noexcept diff --git a/sdk/test/trace/simple_processor_test.cc b/sdk/test/trace/simple_processor_test.cc index ddeba25fe6..b4819aa0ae 100644 --- a/sdk/test/trace/simple_processor_test.cc +++ b/sdk/test/trace/simple_processor_test.cc @@ -1,4 +1,4 @@ -#include "src/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/simple_processor.h" #include "opentelemetry/nostd/span.h" #include "opentelemetry/sdk/trace/span_data.h" @@ -23,7 +23,7 @@ class MockSpanExporter final : public SpanExporter } ExportResult Export( - opentelemetry::nostd::span> &spans) noexcept override + const opentelemetry::nostd::span> &spans) noexcept override { for (auto &span : spans) { diff --git a/sdk/test/trace/tracer_provider_test.cc b/sdk/test/trace/tracer_provider_test.cc index 8168aeb6ba..90dbe7c747 100644 --- a/sdk/test/trace/tracer_provider_test.cc +++ b/sdk/test/trace/tracer_provider_test.cc @@ -1,6 +1,6 @@ #include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/sdk/trace/simple_processor.h" #include "opentelemetry/sdk/trace/tracer.h" -#include "src/trace/simple_processor.h" #include diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index 99a18ba99d..92167fe3b1 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -1,10 +1,12 @@ #include "opentelemetry/sdk/trace/tracer.h" +#include "opentelemetry/sdk/trace/simple_processor.h" #include "opentelemetry/sdk/trace/span_data.h" -#include "src/trace/simple_processor.h" #include using namespace opentelemetry::sdk::trace; +using opentelemetry::core::SteadyTimestamp; +using opentelemetry::core::SystemTimestamp; /** * A mock exporter that switches a flag once a valid recordable was received. @@ -12,7 +14,7 @@ using namespace opentelemetry::sdk::trace; class MockSpanExporter final : public SpanExporter { public: - MockSpanExporter(std::shared_ptr> spans_received) noexcept + MockSpanExporter(std::shared_ptr>> spans_received) noexcept : spans_received_(spans_received) {} @@ -22,14 +24,14 @@ class MockSpanExporter final : public SpanExporter } ExportResult Export( - opentelemetry::nostd::span> &recordables) noexcept override + const opentelemetry::nostd::span> &recordables) noexcept override { for (auto &recordable : recordables) { auto span = std::unique_ptr(static_cast(recordable.release())); if (span != nullptr) { - spans_received_->push_back(std::string(span->GetName())); + spans_received_->push_back(std::move(span)); } } @@ -40,15 +42,25 @@ class MockSpanExporter final : public SpanExporter {} private: - std::shared_ptr> spans_received_; + std::shared_ptr>> spans_received_; }; -TEST(Tracer, ToMockSpanExporter) +namespace +{ +std::shared_ptr initTracer( + std::shared_ptr>> &received) { - std::shared_ptr> spans_received(new std::vector); - std::unique_ptr exporter(new MockSpanExporter(spans_received)); + std::unique_ptr exporter(new MockSpanExporter(received)); std::shared_ptr processor(new SimpleSpanProcessor(std::move(exporter))); - std::shared_ptr tracer(new Tracer(processor)); + return std::shared_ptr(new Tracer(processor)); +} +} // namespace + +TEST(Tracer, ToMockSpanExporter) +{ + std::shared_ptr>> spans_received( + new std::vector>); + auto tracer = initTracer(spans_received); auto span_first = tracer->StartSpan("span 1"); auto span_second = tracer->StartSpan("span 2"); @@ -57,9 +69,46 @@ TEST(Tracer, ToMockSpanExporter) span_second->End(); ASSERT_EQ(1, spans_received->size()); - ASSERT_EQ("span 2", spans_received->at(0)); + ASSERT_EQ("span 2", spans_received->at(0)->GetName()); span_first->End(); ASSERT_EQ(2, spans_received->size()); - ASSERT_EQ("span 1", spans_received->at(1)); + ASSERT_EQ("span 1", spans_received->at(1)->GetName()); +} + +TEST(Tracer, StartSpan) +{ + std::shared_ptr>> spans_received( + new std::vector>); + auto tracer = initTracer(spans_received); + + tracer->StartSpan("span 1")->End(); + + ASSERT_EQ(1, spans_received->size()); + + auto &span_data = spans_received->at(0); + ASSERT_LT(std::chrono::nanoseconds(0), span_data->GetStartTime().time_since_epoch()); + ASSERT_LT(std::chrono::nanoseconds(0), span_data->GetDuration()); +} + +TEST(Tracer, StartSpanWithTime) +{ + std::shared_ptr>> spans_received( + new std::vector>); + auto tracer = initTracer(spans_received); + + opentelemetry::trace::StartSpanOptions start; + start.start_system_time = SystemTimestamp(std::chrono::nanoseconds(300)); + start.start_steady_time = SteadyTimestamp(std::chrono::nanoseconds(10)); + + opentelemetry::trace::EndSpanOptions end; + end.end_steady_time = SteadyTimestamp(std::chrono::nanoseconds(40)); + + tracer->StartSpan("span 1", start)->End(end); + + ASSERT_EQ(1, spans_received->size()); + + auto &span_data = spans_received->at(0); + ASSERT_EQ(std::chrono::nanoseconds(300), span_data->GetStartTime().time_since_epoch()); + ASSERT_EQ(std::chrono::nanoseconds(30), span_data->GetDuration()); } From 58736f0cb02f11aa316f75febd5aa6cc9afdc6d2 Mon Sep 17 00:00:00 2001 From: Johannes Tax Date: Mon, 8 Jun 2020 17:36:00 -0700 Subject: [PATCH 02/42] Set span start and end timestamps (#98) --- api/include/opentelemetry/core/timestamp.h | 10 +++++++++ api/include/opentelemetry/plugin/tracer.h | 2 +- api/include/opentelemetry/trace/noop.h | 2 +- api/include/opentelemetry/trace/span.h | 15 ++++++++++--- api/test/core/timestamp_test.cc | 26 ++++++++++++++++++++++ examples/plugin/plugin/tracer.cc | 4 ++-- sdk/src/trace/span.cc | 15 +++++++------ sdk/test/trace/tracer_test.cc | 2 +- 8 files changed, 61 insertions(+), 15 deletions(-) diff --git a/api/include/opentelemetry/core/timestamp.h b/api/include/opentelemetry/core/timestamp.h index 7ab7da6f5d..c76edd76f4 100644 --- a/api/include/opentelemetry/core/timestamp.h +++ b/api/include/opentelemetry/core/timestamp.h @@ -47,6 +47,11 @@ class SystemTimestamp return nanos_since_epoch_ == other.nanos_since_epoch_; } + bool operator!=(const SystemTimestamp &other) const noexcept + { + return nanos_since_epoch_ != other.nanos_since_epoch_; + } + private: int64_t nanos_since_epoch_; }; @@ -89,6 +94,11 @@ class SteadyTimestamp return nanos_since_epoch_ == other.nanos_since_epoch_; } + bool operator!=(const SteadyTimestamp &other) const noexcept + { + return nanos_since_epoch_ != other.nanos_since_epoch_; + } + private: int64_t nanos_since_epoch_; }; diff --git a/api/include/opentelemetry/plugin/tracer.h b/api/include/opentelemetry/plugin/tracer.h index 4f00be0c32..3d308e5826 100644 --- a/api/include/opentelemetry/plugin/tracer.h +++ b/api/include/opentelemetry/plugin/tracer.h @@ -39,7 +39,7 @@ class Span final : public trace::Span void UpdateName(nostd::string_view name) noexcept override { span_->UpdateName(name); } - void End(const trace::EndSpanOptions &options = {}) noexcept override { span_->End(); } + void End(const trace::EndSpanOptions &options = {}) noexcept override { span_->End(options); } bool IsRecording() const noexcept override { return span_->IsRecording(); } diff --git a/api/include/opentelemetry/trace/noop.h b/api/include/opentelemetry/trace/noop.h index 82b10b9a71..50dcc8b558 100644 --- a/api/include/opentelemetry/trace/noop.h +++ b/api/include/opentelemetry/trace/noop.h @@ -38,7 +38,7 @@ class NoopSpan final : public Span void UpdateName(nostd::string_view /*name*/) noexcept override {} - void End(const EndSpanOptions &options = {}) noexcept override {} + void End(const EndSpanOptions & /*options*/) noexcept override {} bool IsRecording() const noexcept override { return false; } diff --git a/api/include/opentelemetry/trace/span.h b/api/include/opentelemetry/trace/span.h index f7b0aebd94..21ed1aaaff 100644 --- a/api/include/opentelemetry/trace/span.h +++ b/api/include/opentelemetry/trace/span.h @@ -43,9 +43,13 @@ struct StartSpanOptions // Attributes SpanKind kind = SpanKind::kInternal; }; - +/** + * StartEndOptions provides options to set properties of a Span when it is + * ended. + */ struct EndSpanOptions { + // Optionally sets the end time of a Span. core::SteadyTimestamp end_steady_time; }; @@ -135,8 +139,13 @@ class Span // during creation. virtual void UpdateName(nostd::string_view name) noexcept = 0; - // Mark the end of the Span. Only the timing of the first End call for a given Span will - // be recorded, and implementations are free to ignore all further calls. + /** + * Mark the end of the Span. + * Only the timing of the first End call for a given Span will be recorded, + * and implementations are free to ignore all further calls. + * @param options can be used to manually define span properties like the end + * timestamp + */ virtual void End(const EndSpanOptions &options = {}) noexcept = 0; // TODO diff --git a/api/test/core/timestamp_test.cc b/api/test/core/timestamp_test.cc index 140092942a..7ea4484321 100644 --- a/api/test/core/timestamp_test.cc +++ b/api/test/core/timestamp_test.cc @@ -24,6 +24,19 @@ TEST(SystemTimestampTest, Construction) t2.time_since_epoch()); } +TEST(SystemTimestampTest, Comparison) +{ + SystemTimestamp t1; + SystemTimestamp t2; + SystemTimestamp t3{std::chrono::nanoseconds{2}}; + + EXPECT_EQ(t1, t1); + EXPECT_EQ(t1, t2); + EXPECT_EQ(t2, t1); + EXPECT_NE(t1, t3); + EXPECT_NE(t3, t1); +} + TEST(SteadyTimestampTest, Construction) { auto now_steady = std::chrono::steady_clock::now(); @@ -36,3 +49,16 @@ TEST(SteadyTimestampTest, Construction) EXPECT_EQ(std::chrono::duration_cast(now_steady.time_since_epoch()), t2.time_since_epoch()); } + +TEST(SteadyTimestampTest, Comparison) +{ + SteadyTimestamp t1; + SteadyTimestamp t2; + SteadyTimestamp t3{std::chrono::nanoseconds{2}}; + + EXPECT_EQ(t1, t1); + EXPECT_EQ(t1, t2); + EXPECT_EQ(t2, t1); + EXPECT_NE(t1, t3); + EXPECT_NE(t3, t1); +} diff --git a/examples/plugin/plugin/tracer.cc b/examples/plugin/plugin/tracer.cc index 18ab36a03b..c6e646d5d0 100644 --- a/examples/plugin/plugin/tracer.cc +++ b/examples/plugin/plugin/tracer.cc @@ -13,7 +13,7 @@ class Span final : public trace::Span public: Span(std::shared_ptr &&tracer, nostd::string_view name, - const trace::StartSpanOptions &options) noexcept + const trace::StartSpanOptions & /*options*/) noexcept : tracer_{std::move(tracer)}, name_{name} { std::cout << "StartSpan: " << name << "\n"; @@ -38,7 +38,7 @@ class Span final : public trace::Span void UpdateName(nostd::string_view /*name*/) noexcept override {} - void End(const trace::EndSpanOptions &options) noexcept override {} + void End(const trace::EndSpanOptions & /*options*/) noexcept override {} bool IsRecording() const noexcept override { return true; } diff --git a/sdk/src/trace/span.cc b/sdk/src/trace/span.cc index fbe2923dcf..a69e6673b0 100644 --- a/sdk/src/trace/span.cc +++ b/sdk/src/trace/span.cc @@ -13,7 +13,7 @@ using opentelemetry::core::SystemTimestamp; namespace { -SystemTimestamp NowOrGiven(const SystemTimestamp &system) +SystemTimestamp NowOr(const SystemTimestamp &system) { if (system == SystemTimestamp()) { @@ -25,7 +25,7 @@ SystemTimestamp NowOrGiven(const SystemTimestamp &system) } } -SteadyTimestamp NowOrGiven(const SteadyTimestamp &steady) +SteadyTimestamp NowOr(const SteadyTimestamp &steady) { if (steady == SteadyTimestamp()) { @@ -55,8 +55,8 @@ Span::Span(std::shared_ptr &&tracer, processor_->OnStart(*recordable_); recordable_->SetName(name); - recordable_->SetStartTime(NowOrGiven(options.start_system_time)); - start_steady_time = NowOrGiven(options.start_steady_time); + recordable_->SetStartTime(NowOr(options.start_system_time)); + start_steady_time = NowOr(options.start_steady_time); } Span::~Span() @@ -112,9 +112,10 @@ void Span::End(const trace_api::EndSpanOptions &options) noexcept return; } - recordable_->SetDuration( - std::chrono::steady_clock::time_point(NowOrGiven(options.end_steady_time)) - - std::chrono::steady_clock::time_point(start_steady_time)); + auto end_steady_time = NowOr(options.end_steady_time); + recordable_->SetDuration(std::chrono::steady_clock::time_point(end_steady_time) - + std::chrono::steady_clock::time_point(start_steady_time)); + processor_->OnEnd(std::move(recordable_)); recordable_.reset(); } diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index 92167fe3b1..e0bc2afde6 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -91,7 +91,7 @@ TEST(Tracer, StartSpan) ASSERT_LT(std::chrono::nanoseconds(0), span_data->GetDuration()); } -TEST(Tracer, StartSpanWithTime) +TEST(Tracer, StartSpanWithOptions) { std::shared_ptr>> spans_received( new std::vector>); From 9e5924c523c3cd36ecbc38be1c93b6bb162a84d3 Mon Sep 17 00:00:00 2001 From: Hudson Humphries Date: Tue, 9 Jun 2020 12:12:40 -0500 Subject: [PATCH 03/42] Add Useful Resources and Example Build Instructions to CONTRIBUTING.md (#97) --- CONTRIBUTING.md | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a3b18e248a..daacc9e7f0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,6 +20,33 @@ convention](https://google.github.io/styleguide/cppguide.html#Naming). Code is formatted automatically and enforced by CI. +### Build and Run Code Examples + +Note: these instructions apply to examples configured with Bazel, see example-specific documentation for other build automation tools. + +Install the latest bazel version by following the steps listed here + +Select an example of interest from the examples folder . Inside each example directory is a `BUILD` file containing instructions for Bazel. Find the binary name of your example by inspecting the contents of this `BUILD` file. + +Build the example from the root of the opentelemetry-cpp directory using Bazel. Replace `` with the identifier found in the previous step: + +```sh +bazel build //examples/: +``` + +Run the resulting executable to see telemetry from the application as it calls the instrumented library: + +```sh +bazel-bin/examples// +``` + +For instance, building and running the `simple` example can be done as follows: + +```sh +bazel build //examples/simple:example_simple +bazel-bin/examples/simple/example_simple +``` + ## Pull Requests ### How to Send Pull Requests @@ -72,3 +99,33 @@ A PR is considered to be **ready to merge** when: * Urgent fixes can take exceptions as long as it has been actively communicated. Any Approver / Maintainer can merge the PR once it is **ready to merge**. + +## Useful Resources + +Hi! If you’re looking at this document, these resources will provide you the knowledge to get started as a newcomer to the Open Telemetry project. They will help you understand the Open Telemetry Project, its components, and specifically the C++ repository. + +### Reading Resources + +* Medium [article](https://medium.com/opentelemetry/how-to-start-contributing-to-opentelemetry-b23991ad91f4) (October 2019) on how to start contributing to the Open Telemetry project. +* Medium [article](https://medium.com/opentelemetry/opentelemetry-beyond-getting-started-5ac43cd0fe26) (January 2020) describing the overarching goals and use cases for Open Telemetry. + +### Relevant Documentation + +* Open Telemetry [Specification](https://github.com/open-telemetry/opentelemetry-specification) + * The Open Telemetry Specification describes the requirements and expectations of for all Open Telemetry implementations. + +* Read through the [Open Telemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) GitHub repository + * This repository has a lot of good information surrounding the Open Telemetry ecosystem. At the top of the **[readme](https://github.com/open-telemetry/opentelemetry-collector/blob/master/README.md)**, there are multiple links that give newcomers a good idea of what the project is about and how to get involved in it. +* Read through the Open Telemetry Python documentation + * The [API](https://opentelemetry-python.readthedocs.io/en/stable/api/api.html) and [SDK](https://opentelemetry-python.readthedocs.io/en/stable/sdk/sdk.html) documentation provides a lot of information on what the classes and their functions are used for. Since there is currently minimal documentation for C++, use the Python repository’s extensive documentation to learn more about how the API and SDK work. + +### Code Examples + +* Follow the [simple trace example](https://github.com/open-telemetry/opentelemetry-cpp/pull/92) for an introduction to basic Open Telemetry functionality in C++. Currently the example can be found in [PR #94](https://github.com/open-telemetry/opentelemetry-cpp/pull/94) + +* Read through the [Java Quick-Start Guide](https://github.com/open-telemetry/opentelemetry-java/blob/master/QUICKSTART.md) + * This shows you how the classes and functions will interact in simple and easy to digest examples. +* Take a look at this [Java SDK example.](https://github.com/open-telemetry/opentelemetry-java/tree/master/examples/sdk-usage) This shows a good use case of the SDK using stdout exporter. +* Take a look at the [Java Jaeger example.](https://github.com/open-telemetry/opentelemetry-java/tree/master/examples/jaeger) This provides a brief introduction to the Jaeger exporter, its interface, and how to interact with the service. + +Please contribute! You’re welcome to add more information if you come across any helpful resources. \ No newline at end of file From b395e1afd24bcc22fc07d5e6433f008ce33fa599 Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Fri, 12 Jun 2020 10:15:39 -0700 Subject: [PATCH 04/42] Update maintainers/approvers (#107) --- .github/CODEOWNERS | 2 +- CONTRIBUTING.md | 93 +++++++++++++++++++++++++++++++--------------- README.md | 45 +++++++++++++++++++--- 3 files changed, 104 insertions(+), 36 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e872f965e0..36463d8b6a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,4 +2,4 @@ # This file controls who is tagged for review for any given pull request. # For anything not explicitly taken by someone else: -* @g-easy @jmacd @maxgolov @reyang @rnburn @tigrannajaryan +* @g-easy @jmacd @maxgolov @pyohannes @reyang @rnburn @tigrannajaryan diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index daacc9e7f0..e101e058d1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,19 +22,26 @@ Code is formatted automatically and enforced by CI. ### Build and Run Code Examples -Note: these instructions apply to examples configured with Bazel, see example-specific documentation for other build automation tools. +Note: these instructions apply to examples configured with Bazel, see +example-specific documentation for other build automation tools. -Install the latest bazel version by following the steps listed here +Install the latest bazel version by following the steps listed +[here](https://docs.bazel.build/versions/master/install.html). -Select an example of interest from the examples folder . Inside each example directory is a `BUILD` file containing instructions for Bazel. Find the binary name of your example by inspecting the contents of this `BUILD` file. +Select an example of interest from the [examples folder](https://github.com/open-telemetry/opentelemetry-cpp/tree/master/examples). +Inside each example directory is a `BUILD` file containing instructions for +Bazel. Find the binary name of your example by inspecting the contents of this +`BUILD` file. -Build the example from the root of the opentelemetry-cpp directory using Bazel. Replace `` with the identifier found in the previous step: +Build the example from the root of the opentelemetry-cpp directory using Bazel. +Replace `` with the identifier found in the previous step: ```sh bazel build //examples/: ``` -Run the resulting executable to see telemetry from the application as it calls the instrumented library: +Run the resulting executable to see telemetry from the application as it calls +the instrumented library: ```sh bazel-bin/examples// @@ -57,23 +64,23 @@ requests (PRs). To create a new PR, fork the project in GitHub and clone the upstream repo: ```sh -$ git clone https://github.com/open-telemetry/opentelemetry-cpp.git +git clone https://github.com/open-telemetry/opentelemetry-cpp.git ``` Add your fork as a remote: ```sh -$ git remote add fork https://github.com/YOUR_GITHUB_USERNAME/opentelemetry-cpp.git +git remote add fork https://github.com/YOUR_GITHUB_USERNAME/opentelemetry-cpp.git ``` Check out a new branch, make modifications and push the branch to your fork: ```sh -$ git checkout -b feature +git checkout -b feature # edit files -$ tools/format.sh -$ git commit -$ git push fork feature +tools/format.sh +git commit +git push fork feature ``` Open a pull request against the main `opentelemetry-cpp` repo. @@ -84,11 +91,13 @@ To run tests locally, please read the [CI instructions](ci/README.md). * If the PR is not ready for review, please put `[WIP]` in the title, tag it as `work-in-progress`, or mark it as [`draft`](https://github.blog/2019-02-14-introducing-draft-pull-requests/). -* Make sure [CLA](https://identity.linuxfoundation.org/projects/cncf) is signed and CI is clear. +* Make sure [CLA](https://identity.linuxfoundation.org/projects/cncf) is + signed and CI is clear. ### How to Get PRs Merged A PR is considered to be **ready to merge** when: + * It has received two approvals from [Approvers](https://github.com/open-telemetry/community/blob/master/community-membership.md#approver) / [Maintainers](https://github.com/open-telemetry/community/blob/master/community-membership.md#maintainer) (at different companies). @@ -102,30 +111,54 @@ Any Approver / Maintainer can merge the PR once it is **ready to merge**. ## Useful Resources -Hi! If you’re looking at this document, these resources will provide you the knowledge to get started as a newcomer to the Open Telemetry project. They will help you understand the Open Telemetry Project, its components, and specifically the C++ repository. +Hi! If you’re looking at this document, these resources will provide you the +knowledge to get started as a newcomer to the OpenTelemetry project. They will +help you understand the OpenTelemetry Project, its components, and +specifically the C++ repository. ### Reading Resources -* Medium [article](https://medium.com/opentelemetry/how-to-start-contributing-to-opentelemetry-b23991ad91f4) (October 2019) on how to start contributing to the Open Telemetry project. -* Medium [article](https://medium.com/opentelemetry/opentelemetry-beyond-getting-started-5ac43cd0fe26) (January 2020) describing the overarching goals and use cases for Open Telemetry. +* Medium [article](https://medium.com/opentelemetry/how-to-start-contributing-to-opentelemetry-b23991ad91f4) + (October 2019) on how to start contributing to the OpenTelemetry project. +* Medium [article](https://medium.com/opentelemetry/opentelemetry-beyond-getting-started-5ac43cd0fe26) + (January 2020) describing the overarching goals and use cases for OpenTelemetry. ### Relevant Documentation -* Open Telemetry [Specification](https://github.com/open-telemetry/opentelemetry-specification) - * The Open Telemetry Specification describes the requirements and expectations of for all Open Telemetry implementations. - -* Read through the [Open Telemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) GitHub repository - * This repository has a lot of good information surrounding the Open Telemetry ecosystem. At the top of the **[readme](https://github.com/open-telemetry/opentelemetry-collector/blob/master/README.md)**, there are multiple links that give newcomers a good idea of what the project is about and how to get involved in it. -* Read through the Open Telemetry Python documentation - * The [API](https://opentelemetry-python.readthedocs.io/en/stable/api/api.html) and [SDK](https://opentelemetry-python.readthedocs.io/en/stable/sdk/sdk.html) documentation provides a lot of information on what the classes and their functions are used for. Since there is currently minimal documentation for C++, use the Python repository’s extensive documentation to learn more about how the API and SDK work. +* [OpenTelemetry Specification](https://github.com/open-telemetry/opentelemetry-specification) + * The OpenTelemetry Specification describes the requirements and + expectations of for all OpenTelemetry implementations. + +* Read through the [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) + GitHub repository. + * This repository has a lot of good information surrounding the + OpenTelemetry ecosystem. At the top of the **[readme](https://github.com/open-telemetry/opentelemetry-collector/blob/master/README.md)**, + there are multiple links that give newcomers a good idea of what the + project is about and how to get involved in it. +* Read through the OpenTelemetry Python documentation + * The [API](https://opentelemetry-python.readthedocs.io/en/stable/api/api.html) + and [SDK](https://opentelemetry-python.readthedocs.io/en/stable/sdk/sdk.html) + documentation provides a lot of information on what the classes and their + functions are used for. Since there is currently minimal documentation for + C++, use the Python repository’s extensive documentation to learn more + about how the API and SDK work. ### Code Examples -* Follow the [simple trace example](https://github.com/open-telemetry/opentelemetry-cpp/pull/92) for an introduction to basic Open Telemetry functionality in C++. Currently the example can be found in [PR #94](https://github.com/open-telemetry/opentelemetry-cpp/pull/94) - -* Read through the [Java Quick-Start Guide](https://github.com/open-telemetry/opentelemetry-java/blob/master/QUICKSTART.md) - * This shows you how the classes and functions will interact in simple and easy to digest examples. -* Take a look at this [Java SDK example.](https://github.com/open-telemetry/opentelemetry-java/tree/master/examples/sdk-usage) This shows a good use case of the SDK using stdout exporter. -* Take a look at the [Java Jaeger example.](https://github.com/open-telemetry/opentelemetry-java/tree/master/examples/jaeger) This provides a brief introduction to the Jaeger exporter, its interface, and how to interact with the service. - -Please contribute! You’re welcome to add more information if you come across any helpful resources. \ No newline at end of file +* Follow the [simple trace example](https://github.com/open-telemetry/opentelemetry-cpp/pull/92) + for an introduction to basic OpenTelemetry functionality in C++. Currently + the example can be found in [PR #94](https://github.com/open-telemetry/opentelemetry-cpp/pull/94). + +* Read through the [Java Quick-Start + Guide](https://github.com/open-telemetry/opentelemetry-java/blob/master/QUICKSTART.md). + This shows you how the classes and functions will interact in simple and + easy to digest examples. +* Take a look at this [Java SDK + example](https://github.com/open-telemetry/opentelemetry-java/tree/master/examples/sdk-usage). + This shows a good use case of the SDK using stdout exporter. +* Take a look at the [Java Jaeger + example](https://github.com/open-telemetry/opentelemetry-java/tree/master/examples/jaeger). + This provides a brief introduction to the Jaeger exporter, its interface, + and how to interact with the service. + +Please contribute! You’re welcome to add more information if you come across any helpful resources. diff --git a/README.md b/README.md index 5fcc76b553..6371c3c579 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ -# OpenTelemetry C/C++ +# OpenTelemetry C++ + [![Gitter chat][gitter-image]][gitter-url] [gitter-image]: https://badges.gitter.im/open-telemetry/opentelemetry-cpp.svg [gitter-url]: https://gitter.im/open-telemetry/opentelemetry-cpp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge -The C/C++ [OpenTelemetry](https://opentelemetry.io/) client. +The C++ [OpenTelemetry](https://opentelemetry.io/) client. ## Installation @@ -18,10 +19,44 @@ TBD See [CONTRIBUTING.md](CONTRIBUTING.md) +We meet weekly on Mondays at 3:00PM PT. Check the [OpenTelemetry community calendar](https://calendar.google.com/calendar/embed?src=google.com_b79e3e90j7bbsa2n2p5an5lf60%40group.calendar.google.com) for specific dates. + +Meetings take place via [Zoom video conference](https://zoom.us/j/8203130519). + +Meeting notes are available as a public [Google doc](https://docs.google.com/document/d/1i1E4-_y4uJ083lCutKGDhkpi3n4_e774SBLi9hPLocw/edit?usp=sharing). For edit access, get in touch on [Gitter](https://gitter.im/open-telemetry/opentelemetry-cpp). + +Approvers ([@open-telemetry/cpp-approvers](https://github.com/orgs/open-telemetry/teams/cpp-approvers)): + +- [Max Golovanov](https://github.com/maxgolov), Microsoft +- [Johannes Tax](https://github.com/pyohannes), New Relic +- [Josh MacDonald](https://github.com/jmacd), Lightstep +- [Ryan Burn](https://github.com/rnburn), Lightstep +- [Tigran Najaryan](https://github.com/tigrannajaryan), Splunk + +*Find more about the approver role in [community repository](https://github.com/open-telemetry/community/blob/master/community-membership.md#approver).* + +Maintainers ([@open-telemetry/cpp-maintainers](https://github.com/orgs/open-telemetry/teams/cpp-maintainers)): + +- [Emil Mikulic](https://github.com/g-easy), Google +- [Reiley Yang](https://github.com/reyang), Microsoft + +*Find more about the maintainer role in [community repository](https://github.com/open-telemetry/community/blob/master/community-membership.md#maintainer).* + ## Release Schedule -OpenTelemetry C/C++ is under active development. +OpenTelemetry C++ is under active development. The library is not yet _generally available_, and releases aren't guaranteed to -conform to a specific version of the specification. Future releases will not -attempt to maintain backwards compatibility with current releases. +conform to a specific version of the specification. Future releases will not +attempt to maintain backwards compatibility with previous releases. Each alpha +and beta release includes significant changes to the API and SDK packages, +making them incompatible with each other. + +See the [release +notes](https://github.com/open-telemetry/opentelemetry-cpp/releases) +for existing releases. + +See the [project +milestones](https://github.com/open-telemetry/opentelemetry-cpp/milestones) +for details on upcoming releases. The dates and features described in issues +and milestones are estimates, and subject to change. From 422b7a4ac50af5fddbd06e9e402fad174f3501fa Mon Sep 17 00:00:00 2001 From: Brandon Kimberly Date: Mon, 15 Jun 2020 11:54:01 -0400 Subject: [PATCH 05/42] Migrate CI pipeline from CircleCI to GitHub Actions (#103) --- .github/workflows/ci.yml | 172 ++++++++++++++++++++++++++++ ci/do_ci.ps1 | 2 +- ci/do_ci.sh | 2 + ci/setup_windows_ci_environment.ps1 | 3 +- 4 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..0ddda0f986 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,172 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + cmake_test: + name: CMake test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: setup + run: | + sudo ./ci/setup_cmake.sh + sudo ./ci/setup_ci_environment.sh + - name: run tests + run: ./ci/do_ci.sh cmake.test + + plugin_test: + name: Plugin -> CMake + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: setup + run: | + sudo ./ci/setup_cmake.sh + sudo ./ci/setup_ci_environment.sh + - name: run tests + run: ./ci/do_ci.sh cmake.test_example_plugin + + gcc_48_test: + name: Legacy Bazel + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - name: setup + run: | + sudo ./ci/setup_ci_environment.sh + sudo ./ci/install_bazelisk.sh + sudo ./ci/install_gcc48.sh + - name: run tests + run: ./ci/do_ci.sh bazel.legacy.test + + bazel_test: + name: Bazel + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: setup + run: | + sudo ./ci/setup_cmake.sh + sudo ./ci/setup_ci_environment.sh + sudo ./ci/install_bazelisk.sh + - name: run tests + run: ./ci/do_ci.sh bazel.test + + bazel_noexcept: + name: Bazel noexcept + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: setup + run: | + sudo ./ci/setup_cmake.sh + sudo ./ci/setup_ci_environment.sh + sudo ./ci/install_bazelisk.sh + - name: run tests + run: ./ci/do_ci.sh bazel.noexcept + + bazel_asan: + name: Bazel asan config + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: setup + run: | + sudo ./ci/setup_cmake.sh + sudo ./ci/setup_ci_environment.sh + sudo ./ci/install_bazelisk.sh + - name: run tests + run: ./ci/do_ci.sh bazel.asan + + bazel_tsan: + name: Bazel tsan config + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: setup + run: | + sudo ./ci/setup_cmake.sh + sudo ./ci/setup_ci_environment.sh + sudo ./ci/install_bazelisk.sh + - name: run tests + run: ./ci/do_ci.sh bazel.tsan + + benchmark: + name: Benchmark + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: setup + run: | + sudo ./ci/setup_cmake.sh + sudo ./ci/setup_ci_environment.sh + sudo ./ci/install_bazelisk.sh + - name: run tests + run: | + env BENCHMARK_DIR=/benchmark + ./ci/do_ci.sh benchmark + - name: Upload benchmark results + uses: actions/upload-artifact@v2 + with: + name: benchmark_reports + path: /home/runner/benchmark + + format: + name: Format + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: setup + run: sudo ./ci/install_format_tools.sh + - name: run tests + run: ./ci/do_ci.sh format + + osx_test: + name: Bazel on MacOS + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - name: run tests + run: ./ci/do_ci.sh bazel.test + + windows: + name: CMake -> exporter proto + runs-on: windows-2019 + steps: + - uses: actions/checkout@v2 + - name: setup + run: | + ./ci/setup_windows_cmake.ps1 + ./ci/setup_windows_ci_environment.ps1 + ./ci/install_windows_protobuf.ps1 + - name: run cmake test + run: ./ci/do_ci.ps1 cmake.test + - name: run otprotocol test + run: ./ci/do_ci.ps1 cmake.exporter.otprotocol.test + + windows_bazel: + name: Bazel Windows + runs-on: windows-2019 + steps: + - uses: actions/checkout@v2 + - name: setup + run: ./ci/install_windows_bazelisk.ps1 + - name: run tests + run: ./ci/do_ci.ps1 bazel.build + + windows_plugin_test: + name: Plugin -> CMake Windows + runs-on: windows-2019 + steps: + - uses: actions/checkout@v2 + - name: setup + run: | + ./ci/setup_windows_cmake.ps1 + ./ci/setup_windows_ci_environment.ps1 + - name: run tests + run: ./ci/do_ci.ps1 cmake.test_example_plugin diff --git a/ci/do_ci.ps1 b/ci/do_ci.ps1 index 1056225ea2..367d76e080 100644 --- a/ci/do_ci.ps1 +++ b/ci/do_ci.ps1 @@ -22,7 +22,7 @@ $VCPKG_DIR="$SRC_DIR\vcpkg" switch ($action) { "bazel.build" { - bazel build $BAZEL_OPTIONS -- //... -//api/test/... -//sdk/test/... + bazel build $BAZEL_OPTIONS -- //... //api/test/... //sdk/test/... $exit = $LASTEXITCODE if ($exit -ne 0) { exit $exit diff --git a/ci/do_ci.sh b/ci/do_ci.sh index 6b3205843b..f80ca7d749 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -97,6 +97,8 @@ elif [[ "$1" == "benchmark" ]]; then exit 0 elif [[ "$1" == "format" ]]; then tools/format.sh + # normalize file endings according to .gitattributes + git add --renormalize . CHANGED="$(git ls-files --modified)" if [[ ! -z "$CHANGED" ]]; then echo "The following files have changes:" diff --git a/ci/setup_windows_ci_environment.ps1 b/ci/setup_windows_ci_environment.ps1 index a1b1b89d9c..a2134646ea 100755 --- a/ci/setup_windows_ci_environment.ps1 +++ b/ci/setup_windows_ci_environment.ps1 @@ -2,9 +2,10 @@ $ErrorActionPreference = "Stop" trap { $host.SetShouldExit(1) } git clone https://github.com/Microsoft/vcpkg.git -cd vcpkg +Push-Location -Path vcpkg $VCPKG_DIR=(Get-Item -Path ".\").FullName ./bootstrap-vcpkg.bat ./vcpkg integrate install ./vcpkg install benchmark:x64-windows ./vcpkg install gtest:x64-windows +Pop-Location From 668bb8b21ce0afd17348cda8b86eb9a6e2fc18fa Mon Sep 17 00:00:00 2001 From: Johannes Tax Date: Tue, 16 Jun 2020 12:42:30 -0700 Subject: [PATCH 06/42] Fix AtomicSharedPtr for C++20 (#114) --- .github/workflows/ci.yml | 12 ++++++++++ CMakeLists.txt | 4 +++- ci/README.md | 1 + ci/do_ci.sh | 10 ++++++++ ci/setup_cmake.sh | 2 +- .../sdk/common/atomic_shared_ptr.h | 24 +++---------------- sdk/test/common/random_test.cc | 2 +- 7 files changed, 31 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ddda0f986..036f062ef5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,18 @@ jobs: - name: run tests run: ./ci/do_ci.sh cmake.test + cmake_test_cxx20: + name: CMake C++20 test + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - name: setup + run: | + sudo ./ci/setup_ci_environment.sh + sudo ./ci/setup_cmake.sh + - name: run tests + run: ./ci/do_ci.sh cmake.c++20.test + plugin_test: name: Plugin -> CMake runs-on: ubuntu-latest diff --git a/CMakeLists.txt b/CMakeLists.txt index 264d58992d..c2ed2b6d80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,9 @@ cmake_policy(SET CMP0057 NEW) project(opentelemetry-cpp) -set(CMAKE_CXX_STANDARD 11) +if(NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 11) +endif() option(WITH_OTPROTOCOL "Whether to include the OpenTelemetry Protocol in the SDK" OFF) diff --git a/ci/README.md b/ci/README.md index f755d3f54a..5741684d9f 100644 --- a/ci/README.md +++ b/ci/README.md @@ -3,6 +3,7 @@ CI tests can be run on docker by invoking the script `./ci/run_docker.sh ./ci/do_ci.sh ` where the targets are: * `cmake.test`: build cmake targets and run tests. +* `cmake.c++20.test`: build cmake targets with the C++20 standard and run tests. * `cmake.test_example_plugin`: build and test an example OpenTelemetry plugin. * `cmake.exporter.otprotocol.test`: build and test the otprotocol exporter * `bazel.test`: build bazel targets and run tests. diff --git a/ci/do_ci.sh b/ci/do_ci.sh index f80ca7d749..cd41b0a6b4 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -20,6 +20,16 @@ if [[ "$1" == "cmake.test" ]]; then make make test exit 0 +elif [[ "$1" == "cmake.c++20.test" ]]; then + cd "${BUILD_DIR}" + rm -rf * + cmake -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_CXX_FLAGS="-Werror" \ + -DCMAKE_CXX_STANDARD=20 \ + "${SRC_DIR}" + make + make test + exit 0 elif [[ "$1" == "cmake.exporter.otprotocol.test" ]]; then cd "${BUILD_DIR}" rm -rf * diff --git a/ci/setup_cmake.sh b/ci/setup_cmake.sh index 1e22f39f81..0ab9be37fd 100755 --- a/ci/setup_cmake.sh +++ b/ci/setup_cmake.sh @@ -12,5 +12,5 @@ apt-get install --no-install-recommends --no-install-suggests -y \ pushd /usr/src/gtest cmake CMakeLists.txt make -cp *.a /usr/lib +cp *.a /usr/lib || cp lib/*.a /usr/lib popd diff --git a/sdk/include/opentelemetry/sdk/common/atomic_shared_ptr.h b/sdk/include/opentelemetry/sdk/common/atomic_shared_ptr.h index 968167aea8..f3630cce67 100644 --- a/sdk/include/opentelemetry/sdk/common/atomic_shared_ptr.h +++ b/sdk/include/opentelemetry/sdk/common/atomic_shared_ptr.h @@ -11,28 +11,10 @@ namespace sdk /** * A wrapper to provide atomic shared pointers. * - * This wrapper relies on std::atomic for C++20, a mutex for gcc 4.8, and - * specializations of std::atomic_store and std::atomic_load for all other - * instances. + * This wrapper relies on a mutex for gcc 4.8, and specializations of + * std::atomic_store and std::atomic_load for all other instances. */ -#if __cplusplus > 201703L -template -class AtomicSharedPtr -{ -public: - explicit AtomicSharedPtr(std::shared_ptr ptr) noexcept : ptr_{std::move(ptr)} {} - - void store(const std::shared_ptr &other) noexcept - { - ptr_.store(other, std::memory_order_release); - } - - std::shared_ptr load() const noexcept { return ptr_.load(std::memory_order_acquire); } - -private: - std::atomic> ptr_; -}; -#elif (__GNUC__ == 4 && (__GNUC_MINOR__ >= 8)) +#if (__GNUC__ == 4 && (__GNUC_MINOR__ >= 8)) template class AtomicSharedPtr { diff --git a/sdk/test/common/random_test.cc b/sdk/test/common/random_test.cc index b3768c5a79..850e289fff 100644 --- a/sdk/test/common/random_test.cc +++ b/sdk/test/common/random_test.cc @@ -20,7 +20,7 @@ TEST(RandomTest, GenerateRandomBuffer) EXPECT_FALSE(std::equal(std::begin(buf1), std::end(buf1), std::begin(buf2))); // Edge cases. - for (auto size : {1, 7, 8, 9, 16, 17}) + for (auto size : {7, 8, 9, 16, 17}) { std::vector buf1(size); std::vector buf2(size); From b472384807ff5c3b921813d56ddf6f915cc28404 Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Tue, 16 Jun 2020 12:43:57 -0700 Subject: [PATCH 07/42] Remove Josh from the approvers (#116) --- .github/CODEOWNERS | 2 +- README.md | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 36463d8b6a..9852bcdf5a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,4 +2,4 @@ # This file controls who is tagged for review for any given pull request. # For anything not explicitly taken by someone else: -* @g-easy @jmacd @maxgolov @pyohannes @reyang @rnburn @tigrannajaryan +* @open-telemetry/cpp-approvers diff --git a/README.md b/README.md index 6371c3c579..a53ef98f7c 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,6 @@ Approvers ([@open-telemetry/cpp-approvers](https://github.com/orgs/open-telemetr - [Max Golovanov](https://github.com/maxgolov), Microsoft - [Johannes Tax](https://github.com/pyohannes), New Relic -- [Josh MacDonald](https://github.com/jmacd), Lightstep - [Ryan Burn](https://github.com/rnburn), Lightstep - [Tigran Najaryan](https://github.com/tigrannajaryan), Splunk From 49eee20bfed224e4e2f85ac7bbae45de1ae5258e Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Tue, 16 Jun 2020 14:37:01 -0700 Subject: [PATCH 08/42] std::result_of removed in C++20 (#115) --- CMakeLists.txt | 7 +++++++ api/include/opentelemetry/nostd/function_ref.h | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index c2ed2b6d80..ee6dcbe380 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,13 @@ include(CTest) find_package(Threads) +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + # Options for Visual C++ compiler: + # /Zc:__cplusplus - report an updated value for recent C++ language standards. + # Without this option MSVC returns the value of __cplusplus="199711L" + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:__cplusplus") +endif() + if(WITH_PROTOBUF) set(protobuf_MODULE_COMPATIBLE ON) find_package(Protobuf CONFIG NAMES protobuf) diff --git a/api/include/opentelemetry/nostd/function_ref.h b/api/include/opentelemetry/nostd/function_ref.h index 33c94d00ab..de61c7040a 100644 --- a/api/include/opentelemetry/nostd/function_ref.h +++ b/api/include/opentelemetry/nostd/function_ref.h @@ -63,7 +63,13 @@ class function_ref typename std::enable_if::type>::value, int>::type = 0, typename std::enable_if< +#if (__cplusplus >= 201703L) + // std::result_of deprecated in C++17, removed in C++20 + std::is_convertible::type, R>::value, +#else + // std::result_of since C++11 std::is_convertible::type, R>::value, +#endif int>::type = 0> function_ref(F &&f) { From 9048d452bbe1e45d14b600bf37852b125914428c Mon Sep 17 00:00:00 2001 From: Tigran Najaryan <4194920+tigrannajaryan@users.noreply.github.com> Date: Thu, 18 Jun 2020 12:04:59 -0400 Subject: [PATCH 09/42] Remove Tigran Najaryan from Approvers list (#120) I haven't been able to contribute to this SIG. Please remove me. Will be glad to return if I get a chance to work on C++ in the future. :-) --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index a53ef98f7c..b9cee55c84 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,6 @@ Approvers ([@open-telemetry/cpp-approvers](https://github.com/orgs/open-telemetr - [Max Golovanov](https://github.com/maxgolov), Microsoft - [Johannes Tax](https://github.com/pyohannes), New Relic - [Ryan Burn](https://github.com/rnburn), Lightstep -- [Tigran Najaryan](https://github.com/tigrannajaryan), Splunk *Find more about the approver role in [community repository](https://github.com/open-telemetry/community/blob/master/community-membership.md#approver).* From c86794e41b96337ef999dd513d380c3970737f2e Mon Sep 17 00:00:00 2001 From: Ankit Bhargava Date: Fri, 19 Jun 2020 13:14:59 -0400 Subject: [PATCH 10/42] Enhancements to PR #86 Add minimal tracer example (#94) --- CMakeLists.txt | 6 +++--- examples/simple/README.md | 10 ++++++++++ examples/simple/main.cc | 4 ++-- 3 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 examples/simple/README.md diff --git a/CMakeLists.txt b/CMakeLists.txt index ee6dcbe380..9fbfc1c059 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,9 +23,9 @@ include(CTest) find_package(Threads) if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - # Options for Visual C++ compiler: - # /Zc:__cplusplus - report an updated value for recent C++ language standards. - # Without this option MSVC returns the value of __cplusplus="199711L" + # Options for Visual C++ compiler: /Zc:__cplusplus - report an updated value + # for recent C++ language standards. Without this option MSVC returns the + # value of __cplusplus="199711L" set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:__cplusplus") endif() diff --git a/examples/simple/README.md b/examples/simple/README.md new file mode 100644 index 0000000000..d59a1423cd --- /dev/null +++ b/examples/simple/README.md @@ -0,0 +1,10 @@ + +# Simple Trace Example + +In this example, the application in `main.cc` initializes and registers a tracer +provider from the [OpenTelemetry SDK](https://github.com/open-telemetry/opentelemetry-cpp). +The application then calls a `foo_library` which has been instrumented using +the [OpenTelemetry API](https://github.com/open-telemetry/opentelemetry-cpp/tree/master/api). +Resulting telemetry is directed to stdout through a custom exporter. + +See [CONTRIBUTING.md](../../CONTRIBUTING.md) for instructions on building and running the example. \ No newline at end of file diff --git a/examples/simple/main.cc b/examples/simple/main.cc index af03d2e6db..756c764e89 100644 --- a/examples/simple/main.cc +++ b/examples/simple/main.cc @@ -15,14 +15,14 @@ void initTracer() auto processor = std::shared_ptr( new sdktrace::SimpleSpanProcessor(std::move(exporter))); auto provider = nostd::shared_ptr(new sdktrace::TracerProvider(processor)); + // Set the global trace provider trace::Provider::SetTracerProvider(provider); } } // namespace int main() { - // Removing this line will leave OT initialized with the default noop - // tracer, thus being effectively deactivated. + // Removing this line will leave the default noop TracerProvider in place. initTracer(); foo_library(); From 1a54e5d65ccbbf4aa19c6ddc88635a32f4c807d8 Mon Sep 17 00:00:00 2001 From: Brandon Kimberly Date: Fri, 19 Jun 2020 19:49:06 -0400 Subject: [PATCH 11/42] Add code coverage using codecov.io (#121) --- .github/.codecov.yaml | 28 ++++++++++++++++++++++++++++ .github/workflows/ci.yml | 16 ++++++++++++++++ ci/README.md | 1 + ci/do_ci.sh | 10 ++++++++++ ci/setup_ci_environment.sh | 1 + 5 files changed, 56 insertions(+) create mode 100644 .github/.codecov.yaml diff --git a/.github/.codecov.yaml b/.github/.codecov.yaml new file mode 100644 index 0000000000..354ed22dd4 --- /dev/null +++ b/.github/.codecov.yaml @@ -0,0 +1,28 @@ +codecov: + require_ci_to_pass: yes + max_report_age: off + +coverage: + precision: 2 + round: down + range: "80...100" + +parsers: + gcov: + branch_detection: + conditional: yes + loop: yes + method: no + macro: no + +comment: + layout: "reach,diff,flags,tree" + behavior: default + require_changes: no + +# Relative file path fixing. +# CI file paths must match Git file paths. +# This fix removes the "/home/runner/" prefix +# to coverage report file paths. +fixes: + - "/home/runner/::" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 036f062ef5..a5d36c4a61 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -182,3 +182,19 @@ jobs: ./ci/setup_windows_ci_environment.ps1 - name: run tests run: ./ci/do_ci.ps1 cmake.test_example_plugin + + code_coverage: + name: Code coverage + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: setup + run: | + sudo ./ci/setup_cmake.sh + sudo ./ci/setup_ci_environment.sh + - name: run tests and generate report + run: ./ci/do_ci.sh code.coverage + - name: upload report + uses: codecov/codecov-action@v1 + with: + file: /home/runner/build/coverage.info diff --git a/ci/README.md b/ci/README.md index 5741684d9f..6695c8b134 100644 --- a/ci/README.md +++ b/ci/README.md @@ -13,6 +13,7 @@ CI tests can be run on docker by invoking the script `./ci/run_docker.sh ./ci/do * `bazel.tsan`: build bazel targets and run tests with ThreadSanitizer. * `benchmark`: run all benchmarks. * `format`: use `tools/format.sh` to enforce text formatting. +* `code.coverage`: build cmake targets and run tests. Then upload coverage report to [codecov.io](https://codecov.io/). Additionally, `./ci/run_docker.sh` can be invoked with no arguments to get a docker shell where tests can be run manually. diff --git a/ci/do_ci.sh b/ci/do_ci.sh index cd41b0a6b4..b6d23f763f 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -116,6 +116,16 @@ elif [[ "$1" == "format" ]]; then exit 1 fi exit 0 +elif [[ "$1" == "code.coverage" ]]; then + cd "${BUILD_DIR}" + rm -rf * + cmake -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_CXX_FLAGS="-Werror --coverage" \ + "${SRC_DIR}" + make + make test + lcov --directory $PWD --capture --output-file coverage.info + exit 0 fi echo "Invalid do_ci.sh target, see ci/README.md for valid targets." diff --git a/ci/setup_ci_environment.sh b/ci/setup_ci_environment.sh index 50c7b373e9..9d7df6a1d5 100755 --- a/ci/setup_ci_environment.sh +++ b/ci/setup_ci_environment.sh @@ -7,3 +7,4 @@ apt-get install --no-install-recommends --no-install-suggests -y \ ca-certificates \ wget \ git +apt-get install -y lcov From 9b624b9bbba6761a891b20bc305a9c92d995812d Mon Sep 17 00:00:00 2001 From: Johannes Tax Date: Tue, 23 Jun 2020 09:40:23 -0700 Subject: [PATCH 12/42] Support for attributes on spans (#117) --- api/include/opentelemetry/plugin/factory.h | 9 +++-- api/include/opentelemetry/plugin/tracer.h | 8 +++- api/include/opentelemetry/trace/noop.h | 5 +++ api/include/opentelemetry/trace/span.h | 9 ++--- api/include/opentelemetry/trace/tracer.h | 31 ++++++++++++++++ examples/plugin/plugin/tracer.cc | 20 +++++++--- examples/plugin/plugin/tracer.h | 3 +- .../opentelemetry/sdk/trace/recordable.h | 9 +++++ .../opentelemetry/sdk/trace/span_data.h | 16 ++++++++ sdk/include/opentelemetry/sdk/trace/tracer.h | 1 + sdk/src/trace/span.cc | 13 +++++++ sdk/src/trace/span.h | 3 ++ sdk/src/trace/tracer.cc | 5 ++- sdk/test/trace/span_data_test.cc | 4 ++ sdk/test/trace/tracer_test.cc | 37 ++++++++++++++++--- 15 files changed, 148 insertions(+), 25 deletions(-) diff --git a/api/include/opentelemetry/plugin/factory.h b/api/include/opentelemetry/plugin/factory.h index dd849335e7..abec73867a 100644 --- a/api/include/opentelemetry/plugin/factory.h +++ b/api/include/opentelemetry/plugin/factory.h @@ -36,8 +36,9 @@ class Factory final * @param error_message on failure this will contain an error message. * @return a Tracer on success or nullptr on failure. */ - std::shared_ptr MakeTracer(nostd::string_view tracer_config, - std::string &error_message) const noexcept + std::shared_ptr MakeTracer(nostd::string_view tracer_config, + std::string &error_message) const + noexcept { nostd::unique_ptr plugin_error_message; auto tracer_handle = factory_impl_->MakeTracerHandle(tracer_config, plugin_error_message); @@ -46,8 +47,8 @@ class Factory final detail::CopyErrorMessage(plugin_error_message.get(), error_message); return nullptr; } - return std::shared_ptr{new (std::nothrow) - Tracer{library_handle_, std::move(tracer_handle)}}; + return std::shared_ptr{ + new (std::nothrow) Tracer{library_handle_, std::move(tracer_handle)}}; } private: diff --git a/api/include/opentelemetry/plugin/tracer.h b/api/include/opentelemetry/plugin/tracer.h index 3d308e5826..9970e5a533 100644 --- a/api/include/opentelemetry/plugin/tracer.h +++ b/api/include/opentelemetry/plugin/tracer.h @@ -18,6 +18,11 @@ class Span final : public trace::Span {} // trace::Span + void SetAttribute(nostd::string_view name, const common::AttributeValue &&value) noexcept override + { + span_->SetAttribute(name, std::move(value)); + } + void AddEvent(nostd::string_view name) noexcept override { span_->AddEvent(name); } void AddEvent(nostd::string_view name, core::SystemTimestamp timestamp) noexcept override @@ -61,9 +66,10 @@ class Tracer final : public trace::Tracer, public std::enable_shared_from_this StartSpan( nostd::string_view name, + const trace::KeyValueIterable &attributes, const trace::StartSpanOptions &options = {}) noexcept override { - auto span = tracer_handle_->tracer().StartSpan(name, options); + auto span = tracer_handle_->tracer().StartSpan(name, attributes, options); if (span == nullptr) { return nullptr; diff --git a/api/include/opentelemetry/trace/noop.h b/api/include/opentelemetry/trace/noop.h index 50dcc8b558..fbb0e0cb68 100644 --- a/api/include/opentelemetry/trace/noop.h +++ b/api/include/opentelemetry/trace/noop.h @@ -24,6 +24,10 @@ class NoopSpan final : public Span public: explicit NoopSpan(const std::shared_ptr &tracer) noexcept : tracer_{tracer} {} + void SetAttribute(nostd::string_view /*key*/, + const common::AttributeValue && /*value*/) noexcept override + {} + void AddEvent(nostd::string_view /*name*/) noexcept override {} void AddEvent(nostd::string_view /*name*/, core::SystemTimestamp /*timestamp*/) noexcept override @@ -56,6 +60,7 @@ class NoopTracer final : public Tracer, public std::enable_shared_from_this StartSpan(nostd::string_view /*name*/, + const KeyValueIterable & /*attributes*/, const StartSpanOptions & /*options*/) noexcept override { return nostd::unique_ptr{new (std::nothrow) NoopSpan{this->shared_from_this()}}; diff --git a/api/include/opentelemetry/trace/span.h b/api/include/opentelemetry/trace/span.h index 21ed1aaaff..77265387e6 100644 --- a/api/include/opentelemetry/trace/span.h +++ b/api/include/opentelemetry/trace/span.h @@ -2,6 +2,7 @@ #include +#include "opentelemetry/common/attribute_value.h" #include "opentelemetry/core/timestamp.h" #include "opentelemetry/nostd/span.h" #include "opentelemetry/nostd/string_view.h" @@ -40,7 +41,6 @@ struct StartSpanOptions // Span(Context?) parent; // SpanContext remote_parent; // Links - // Attributes SpanKind kind = SpanKind::kInternal; }; /** @@ -74,13 +74,10 @@ class Span Span &operator=(const Span &) = delete; Span &operator=(Span &&) = delete; - // TODO // Sets an attribute on the Span. If the Span previously contained a mapping for // the key, the old value is replaced. - // - // If an empty string is used as the value, the attribute will be silently - // dropped. Note: this behavior could change in the future. - // virtual void SetAttribute(nostd::string_view key, AttributeValue&& value) = 0; + virtual void SetAttribute(nostd::string_view key, + const common::AttributeValue &&value) noexcept = 0; // Adds an event to the Span. virtual void AddEvent(nostd::string_view name) noexcept = 0; diff --git a/api/include/opentelemetry/trace/tracer.h b/api/include/opentelemetry/trace/tracer.h index 29aa288123..825ff39fb1 100644 --- a/api/include/opentelemetry/trace/tracer.h +++ b/api/include/opentelemetry/trace/tracer.h @@ -22,10 +22,41 @@ class Tracer virtual ~Tracer() = default; /** * Starts a span. + * + * Optionally sets attributes at Span creation from the given key/value pairs. + * + * Attributes will be processed in order, previous attributes with the same + * key will be overwritten. */ virtual nostd::unique_ptr StartSpan(nostd::string_view name, + const KeyValueIterable &attributes, const StartSpanOptions &options = {}) noexcept = 0; + nostd::unique_ptr StartSpan(nostd::string_view name, + const StartSpanOptions &options = {}) noexcept + { + return this->StartSpan(name, {}, options); + } + + template ::value> * = nullptr> + nostd::unique_ptr StartSpan(nostd::string_view name, + const T &attributes, + const StartSpanOptions &options = {}) noexcept + { + return this->StartSpan(name, KeyValueIterableView(attributes), options); + } + + nostd::unique_ptr StartSpan( + nostd::string_view name, + std::initializer_list> attributes, + const StartSpanOptions &options = {}) noexcept + { + return this->StartSpan(name, + nostd::span>{ + attributes.begin(), attributes.end()}, + options); + } + /** * Force any buffered spans to flush. * @param timeout to complete the flush diff --git a/examples/plugin/plugin/tracer.cc b/examples/plugin/plugin/tracer.cc index c6e646d5d0..3aa68e8b15 100644 --- a/examples/plugin/plugin/tracer.cc +++ b/examples/plugin/plugin/tracer.cc @@ -2,9 +2,10 @@ #include -namespace nostd = opentelemetry::nostd; -namespace core = opentelemetry::core; -namespace trace = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace common = opentelemetry::common; +namespace core = opentelemetry::core; +namespace trace = opentelemetry::trace; namespace { @@ -13,6 +14,7 @@ class Span final : public trace::Span public: Span(std::shared_ptr &&tracer, nostd::string_view name, + const opentelemetry::trace::KeyValueIterable & /*attributes*/, const trace::StartSpanOptions & /*options*/) noexcept : tracer_{std::move(tracer)}, name_{name} { @@ -22,6 +24,10 @@ class Span final : public trace::Span ~Span() { std::cout << "~Span\n"; } // opentelemetry::trace::Span + void SetAttribute(nostd::string_view /*name*/, + const common::AttributeValue && /*value*/) noexcept override + {} + void AddEvent(nostd::string_view /*name*/) noexcept override {} void AddEvent(nostd::string_view /*name*/, core::SystemTimestamp /*timestamp*/) noexcept override @@ -52,9 +58,11 @@ class Span final : public trace::Span Tracer::Tracer(nostd::string_view /*output*/) {} -nostd::unique_ptr Tracer::StartSpan(nostd::string_view name, - const trace::StartSpanOptions &options) noexcept +nostd::unique_ptr Tracer::StartSpan( + nostd::string_view name, + const opentelemetry::trace::KeyValueIterable &attributes, + const trace::StartSpanOptions &options) noexcept { return nostd::unique_ptr{ - new (std::nothrow) Span{this->shared_from_this(), name, options}}; + new (std::nothrow) Span{this->shared_from_this(), name, attributes, options}}; } diff --git a/examples/plugin/plugin/tracer.h b/examples/plugin/plugin/tracer.h index 4d653f32e9..ad1b98633d 100644 --- a/examples/plugin/plugin/tracer.h +++ b/examples/plugin/plugin/tracer.h @@ -13,7 +13,8 @@ class Tracer final : public opentelemetry::trace::Tracer, // opentelemetry::trace::Tracer opentelemetry::nostd::unique_ptr StartSpan( opentelemetry::nostd::string_view name, - const opentelemetry::trace::StartSpanOptions &options) noexcept override; + const opentelemetry::trace::KeyValueIterable & /*attributes*/, + const opentelemetry::trace::StartSpanOptions & /*options */) noexcept override; void ForceFlushWithMicroseconds(uint64_t /*timeout*/) noexcept override {} diff --git a/sdk/include/opentelemetry/sdk/trace/recordable.h b/sdk/include/opentelemetry/sdk/trace/recordable.h index c102958fe3..d901dbfa54 100644 --- a/sdk/include/opentelemetry/sdk/trace/recordable.h +++ b/sdk/include/opentelemetry/sdk/trace/recordable.h @@ -1,5 +1,6 @@ #pragma once +#include "opentelemetry/common/attribute_value.h" #include "opentelemetry/core/timestamp.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/trace/canonical_code.h" @@ -33,6 +34,14 @@ class Recordable opentelemetry::trace::SpanId span_id, opentelemetry::trace::SpanId parent_span_id) noexcept = 0; + /** + * Set an attribute of a span. + * @param name the name of the attribute + * @param value the attribute value + */ + virtual void SetAttribute(nostd::string_view key, + const opentelemetry::common::AttributeValue &&value) noexcept = 0; + /** * Add an event to a span. * @param name the name of the event diff --git a/sdk/include/opentelemetry/sdk/trace/span_data.h b/sdk/include/opentelemetry/sdk/trace/span_data.h index 8ac620ad1b..c3b557dc9b 100644 --- a/sdk/include/opentelemetry/sdk/trace/span_data.h +++ b/sdk/include/opentelemetry/sdk/trace/span_data.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "opentelemetry/core/timestamp.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/sdk/trace/recordable.h" @@ -67,6 +68,15 @@ class SpanData final : public Recordable */ std::chrono::nanoseconds GetDuration() const noexcept { return duration_; } + /** + * Get the attributes for this span + * @return the attributes for this span + */ + const std::unordered_map &GetAttributes() const noexcept + { + return attributes_; + } + void SetIds(opentelemetry::trace::TraceId trace_id, opentelemetry::trace::SpanId span_id, opentelemetry::trace::SpanId parent_span_id) noexcept override @@ -76,6 +86,11 @@ class SpanData final : public Recordable parent_span_id_ = parent_span_id; } + void SetAttribute(nostd::string_view key, const common::AttributeValue &&value) noexcept override + { + attributes_[std::string(key)] = value; + } + void AddEvent(nostd::string_view name, core::SystemTimestamp timestamp) noexcept override { (void)name; @@ -106,6 +121,7 @@ class SpanData final : public Recordable std::string name_; opentelemetry::trace::CanonicalCode status_code_{opentelemetry::trace::CanonicalCode::OK}; std::string status_desc_; + std::unordered_map attributes_; }; } // namespace trace } // namespace sdk diff --git a/sdk/include/opentelemetry/sdk/trace/tracer.h b/sdk/include/opentelemetry/sdk/trace/tracer.h index 06c83b1058..577785878a 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer.h @@ -37,6 +37,7 @@ class Tracer final : public trace_api::Tracer, public std::enable_shared_from_th nostd::unique_ptr StartSpan( nostd::string_view name, + const trace_api::KeyValueIterable &attributes, const trace_api::StartSpanOptions &options = {}) noexcept override; void ForceFlushWithMicroseconds(uint64_t timeout) noexcept override; diff --git a/sdk/src/trace/span.cc b/sdk/src/trace/span.cc index a69e6673b0..dde8710ec2 100644 --- a/sdk/src/trace/span.cc +++ b/sdk/src/trace/span.cc @@ -41,6 +41,7 @@ SteadyTimestamp NowOr(const SteadyTimestamp &steady) Span::Span(std::shared_ptr &&tracer, std::shared_ptr processor, nostd::string_view name, + const trace_api::KeyValueIterable &attributes, const trace_api::StartSpanOptions &options) noexcept : tracer_{std::move(tracer)}, processor_{processor}, @@ -55,6 +56,11 @@ Span::Span(std::shared_ptr &&tracer, processor_->OnStart(*recordable_); recordable_->SetName(name); + attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept { + recordable_->SetAttribute(key, std::move(value)); + return true; + }); + recordable_->SetStartTime(NowOr(options.start_system_time)); start_steady_time = NowOr(options.start_steady_time); } @@ -64,6 +70,13 @@ Span::~Span() End(); } +void Span::SetAttribute(nostd::string_view key, const common::AttributeValue &&value) noexcept +{ + std::lock_guard lock_guard{mu_}; + + recordable_->SetAttribute(key, std::move(value)); +} + void Span::AddEvent(nostd::string_view name) noexcept { (void)name; diff --git a/sdk/src/trace/span.h b/sdk/src/trace/span.h index e1a6f2084a..db8d01ab4e 100644 --- a/sdk/src/trace/span.h +++ b/sdk/src/trace/span.h @@ -18,11 +18,14 @@ class Span final : public trace_api::Span explicit Span(std::shared_ptr &&tracer, std::shared_ptr processor, nostd::string_view name, + const trace_api::KeyValueIterable &attributes, const trace_api::StartSpanOptions &options) noexcept; ~Span() override; // trace_api::Span + void SetAttribute(nostd::string_view key, const common::AttributeValue &&value) noexcept override; + void AddEvent(nostd::string_view name) noexcept override; void AddEvent(nostd::string_view name, core::SystemTimestamp timestamp) noexcept override; diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 15e89ceffd..311459060b 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -21,10 +21,11 @@ std::shared_ptr Tracer::GetProcessor() const noexcept nostd::unique_ptr Tracer::StartSpan( nostd::string_view name, + const trace_api::KeyValueIterable &attributes, const trace_api::StartSpanOptions &options) noexcept { - return nostd::unique_ptr{ - new (std::nothrow) Span{this->shared_from_this(), processor_.load(), name, options}}; + return nostd::unique_ptr{new (std::nothrow) Span{ + this->shared_from_this(), processor_.load(), name, attributes, options}}; } void Tracer::ForceFlushWithMicroseconds(uint64_t timeout) noexcept diff --git a/sdk/test/trace/span_data_test.cc b/sdk/test/trace/span_data_test.cc index ea8aab446c..7bf6c34ec1 100644 --- a/sdk/test/trace/span_data_test.cc +++ b/sdk/test/trace/span_data_test.cc @@ -1,4 +1,5 @@ #include "opentelemetry/sdk/trace/span_data.h" +#include "opentelemetry/nostd/variant.h" #include "opentelemetry/trace/span_id.h" #include "opentelemetry/trace/trace_id.h" @@ -20,6 +21,7 @@ TEST(SpanData, DefaultValues) ASSERT_EQ(data.GetDescription(), ""); ASSERT_EQ(data.GetStartTime().time_since_epoch(), std::chrono::nanoseconds(0)); ASSERT_EQ(data.GetDuration(), std::chrono::nanoseconds(0)); + ASSERT_EQ(data.GetAttributes().size(), 0); } TEST(SpanData, Set) @@ -35,6 +37,7 @@ TEST(SpanData, Set) data.SetStatus(opentelemetry::trace::CanonicalCode::UNKNOWN, "description"); data.SetStartTime(now); data.SetDuration(std::chrono::nanoseconds(1000000)); + data.SetAttribute("attr1", 314159); data.AddEvent("event1", now); ASSERT_EQ(data.GetTraceId(), trace_id); @@ -45,4 +48,5 @@ TEST(SpanData, Set) ASSERT_EQ(data.GetDescription(), "description"); ASSERT_EQ(data.GetStartTime().time_since_epoch(), now.time_since_epoch()); ASSERT_EQ(data.GetDuration(), std::chrono::nanoseconds(1000000)); + ASSERT_EQ(opentelemetry::nostd::get(data.GetAttributes().at("attr1")), 314159); } diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index e0bc2afde6..056227aa8d 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -7,6 +7,8 @@ using namespace opentelemetry::sdk::trace; using opentelemetry::core::SteadyTimestamp; using opentelemetry::core::SystemTimestamp; +namespace nostd = opentelemetry::nostd; +namespace common = opentelemetry::common; /** * A mock exporter that switches a flag once a valid recordable was received. @@ -23,8 +25,7 @@ class MockSpanExporter final : public SpanExporter return std::unique_ptr(new SpanData); } - ExportResult Export( - const opentelemetry::nostd::span> &recordables) noexcept override + ExportResult Export(const nostd::span> &recordables) noexcept override { for (auto &recordable : recordables) { @@ -47,12 +48,12 @@ class MockSpanExporter final : public SpanExporter namespace { -std::shared_ptr initTracer( +std::shared_ptr initTracer( std::shared_ptr>> &received) { std::unique_ptr exporter(new MockSpanExporter(received)); std::shared_ptr processor(new SimpleSpanProcessor(std::move(exporter))); - return std::shared_ptr(new Tracer(processor)); + return std::shared_ptr(new Tracer(processor)); } } // namespace @@ -91,7 +92,7 @@ TEST(Tracer, StartSpan) ASSERT_LT(std::chrono::nanoseconds(0), span_data->GetDuration()); } -TEST(Tracer, StartSpanWithOptions) +TEST(Tracer, StartSpanWithOptionsTime) { std::shared_ptr>> spans_received( new std::vector>); @@ -112,3 +113,29 @@ TEST(Tracer, StartSpanWithOptions) ASSERT_EQ(std::chrono::nanoseconds(300), span_data->GetStartTime().time_since_epoch()); ASSERT_EQ(std::chrono::nanoseconds(30), span_data->GetDuration()); } + +TEST(Tracer, StartSpanWithAttributes) +{ + std::shared_ptr>> spans_received( + new std::vector>); + auto tracer = initTracer(spans_received); + + { + tracer->StartSpan("span 1", {{"attr1", 314159}, {"attr2", false}, {"attr1", "string"}}); + + std::map m; + m["attr3"] = 3.0; + tracer->StartSpan("span 2", m); + } + + ASSERT_EQ(2, spans_received->size()); + + auto &span_data = spans_received->at(0); + ASSERT_EQ(2, span_data->GetAttributes().size()); + ASSERT_EQ("string", nostd::get(span_data->GetAttributes().at("attr1"))); + ASSERT_EQ(false, nostd::get(span_data->GetAttributes().at("attr2"))); + + auto &span_data2 = spans_received->at(1); + ASSERT_EQ(1, span_data2->GetAttributes().size()); + ASSERT_EQ(3.0, nostd::get(span_data2->GetAttributes().at("attr3"))); +} From 70d86d555205987278f37c806cc24ca4142ed2b9 Mon Sep 17 00:00:00 2001 From: Oliver Zhang <30583106+ziqizh@users.noreply.github.com> Date: Tue, 23 Jun 2020 16:06:14 -0400 Subject: [PATCH 13/42] Add sampler header file (#118) --- sdk/include/opentelemetry/sdk/trace/sampler.h | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 sdk/include/opentelemetry/sdk/trace/sampler.h diff --git a/sdk/include/opentelemetry/sdk/trace/sampler.h b/sdk/include/opentelemetry/sdk/trace/sampler.h new file mode 100644 index 0000000000..2cf24b4b40 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/trace/sampler.h @@ -0,0 +1,85 @@ +#pragma once + +#include "opentelemetry/common/attribute_value.h" +#include "opentelemetry/trace/span.h" +#include "opentelemetry/trace/trace_id.h" +#include "opentelemetry/version.h" + +#include +#include +#include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace trace +{ +namespace trace_api = opentelemetry::trace; + +/** + * A sampling Decision for a Span to be created. + */ +enum class Decision +{ + // IsRecording() == false, span will not be recorded and all events and attributes will be + // dropped. + NOT_RECORD, + // IsRecording() == true, but Sampled flag MUST NOT be set. + RECORD, + // IsRecording() == true AND Sampled flag` MUST be set. + RECORD_AND_SAMPLE +}; + +/** + * The output of ShouldSample. + * It contains a sampling Decision and a set of Span Attributes. + */ +struct SamplingResult +{ + Decision decision; + // A set of span Attributes that will also be added to the Span. Can be nullptr. + std::unique_ptr> attributes; +}; + +/** + * The Sampler interface allows users to create custom samplers which will return a + * SamplingResult based on information that is typically available just before the Span was created. + */ +class Sampler +{ +public: + // TODO: Remove this placeholder with real class + class SpanContext; + virtual ~Sampler() = default; + /** + * Called during Span creation to make a sampling decision. + * + * @param parent_context a const pointer of the SpanContext of a parent Span. + * null if this is a root span. + * @param trace_id the TraceId for the new Span. This will be identical to that in + * the parentContext, unless this is a root span. + * @param name the name of the new Span. + * @param spanKind the trace_api::SpanKind of the Span. + * @param attributes list of AttributeValue with their keys. + * @param links TODO: Collection of links that will be associated with the Span to be created. + * @return sampling result whether span should be sampled or not. + * @since 0.1.0 + */ + + virtual SamplingResult ShouldSample(const SpanContext *parent_context, + trace_api::TraceId trace_id, + nostd::string_view name, + trace_api::SpanKind span_kind, + const KeyValueIterable &attributes) noexcept = 0; + + /** + * Returns the sampler name or short description with the configuration. + * This may be displayed on debug pages or in the logs. + * + * @return the description of this Sampler. + */ + virtual std::string GetDescription() const noexcept = 0; +}; +} // namespace trace +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE From 6cb38fa6341812acfe664e631a9a76952ed84188 Mon Sep 17 00:00:00 2001 From: Oliver Zhang <30583106+ziqizh@users.noreply.github.com> Date: Wed, 24 Jun 2020 11:23:02 -0400 Subject: [PATCH 14/42] SamplingResult attributes fix (#126) --- sdk/include/opentelemetry/sdk/trace/sampler.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/include/opentelemetry/sdk/trace/sampler.h b/sdk/include/opentelemetry/sdk/trace/sampler.h index 2cf24b4b40..93599b18e7 100644 --- a/sdk/include/opentelemetry/sdk/trace/sampler.h +++ b/sdk/include/opentelemetry/sdk/trace/sampler.h @@ -38,7 +38,7 @@ struct SamplingResult { Decision decision; // A set of span Attributes that will also be added to the Span. Can be nullptr. - std::unique_ptr> attributes; + std::unique_ptr> attributes; }; /** @@ -70,7 +70,7 @@ class Sampler trace_api::TraceId trace_id, nostd::string_view name, trace_api::SpanKind span_kind, - const KeyValueIterable &attributes) noexcept = 0; + const trace_api::KeyValueIterable &attributes) noexcept = 0; /** * Returns the sampler name or short description with the configuration. From ed0a36e2906ab7eb03c3b0a4c8dea02eb78849ce Mon Sep 17 00:00:00 2001 From: Nick Holbrook Date: Fri, 26 Jun 2020 17:33:38 -0400 Subject: [PATCH 15/42] Always Off Sampler (#125) --- .bazelversion | 2 +- .../sdk/trace/samplers/always_off.h | 41 +++++++++++++++++++ sdk/test/trace/BUILD | 11 +++++ sdk/test/trace/CMakeLists.txt | 2 +- sdk/test/trace/always_off_sampler_test.cc | 30 ++++++++++++++ 5 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 sdk/include/opentelemetry/sdk/trace/samplers/always_off.h create mode 100644 sdk/test/trace/always_off_sampler_test.cc diff --git a/.bazelversion b/.bazelversion index 944880fa15..15a2799817 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -3.2.0 +3.3.0 diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h b/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h new file mode 100644 index 0000000000..0547068280 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h @@ -0,0 +1,41 @@ +#pragma once + +#include "opentelemetry/sdk/trace/sampler.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace trace +{ +namespace trace_api = opentelemetry::trace; +/** + * The always off sampler always returns NOT_RECORD, effectively disabling + * tracing functionality. + */ +class AlwaysOffSampler : public Sampler +{ +public: + /** + * @return Returns NOT_RECORD always + */ + SamplingResult ShouldSample( + const SpanContext * /*parent_context*/, + trace_api::TraceId /*trace_id*/, + nostd::string_view /*name*/, + trace_api::SpanKind /*span_kind*/, + const trace_api::KeyValueIterable & /*attributes*/) noexcept override + { + return { Decision::NOT_RECORD, nullptr }; + } + + /** + * @return Description MUST be AlwaysOffSampler + */ + std::string GetDescription() const noexcept override + { + return "AlwaysOffSampler"; + } +}; +} // namespace trace +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/test/trace/BUILD b/sdk/test/trace/BUILD index 6748cde17f..f07ee5440a 100644 --- a/sdk/test/trace/BUILD +++ b/sdk/test/trace/BUILD @@ -41,3 +41,14 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "always_off_sampler_test", + srcs = [ + "always_off_sampler_test.cc" + ], + deps = [ + "//sdk/src/trace", + "@com_google_googletest//:gtest_main", + ] +) diff --git a/sdk/test/trace/CMakeLists.txt b/sdk/test/trace/CMakeLists.txt index 5bca38440a..052b7e2a86 100644 --- a/sdk/test/trace/CMakeLists.txt +++ b/sdk/test/trace/CMakeLists.txt @@ -1,5 +1,5 @@ foreach(testname tracer_provider_test span_data_test simple_processor_test - tracer_test) + tracer_test always_off_sampler_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_trace) diff --git a/sdk/test/trace/always_off_sampler_test.cc b/sdk/test/trace/always_off_sampler_test.cc new file mode 100644 index 0000000000..2c892fcfa7 --- /dev/null +++ b/sdk/test/trace/always_off_sampler_test.cc @@ -0,0 +1,30 @@ +#include "opentelemetry/sdk/trace/samplers/always_off.h" + +#include + +using opentelemetry::sdk::trace::AlwaysOffSampler; +using opentelemetry::sdk::trace::Decision; + +TEST(AlwaysOffSampler, ShouldSample) +{ + AlwaysOffSampler sampler; + + opentelemetry::trace::TraceId trace_id; + opentelemetry::trace::SpanKind span_kind = opentelemetry::trace::SpanKind::kInternal; + + using M = std::map; + M m1 = {{}}; + opentelemetry::trace::KeyValueIterableView view{m1}; + + auto sampling_result = sampler.ShouldSample(nullptr, trace_id, "", span_kind, view); + + ASSERT_EQ(Decision::NOT_RECORD, sampling_result.decision); + ASSERT_EQ(nullptr, sampling_result.attributes); +} + +TEST(AlwaysOffSampler, GetDescription) +{ + AlwaysOffSampler sampler; + + ASSERT_EQ("AlwaysOffSampler", sampler.GetDescription()); +} From 79b61418febc1768b7327de1cd8b416f0a492a11 Mon Sep 17 00:00:00 2001 From: Oliver Zhang <30583106+ziqizh@users.noreply.github.com> Date: Mon, 29 Jun 2020 18:50:53 -0400 Subject: [PATCH 16/42] Always on sampler (#122) --- sdk/include/opentelemetry/sdk/trace/sampler.h | 4 +- .../sdk/trace/samplers/always_on.h | 36 ++++++++++++++++ sdk/test/trace/BUILD | 19 ++++++-- sdk/test/trace/CMakeLists.txt | 2 +- sdk/test/trace/always_on_sampler_test.cc | 43 +++++++++++++++++++ 5 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 sdk/include/opentelemetry/sdk/trace/samplers/always_on.h create mode 100644 sdk/test/trace/always_on_sampler_test.cc diff --git a/sdk/include/opentelemetry/sdk/trace/sampler.h b/sdk/include/opentelemetry/sdk/trace/sampler.h index 93599b18e7..27071b458c 100644 --- a/sdk/include/opentelemetry/sdk/trace/sampler.h +++ b/sdk/include/opentelemetry/sdk/trace/sampler.h @@ -17,7 +17,7 @@ namespace trace namespace trace_api = opentelemetry::trace; /** - * A sampling Decision for a Span to be created. + * A sampling Decision for a Span to be created. */ enum class Decision { @@ -31,7 +31,7 @@ enum class Decision }; /** - * The output of ShouldSample. + * The output of ShouldSample. * It contains a sampling Decision and a set of Span Attributes. */ struct SamplingResult diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h b/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h new file mode 100644 index 0000000000..e50d15829f --- /dev/null +++ b/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h @@ -0,0 +1,36 @@ +#pragma once + +#include "opentelemetry/sdk/trace/sampler.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace trace +{ +namespace trace_api = opentelemetry::trace; +/** + * The always on sampler is a default sampler which always return Decision::RECORD_AND_SAMPLE + */ +class AlwaysOnSampler : public Sampler +{ +public: + /** + * @return Always return Decision RECORD_AND_SAMPLE + */ + inline SamplingResult ShouldSample(const SpanContext * /*parent_context*/, + trace_api::TraceId /*trace_id*/, + nostd::string_view /*name*/, + trace_api::SpanKind /*span_kind*/, + const trace_api::KeyValueIterable & /*attributes*/) noexcept override + { + return {Decision::RECORD_AND_SAMPLE, nullptr}; + } + + /** + * @return Description MUST be AlwaysOnSampler + */ + inline std::string GetDescription() const noexcept override { return "AlwaysOnSampler"; } +}; +} // namespace trace +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/test/trace/BUILD b/sdk/test/trace/BUILD index f07ee5440a..37018d7eeb 100644 --- a/sdk/test/trace/BUILD +++ b/sdk/test/trace/BUILD @@ -43,12 +43,25 @@ cc_test( ) cc_test( - name = "always_off_sampler_test", + name = "always_on_sampler_test", srcs = [ - "always_off_sampler_test.cc" + "always_on_sampler_test.cc", ], deps = [ "//sdk/src/trace", "@com_google_googletest//:gtest_main", - ] + ], ) + + + +cc_test( + name = "always_off_sampler_test", + srcs = [ + "always_off_sampler_test.cc", + ], + deps = [ + "//sdk/src/trace", + "@com_google_googletest//:gtest_main", + ], +) \ No newline at end of file diff --git a/sdk/test/trace/CMakeLists.txt b/sdk/test/trace/CMakeLists.txt index 052b7e2a86..75bfd4f97a 100644 --- a/sdk/test/trace/CMakeLists.txt +++ b/sdk/test/trace/CMakeLists.txt @@ -1,5 +1,5 @@ foreach(testname tracer_provider_test span_data_test simple_processor_test - tracer_test always_off_sampler_test) + tracer_test always_off_sampler_test always_on_sampler_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_trace) diff --git a/sdk/test/trace/always_on_sampler_test.cc b/sdk/test/trace/always_on_sampler_test.cc new file mode 100644 index 0000000000..a933cd0073 --- /dev/null +++ b/sdk/test/trace/always_on_sampler_test.cc @@ -0,0 +1,43 @@ +#include "opentelemetry/nostd/span.h" +#include "opentelemetry/sdk/trace/samplers/always_on.h" + +#include +#include + +using namespace opentelemetry::sdk::trace; +using namespace opentelemetry::nostd; + +TEST(AlwaysOnSampler, ShouldSample) +{ + AlwaysOnSampler sampler; + + // A buffer of trace_id with no specific meaning + constexpr uint8_t buf[] = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7}; + + trace_api::TraceId trace_id_invalid; + trace_api::TraceId trace_id_valid(buf); + std::map key_value_container = {{"key", 0}}; + + // Test with invalid (empty) trace id and empty parent context + auto sampling_result = sampler.ShouldSample( + nullptr, trace_id_invalid, "invalid trace id test", trace_api::SpanKind::kServer, + trace_api::KeyValueIterableView>(key_value_container)); + + ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision); + ASSERT_EQ(nullptr, sampling_result.attributes); + + // Test with a valid trace id and empty parent context + sampling_result = sampler.ShouldSample( + nullptr, trace_id_valid, "valid trace id test", trace_api::SpanKind::kServer, + trace_api::KeyValueIterableView>(key_value_container)); + + ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result.decision); + ASSERT_EQ(nullptr, sampling_result.attributes); +} + +TEST(AlwaysOnSampler, GetDescription) +{ + AlwaysOnSampler sampler; + + ASSERT_EQ("AlwaysOnSampler", sampler.GetDescription()); +} From aa79d9ca0bc00c813b2e6029b3ab0e74b16a52c6 Mon Sep 17 00:00:00 2001 From: Max Golovanov Date: Mon, 29 Jun 2020 16:13:06 -0700 Subject: [PATCH 17/42] Add compare operators to nostd::string_view (#124) * Add compare operators to nostd::string_view * Added tests --- api/include/opentelemetry/nostd/string_view.h | 64 +++++++++++++++++-- api/test/nostd/string_view_test.cc | 30 +++++++++ 2 files changed, 87 insertions(+), 7 deletions(-) diff --git a/api/include/opentelemetry/nostd/string_view.h b/api/include/opentelemetry/nostd/string_view.h index 02f6b326a7..e947d23259 100644 --- a/api/include/opentelemetry/nostd/string_view.h +++ b/api/include/opentelemetry/nostd/string_view.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -11,6 +12,9 @@ OPENTELEMETRY_BEGIN_NAMESPACE namespace nostd { + +using Traits = std::char_traits; + /** * Back port of std::string_view to work with pre-cpp-17 compilers. * @@ -20,7 +24,9 @@ namespace nostd class string_view { public: - static constexpr std::size_t npos = static_cast(-1); + typedef std::size_t size_type; + + static constexpr size_type npos = static_cast(-1); string_view() noexcept : length_(0), data_(nullptr) {} @@ -30,7 +36,7 @@ class string_view : length_(str.length()), data_(str.c_str()) {} - string_view(const char *str, size_t len) noexcept : length_(len), data_(str) {} + string_view(const char *str, size_type len) noexcept : length_(len), data_(str) {} explicit operator std::string() const { return {data_, length_}; } @@ -38,17 +44,17 @@ class string_view bool empty() const noexcept { return length_ == 0; } - size_t length() const noexcept { return length_; } + size_type length() const noexcept { return length_; } - size_t size() const noexcept { return length_; } + size_type size() const noexcept { return length_; } const char *begin() const noexcept { return data(); } const char *end() const noexcept { return data() + length(); } - const char &operator[](std::size_t i) { return *(data() + i); } + const char &operator[](size_type i) { return *(data() + i); } - string_view substr(std::size_t pos, std::size_t n = npos) const + string_view substr(size_type pos, size_type n = npos) const { if (pos > length_) { @@ -62,11 +68,55 @@ class string_view return string_view(data_ + pos, n); } + int compare(string_view v) const noexcept + { + size_type len = std::min(size(), v.size()); + int result = Traits::compare(data(), v.data(), len); + if (result == 0) + result = size() == v.size() ? 0 : (size() < v.size() ? -1 : 1); + return result; + }; + + int compare(size_type pos1, size_type count1, string_view v) const + { + return substr(pos1, count1).compare(v); + }; + + int compare(size_type pos1, size_type count1, string_view v, size_type pos2, size_type count2) const + { + return substr(pos1, count1).compare(v.substr(pos2, count2)); + }; + + int compare(const char *s) const + { + return compare(string_view(s)); + }; + + int compare(size_type pos1, size_type count1, const char *s) const + { + return substr(pos1, count1).compare(string_view(s)); + }; + + int compare(size_type pos1, size_type count1, const char *s, size_type count2) const + { + return substr(pos1, count1).compare(string_view(s, count2)); + }; + + bool operator<(const string_view v) const noexcept + { + return compare(v) < 0; + } + + bool operator>(const string_view v) const noexcept + { + return compare(v) > 0; + } + private: // Note: uses the same binary layout as libstdc++'s std::string_view // See // https://github.com/gcc-mirror/gcc/blob/e0c554e4da7310df83bb1dcc7b8e6c4c9c5a2a4f/libstdc%2B%2B-v3/include/std/string_view#L466-L467 - size_t length_; + size_type length_; const char *data_; }; diff --git a/api/test/nostd/string_view_test.cc b/api/test/nostd/string_view_test.cc index 17c52bf6cb..074d3bee49 100644 --- a/api/test/nostd/string_view_test.cc +++ b/api/test/nostd/string_view_test.cc @@ -2,6 +2,8 @@ #include +#include "map" + using opentelemetry::nostd::string_view; TEST(StringViewTest, DefaultConstruction) @@ -72,3 +74,31 @@ TEST(StringViewTest, SubstrOutOfRange) EXPECT_DEATH({ s.substr(10); }, ""); #endif } + +TEST(StringViewTest, Compare) +{ + string_view s1 = "aaa"; + string_view s2 = "bbb"; + string_view s3 = "aaa"; + + // Equals + EXPECT_EQ(s1, s3); + EXPECT_EQ(s1, s1); + + // Less then + EXPECT_LT(s1, s2); + + // Greater then + EXPECT_GT(s2, s1); +} + +TEST(StringViewTest, MapKeyOrdering) +{ + std::map m = {{"bbb", 2}, {"aaa", 1}, {"ccc", 3}}; + size_t i = 1; + for (const auto &kv : m) + { + EXPECT_EQ(kv.second, i); + i++; + } +} From f399bf5db4f46a3611363d54dd29723d7f5d1166 Mon Sep 17 00:00:00 2001 From: Janet Vu Date: Tue, 30 Jun 2020 10:56:45 -0400 Subject: [PATCH 18/42] Start zPages README (#131) --- ext/src/zpages/README.md | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 ext/src/zpages/README.md diff --git a/ext/src/zpages/README.md b/ext/src/zpages/README.md new file mode 100644 index 0000000000..f1bad98516 --- /dev/null +++ b/ext/src/zpages/README.md @@ -0,0 +1,46 @@ +# zPages +> Last updated 6/26/20 + +# Table of Contents +- [Summary](#summary) + - [TraceZ](#tracez) + - [RPCz](#rpcz) +- [Usage](#usage) +- [Links of Interest](#links-of-interest) + +## Summary +zPages allow easy viewing of tracing information. When included for a process, zPages will display basic information about that process on a webpage. There are currently two types of zPages: TraceZ and RPCz. + +Including a zPage within a page is useful for developers because it's quicker to get running than adding extra code and installing external exporters like Jaeger and Zipkin. zPages tend to be more lightweight than these external exporters, but are also helpful for debugging latency issues and deadlocks. + +The idea of "zPages" originates from one of OpenTelemetry's predecessors, [OpenCensus](https://opencensus.io/). You can read more about it [here](https://opencensus.io/zpages). OpenCensus has different zPage implementations in [Java](https://opencensus.io/zpages/java/), [Go](https://opencensus.io/zpages/go/), and [Node](https://opencensus.io/zpages/node/) and there has been similar internal solutions developed at companies like Uber, but *this is the first major open-source implementation of zPages in C++*. Within OpenTelemetry, zPages are also being developed in [Java](https://github.com/open-telemetry/opentelemetry-java). + +#### How It Works +On a high level, zPages work by reading a process' spans using a SpanProcessor, which exports spans to the appropriate DataAggregator that a HttpServer uses. + +> TODO: Add picture examples for span overview and individual span view + +### TraceZ +TraceZ is a type of zPage that shows information on tracing spans, and allows users to look closer at specific and individual spans. Details a user would view include span id, name, status, and timestamps. The individual components of TraceZ are as follows: + +- TracezSpanProcessor (TSP) + - Contact point for TraceZ to connect with a process, which collects tracing information and provides an interface for TDA. +- TracezDataAggregator (TDA) + - Intermediary between the TSP and THS, which also performs various functions and calculations to send the correct tracing information to the THS. +- TracezHttpServer (THS) + - User-facing web page generator, which creates HTML pages using TDA that display 1) overall information on all of the process's spans and 2) more detailed information on specific spans when clicked. + +### RPCz +RPCz is a type of zPage that provides details on instrumented sent and received RPC messages. Although there is currently no ongoing development of RPCz for OpenTelemetry, OpenCensus zPages have implementations of RPCz (linked above). + +# Usage + +> TODO: Add instructions to add zPages + +## Links of Interest +- [TracezSpanProcessor Design Doc](https://docs.google.com/document/d/1kO4iZARYyr-EGBlY2VNM3ELU3iw6ZrC58Omup_YT-fU/edit#) (pending review) +- [TracezDataAggregator Design Doc](https://docs.google.com/document/d/1ziKFgvhXFfRXZjOlAHQRR-TzcNcTXzg1p2I9oPCEIoU/edit?ts=5ef0d177#heading=h.5irk4csrpu0y) (pending review) +- [TracezHttpServer Design Doc](https://docs.google.com/document/d/1U1V8QZ5LtGl4Mich-aJ6KZGLHrMIE8pWyspmzvnIefI/edit#) (draft) +- [Contribution Guidelines](https://github.com/open-telemetry/opentelemetry-cpp/blob/master/CONTRIBUTING.md) + + From 5f4a464396782110ecf5c0a669dee1f850b94ec4 Mon Sep 17 00:00:00 2001 From: Nadia Ciobanu Date: Thu, 2 Jul 2020 09:15:03 -0700 Subject: [PATCH 19/42] Implement basic OTLP Recordable (#127) --- exporters/otlp/BUILD | 9 ++++ exporters/otlp/CMakeLists.txt | 8 ++++ exporters/otlp/recordable.cc | 29 ++++++++++++ exporters/otlp/recordable.h | 12 ++++- exporters/otlp/recordable_test.cc | 73 +++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 exporters/otlp/recordable_test.cc diff --git a/exporters/otlp/BUILD b/exporters/otlp/BUILD index 09b1516ab5..fd1f048889 100644 --- a/exporters/otlp/BUILD +++ b/exporters/otlp/BUILD @@ -28,3 +28,12 @@ cc_library( "@com_github_opentelemetry_proto//:trace_proto_cc", ], ) + +cc_test( + name = "recordable_test", + srcs = ["recordable_test.cc"], + deps = [ + ":recordable", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/exporters/otlp/CMakeLists.txt b/exporters/otlp/CMakeLists.txt index 07311ce909..3cfc1a5832 100644 --- a/exporters/otlp/CMakeLists.txt +++ b/exporters/otlp/CMakeLists.txt @@ -1,3 +1,11 @@ add_library(opentelemetry_exporter_otprotocol recordable.cc) target_link_libraries(opentelemetry_exporter_otprotocol $) + +add_executable(recordable_test recordable_test.cc) +target_link_libraries(recordable_test + ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_exporter_otprotocol + protobuf::libprotobuf) +gtest_add_tests(TARGET recordable_test TEST_PREFIX exporter. TEST_LIST recordable_test) diff --git a/exporters/otlp/recordable.cc b/exporters/otlp/recordable.cc index d38f284577..ac53abbd26 100644 --- a/exporters/otlp/recordable.cc +++ b/exporters/otlp/recordable.cc @@ -5,6 +5,23 @@ namespace exporter { namespace otlp { +void Recordable::SetIds(trace::TraceId trace_id, + trace::SpanId span_id, + trace::SpanId parent_span_id) noexcept +{ + span_.set_trace_id(reinterpret_cast(trace_id.Id().data()), trace::TraceId::kSize); + span_.set_span_id(reinterpret_cast(span_id.Id().data()), trace::SpanId::kSize); + span_.set_parent_span_id(reinterpret_cast(parent_span_id.Id().data()), + trace::SpanId::kSize); +} + +void Recordable::SetAttribute(nostd::string_view key, + const opentelemetry::common::AttributeValue &&value) noexcept +{ + (void)key; + (void)value; +} + void Recordable::AddEvent(nostd::string_view name, core::SystemTimestamp timestamp) noexcept { (void)name; @@ -20,6 +37,18 @@ void Recordable::SetName(nostd::string_view name) noexcept { span_.set_name(name.data(), name.size()); } + +void Recordable::SetStartTime(opentelemetry::core::SystemTimestamp start_time) noexcept +{ + const uint64_t nano_unix_time = start_time.time_since_epoch().count(); + span_.set_start_time_unixnano(nano_unix_time); +} + +void Recordable::SetDuration(std::chrono::nanoseconds duration) noexcept +{ + const uint64_t unix_end_time = span_.start_time_unixnano() + duration.count(); + span_.set_end_time_unixnano(unix_end_time); +} } // namespace otlp } // namespace exporter OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/otlp/recordable.h b/exporters/otlp/recordable.h index 5ea1edf497..8490bc9141 100644 --- a/exporters/otlp/recordable.h +++ b/exporters/otlp/recordable.h @@ -14,13 +14,23 @@ class Recordable final : public sdk::trace::Recordable public: const proto::trace::v1::Span &span() const noexcept { return span_; } - // sdk::trace::Recordable + void SetIds(trace::TraceId trace_id, + trace::SpanId span_id, + trace::SpanId parent_span_id) noexcept override; + + void SetAttribute(nostd::string_view key, + const opentelemetry::common::AttributeValue &&value) noexcept override; + void AddEvent(nostd::string_view name, core::SystemTimestamp timestamp) noexcept override; void SetStatus(trace::CanonicalCode code, nostd::string_view description) noexcept override; void SetName(nostd::string_view name) noexcept override; + void SetStartTime(opentelemetry::core::SystemTimestamp start_time) noexcept override; + + void SetDuration(std::chrono::nanoseconds duration) noexcept override; + private: proto::trace::v1::Span span_; }; diff --git a/exporters/otlp/recordable_test.cc b/exporters/otlp/recordable_test.cc new file mode 100644 index 0000000000..7e114ab539 --- /dev/null +++ b/exporters/otlp/recordable_test.cc @@ -0,0 +1,73 @@ +#include "exporters/otlp/recordable.h" + +#include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ +TEST(Recordable, SetIds) +{ + const trace::TraceId trace_id( + std::array( + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})); + + const trace::SpanId span_id( + std::array( + {0, 0, 0, 0, 0, 0, 0, 2})); + + const trace::SpanId parent_span_id( + std::array( + {0, 0, 0, 0, 0, 0, 0, 3})); + + Recordable rec; + + rec.SetIds(trace_id, span_id, parent_span_id); + + EXPECT_EQ(rec.span().trace_id(), + std::string(reinterpret_cast(trace_id.Id().data()), trace::TraceId::kSize)); + EXPECT_EQ(rec.span().span_id(), + std::string(reinterpret_cast(span_id.Id().data()), trace::SpanId::kSize)); + EXPECT_EQ(rec.span().parent_span_id(), + std::string(reinterpret_cast(parent_span_id.Id().data()), trace::SpanId::kSize)); +} + +TEST(Recordable, SetName) +{ + Recordable rec; + nostd::string_view name = "TestSpan"; + rec.SetName(name); + EXPECT_EQ(rec.span().name(), name); +} + +TEST(Recordable, SetStartTime) +{ + Recordable rec; + std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now(); + core::SystemTimestamp start_timestamp(start_time); + + uint64_t unix_start = + std::chrono::duration_cast(start_time.time_since_epoch()).count(); + + rec.SetStartTime(start_timestamp); + EXPECT_EQ(rec.span().start_time_unixnano(), unix_start); +} + +TEST(Recordable, SetDuration) +{ + Recordable rec; + // Start time is 0 + core::SystemTimestamp start_timestamp; + + std::chrono::nanoseconds duration(10); + uint64_t unix_end = duration.count(); + + rec.SetStartTime(start_timestamp); + rec.SetDuration(duration); + + EXPECT_EQ(rec.span().end_time_unixnano(), unix_end); +} +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE From 7486a290bb862b20b3206e3ce0c78118da689cbe Mon Sep 17 00:00:00 2001 From: Nadia Ciobanu Date: Thu, 2 Jul 2020 11:34:02 -0700 Subject: [PATCH 20/42] Update OpenTelemetry protobuf definitions (#140) --- exporters/otlp/recordable.cc | 6 +- exporters/otlp/recordable_test.cc | 4 +- third_party/opentelemetry-proto/README | 2 +- .../metrics/v1/metrics_service_http.yaml | 9 + .../trace/v1/trace_service_http.yaml | 3 - .../proto/common/v1/common.proto | 66 +++-- .../proto/metrics/v1/metrics.proto | 233 ++++++++++++------ .../proto/resource/v1/resource.proto | 2 +- .../opentelemetry/proto/trace/v1/trace.proto | 32 ++- 9 files changed, 237 insertions(+), 120 deletions(-) create mode 100644 third_party/opentelemetry-proto/opentelemetry/proto/collector/metrics/v1/metrics_service_http.yaml diff --git a/exporters/otlp/recordable.cc b/exporters/otlp/recordable.cc index ac53abbd26..1677bb6be1 100644 --- a/exporters/otlp/recordable.cc +++ b/exporters/otlp/recordable.cc @@ -41,13 +41,13 @@ void Recordable::SetName(nostd::string_view name) noexcept void Recordable::SetStartTime(opentelemetry::core::SystemTimestamp start_time) noexcept { const uint64_t nano_unix_time = start_time.time_since_epoch().count(); - span_.set_start_time_unixnano(nano_unix_time); + span_.set_start_time_unix_nano(nano_unix_time); } void Recordable::SetDuration(std::chrono::nanoseconds duration) noexcept { - const uint64_t unix_end_time = span_.start_time_unixnano() + duration.count(); - span_.set_end_time_unixnano(unix_end_time); + const uint64_t unix_end_time = span_.start_time_unix_nano() + duration.count(); + span_.set_end_time_unix_nano(unix_end_time); } } // namespace otlp } // namespace exporter diff --git a/exporters/otlp/recordable_test.cc b/exporters/otlp/recordable_test.cc index 7e114ab539..b086c46b36 100644 --- a/exporters/otlp/recordable_test.cc +++ b/exporters/otlp/recordable_test.cc @@ -51,7 +51,7 @@ TEST(Recordable, SetStartTime) std::chrono::duration_cast(start_time.time_since_epoch()).count(); rec.SetStartTime(start_timestamp); - EXPECT_EQ(rec.span().start_time_unixnano(), unix_start); + EXPECT_EQ(rec.span().start_time_unix_nano(), unix_start); } TEST(Recordable, SetDuration) @@ -66,7 +66,7 @@ TEST(Recordable, SetDuration) rec.SetStartTime(start_timestamp); rec.SetDuration(duration); - EXPECT_EQ(rec.span().end_time_unixnano(), unix_end); + EXPECT_EQ(rec.span().end_time_unix_nano(), unix_end); } } // namespace otlp } // namespace exporter diff --git a/third_party/opentelemetry-proto/README b/third_party/opentelemetry-proto/README index dfd3a68e21..e32d7de183 100644 --- a/third_party/opentelemetry-proto/README +++ b/third_party/opentelemetry-proto/README @@ -1,2 +1,2 @@ From: https://github.com/open-telemetry/opentelemetry-proto -Commit: d496c80b353bc4a4f754ae686b59ca3c41de0946 +Commit: e43e1abc40428a6ee98e3bfd79bec1dfa2ed18cd diff --git a/third_party/opentelemetry-proto/opentelemetry/proto/collector/metrics/v1/metrics_service_http.yaml b/third_party/opentelemetry-proto/opentelemetry/proto/collector/metrics/v1/metrics_service_http.yaml new file mode 100644 index 0000000000..bc5f9ff241 --- /dev/null +++ b/third_party/opentelemetry-proto/opentelemetry/proto/collector/metrics/v1/metrics_service_http.yaml @@ -0,0 +1,9 @@ +# This is an API configuration to generate an HTTP/JSON -> gRPC gateway for the +# OpenTelemetry service using github.com/grpc-ecosystem/grpc-gateway. +type: google.api.Service +config_version: 3 +http: + rules: + - selector: opentelemetry.proto.collector.metrics.v1.MetricsService.Export + post: /v1/metrics + body: "*" diff --git a/third_party/opentelemetry-proto/opentelemetry/proto/collector/trace/v1/trace_service_http.yaml b/third_party/opentelemetry-proto/opentelemetry/proto/collector/trace/v1/trace_service_http.yaml index 7754e5ff12..10eae48d51 100644 --- a/third_party/opentelemetry-proto/opentelemetry/proto/collector/trace/v1/trace_service_http.yaml +++ b/third_party/opentelemetry-proto/opentelemetry/proto/collector/trace/v1/trace_service_http.yaml @@ -7,6 +7,3 @@ http: - selector: opentelemetry.proto.collector.trace.v1.TraceService.Export post: /v1/trace body: "*" - - selector: opentelemetry.proto.collector.metrics.v1.MetricsService.Export - post: /v1/trace - body: "*" \ No newline at end of file diff --git a/third_party/opentelemetry-proto/opentelemetry/proto/common/v1/common.proto b/third_party/opentelemetry-proto/opentelemetry/proto/common/v1/common.proto index b3b1852459..dc67e43fb6 100644 --- a/third_party/opentelemetry-proto/opentelemetry/proto/common/v1/common.proto +++ b/third_party/opentelemetry-proto/opentelemetry/proto/common/v1/common.proto @@ -21,35 +21,57 @@ option java_package = "io.opentelemetry.proto.common.v1"; option java_outer_classname = "CommonProto"; option go_package = "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1"; -// AttributeKeyValue is a key-value pair that is used to store Span attributes, Link -// attributes, etc. -message AttributeKeyValue { - // ValueType is the enumeration of possible types that value can have. - enum ValueType { - STRING = 0; - INT = 1; - DOUBLE = 2; - BOOL = 3; - }; - - // key part of the key-value pair. - string key = 1; +// AnyValue is used to represent any type of attribute value. AnyValue may contain a +// primitive value such as a string or integer or it may contain an arbitrary nested +// object containing arrays, key-value lists and primitives. +message AnyValue { + // The value is one of the listed fields. It is valid for all values to be unspecified + // in which case this AnyValue is considered to be "null". + oneof value { + string string_value = 1; + bool bool_value = 2; + int64 int_value = 3; + double double_value = 4; + ArrayValue array_value = 5; + KeyValueList kvlist_value = 6; + } +} - // type of the value. - ValueType type = 2; +// ArrayValue is a list of AnyValue messages. We need ArrayValue as a message +// since oneof in AnyValue does not allow repeated fields. +message ArrayValue { + // Array of values. The array may be empty (contain 0 elements). + repeated AnyValue values = 1; +} - // Only one of the following fields is supposed to contain data (determined by `type` field). - // This is deliberately not using Protobuf `oneof` for performance reasons (verified by benchmarks). +// KeyValueList is a list of KeyValue messages. We need KeyValueList as a message +// since `oneof` in AnyValue does not allow repeated fields. Everywhere else where we need +// a list of KeyValue messages (e.g. in Span) we use `repeated KeyValue` directly to +// avoid unnecessary extra wrapping (which slows down the protocol). The 2 approaches +// are semantically equivalent. +message KeyValueList { + // A collection of key/value pairs of key-value pairs. The list may be empty (may + // contain 0 elements). + repeated KeyValue values = 1; +} - string string_value = 3; - int64 int_value = 4; - double double_value = 5; - bool bool_value = 6; +// KeyValue is a key-value pair that is used to store Span attributes, Link +// attributes, etc. +message KeyValue { + string key = 1; + AnyValue value = 2; } // StringKeyValue is a pair of key/value strings. This is the simpler (and faster) version -// of AttributeKeyValue that only supports string values. +// of KeyValue that only supports string values. message StringKeyValue { string key = 1; string value = 2; } + +// InstrumentationLibrary is a message representing the instrumentation library information +// such as the fully qualified name and version. +message InstrumentationLibrary { + string name = 1; + string version = 2; +} diff --git a/third_party/opentelemetry-proto/opentelemetry/proto/metrics/v1/metrics.proto b/third_party/opentelemetry-proto/opentelemetry/proto/metrics/v1/metrics.proto index a15a7b6c2b..1d458824fe 100644 --- a/third_party/opentelemetry-proto/opentelemetry/proto/metrics/v1/metrics.proto +++ b/third_party/opentelemetry-proto/opentelemetry/proto/metrics/v1/metrics.proto @@ -24,14 +24,24 @@ option java_package = "io.opentelemetry.proto.metrics.v1"; option java_outer_classname = "MetricsProto"; option go_package = "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1"; -// A collection of metrics from a Resource. +// A collection of InstrumentationLibraryMetrics from a Resource. message ResourceMetrics { - // A list of metrics that originate from a resource. - repeated Metric metrics = 1; - // The resource for the metrics in this message. // If this field is not set then no resource info is known. - opentelemetry.proto.resource.v1.Resource resource = 2; + opentelemetry.proto.resource.v1.Resource resource = 1; + + // A list of metrics that originate from a resource. + repeated InstrumentationLibraryMetrics instrumentation_library_metrics = 2; +} + +// A collection of Metrics produced by an InstrumentationLibrary. +message InstrumentationLibraryMetrics { + // The instrumentation library information for the metrics in this message. + // If this field is not set then no library info is known. + opentelemetry.proto.common.v1.InstrumentationLibrary instrumentation_library = 1; + + // A list of metrics that originate from an instrumentation library. + repeated Metric metrics = 2; } // Defines a Metric which has one or more timeseries. @@ -90,10 +100,10 @@ message Metric { // Data is a list of one or more DataPoints for a single metric. Only one of the // following fields is used for the data, depending on the type of the metric defined // by MetricDescriptor.type field. - repeated Int64DataPoint int64_datapoints = 2; - repeated DoubleDataPoint double_datapoints = 3; - repeated HistogramDataPoint histogram_datapoints = 4; - repeated SummaryDataPoint summary_datapoints = 5; + repeated Int64DataPoint int64_data_points = 2; + repeated DoubleDataPoint double_data_points = 3; + repeated HistogramDataPoint histogram_data_points = 4; + repeated SummaryDataPoint summary_data_points = 5; } // Defines a metric type and its schema. @@ -108,49 +118,36 @@ message MetricDescriptor { // described by http://unitsofmeasure.org/ucum.html. string unit = 3; - // Type of the metric. It describes how the data is reported. - // - // A gauge is an instantaneous measurement of a value. - // - // A counter/cumulative measurement is a value accumulated over a time - // interval. In a time series, cumulative measurements should have the same - // start time, increasing values, until an event resets the cumulative value - // to zero and sets a new start time for the subsequent points. + // Type is the type of values a metric has. enum Type { - // Do not use this default value. - UNSPECIFIED = 0; - - // Integer gauge. The value can go both up and down over time. - // Corresponding values are stored in Int64DataPoint. - GAUGE_INT64 = 1; - - // Floating point gauge. The value can go both up and down over time. - // Corresponding values are stored in DoubleDataPoint. - GAUGE_DOUBLE = 2; - - // Histogram gauge measurement. - // Used in scenarios like a snapshot of time that current items in a queue - // have spent there. - // Corresponding values are stored in HistogramDataPoint. The count and sum of the - // histogram can go both up and down over time. Recorded values are always >= 0. - GAUGE_HISTOGRAM = 3; - - // Integer counter measurement. The value cannot decrease; if value is reset then - // start_time_unixnano should also be reset. - // Corresponding values are stored in Int64DataPoint. - COUNTER_INT64 = 4; - - // Floating point counter measurement. The value cannot decrease, if - // resets then the start_time_unixnano should also be reset. - // Recorded values are always >= 0. - // Corresponding values are stored in DoubleDataPoint. - COUNTER_DOUBLE = 5; - - // Histogram cumulative measurement. - // Corresponding values are stored in HistogramDataPoint. The count and sum of the - // histogram cannot decrease; if values are reset then start_time_unixnano - // should also be reset to the new start timestamp. - CUMULATIVE_HISTOGRAM = 6; + // INVALID_TYPE is the default Type, it MUST not be used. + INVALID_TYPE = 0; + + // INT64 values are signed 64-bit integers. + // + // A Metric of this Type MUST store its values as Int64DataPoint. + INT64 = 1; + + // MONOTONIC_INT64 values are monotonically increasing signed 64-bit + // integers. + // + // A Metric of this Type MUST store its values as Int64DataPoint. + MONOTONIC_INT64 = 2; + + // DOUBLE values are double-precision floating-point numbers. + // + // A Metric of this Type MUST store its values as DoubleDataPoint. + DOUBLE = 3; + + // MONOTONIC_DOUBLE values are monotonically increasing double-precision + // floating-point numbers. + // + // A Metric of this Type MUST store its values as DoubleDataPoint. + MONOTONIC_DOUBLE = 4; + + // Histogram measurement. + // Corresponding values are stored in HistogramDataPoint. + HISTOGRAM = 5; // Summary value. Some frameworks implemented Histograms as a summary of observations // (usually things like request durations and response sizes). While it @@ -158,13 +155,88 @@ message MetricDescriptor { // values, it calculates configurable percentiles over a sliding time // window. // Corresponding values are stored in SummaryDataPoint. - SUMMARY = 7; + SUMMARY = 6; } + + // type is the type of values this metric has. Type type = 4; - // The set of labels associated with the metric descriptor. Labels in this list apply to - // all data points. - repeated opentelemetry.proto.common.v1.StringKeyValue labels = 5; + // Temporality is the temporal quality values of a metric have. It + // describes how those values relate to the time interval over which they + // are reported. + enum Temporality { + // INVALID_TEMPORALITY is the default Temporality, it MUST not be + // used. + INVALID_TEMPORALITY = 0; + + // INSTANTANEOUS is a metric whose values are measured at a particular + // instant. The values are not aggregated over any time interval and are + // unique per timestamp. As such, these metrics are not expected to have + // an associated start time. + INSTANTANEOUS = 1; + + // DELTA is a metric whose values are the aggregation of measurements + // made over a time interval. Successive metrics contain aggregation of + // values from continuous and non-overlapping intervals. + // + // The values for a DELTA metric are based only on the time interval + // associated with one measurement cycle. There is no dependency on + // previous measurements like is the case for CUMULATIVE metrics. + // + // For example, consider a system measuring the number of requests that + // it receives and reports the sum of these requests every second as a + // DELTA metric: + // + // 1. The system starts receiving at time=t_0. + // 2. A request is received, the system measures 1 request. + // 3. A request is received, the system measures 1 request. + // 4. A request is received, the system measures 1 request. + // 5. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_0 to + // t_0+1 with a value of 3. + // 6. A request is received, the system measures 1 request. + // 7. A request is received, the system measures 1 request. + // 8. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_0+1 to + // t_0+2 with a value of 2. + DELTA = 2; + + // CUMULATIVE is a metric whose values are the aggregation of + // successively made measurements from a fixed start time until the last + // reported measurement. This means that current values of a CUMULATIVE + // metric depend on all previous measurements since the start time. + // Because of this, the sender is required to retain this state in some + // form. If this state is lost or invalidated, the CUMULATIVE metric + // values MUST be reset and a new fixed start time following the last + // reported measurement time sent MUST be used. + // + // For example, consider a system measuring the number of requests that + // it receives and reports the sum of these requests every second as a + // CUMULATIVE metric: + // + // 1. The system starts receiving at time=t_0. + // 2. A request is received, the system measures 1 request. + // 3. A request is received, the system measures 1 request. + // 4. A request is received, the system measures 1 request. + // 5. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_0 to + // t_0+1 with a value of 3. + // 6. A request is received, the system measures 1 request. + // 7. A request is received, the system measures 1 request. + // 8. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_0 to + // t_0+2 with a value of 5. + // 9. The system experiences a fault and loses state. + // 10. The system recovers and resumes receiving at time=t_1. + // 11. A request is received, the system measures 1 request. + // 12. The 1 second collection cycle ends. A metric is exported for the + // number of requests received over the interval of time t_1 to + // t_0+1 with a value of 1. + CUMULATIVE = 3; + } + + // temporality is the Temporality of values this metric has. + Temporality temporality = 5; } // Int64DataPoint is a single data point in a timeseries that describes the time-varying @@ -173,20 +245,20 @@ message Int64DataPoint { // The set of labels that uniquely identify this timeseries. repeated opentelemetry.proto.common.v1.StringKeyValue labels = 1; - // start_time_unixnano is the time when the cumulative value was reset to zero. + // start_time_unix_nano is the time when the cumulative value was reset to zero. // This is used for Counter type only. For Gauge the value is not specified and // defaults to 0. // - // The cumulative value is over the time interval (start_time_unixnano, timestamp_unixnano]. + // The cumulative value is over the time interval (start_time_unix_nano, time_unix_nano]. // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. // // Value of 0 indicates that the timestamp is unspecified. In that case the timestamp // may be decided by the backend. - fixed64 start_time_unixnano = 2; + fixed64 start_time_unix_nano = 2; - // timestamp_unixnano is the moment when this value was recorded. + // time_unix_nano is the moment when this value was recorded. // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. - fixed64 timestamp_unixnano = 3; + fixed64 time_unix_nano = 3; // value itself. int64 value = 4; @@ -198,20 +270,20 @@ message DoubleDataPoint { // The set of labels that uniquely identify this timeseries. repeated opentelemetry.proto.common.v1.StringKeyValue labels = 1; - // start_time_unixnano is the time when the cumulative value was reset to zero. + // start_time_unix_nano is the time when the cumulative value was reset to zero. // This is used for Counter type only. For Gauge the value is not specified and // defaults to 0. // - // The cumulative value is over the time interval (start_time_unixnano, timestamp_unixnano]. + // The cumulative value is over the time interval (start_time_unix_nano, time_unix_nano]. // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. // // Value of 0 indicates that the timestamp is unspecified. In that case the timestamp // may be decided by the backend. - fixed64 start_time_unixnano = 2; + fixed64 start_time_unix_nano = 2; - // timestamp_unixnano is the moment when this value was recorded. + // time_unix_nano is the moment when this value was recorded. // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. - fixed64 timestamp_unixnano = 3; + fixed64 time_unix_nano = 3; // value itself. double value = 4; @@ -224,19 +296,19 @@ message HistogramDataPoint { // The set of labels that uniquely identify this timeseries. repeated opentelemetry.proto.common.v1.StringKeyValue labels = 1; - // start_time_unixnano is the time when the cumulative value was reset to zero. + // start_time_unix_nano is the time when the cumulative value was reset to zero. // - // The cumulative value is over the time interval (start_time_unixnano, timestamp_unixnano]. + // The cumulative value is over the time interval (start_time_unix_nano, time_unix_nano]. // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. // // Value of 0 indicates that the timestamp is unspecified. In that case the timestamp // may be decided by the backend. // Note: this field is always unspecified and ignored if MetricDescriptor.type==GAUGE_HISTOGRAM. - fixed64 start_time_unixnano = 2; + fixed64 start_time_unix_nano = 2; - // timestamp_unixnano is the moment when this value was recorded. + // time_unix_nano is the moment when this value was recorded. // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. - fixed64 timestamp_unixnano = 3; + fixed64 time_unix_nano = 3; // count is the number of values in the population. Must be non-negative. This value // must be equal to the sum of the "count" fields in buckets if a histogram is provided. @@ -262,9 +334,9 @@ message HistogramDataPoint { // the defined bounds. double value = 1; - // timestamp_unixnano is the moment when this exemplar was recorded. + // time_unix_nano is the moment when this exemplar was recorded. // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. - fixed64 timestamp_unixnano = 2; + fixed64 time_unix_nano = 2; // exemplar_attachments are contextual information about the example value. // Keys in this list must be unique. @@ -318,18 +390,18 @@ message SummaryDataPoint { // The set of labels that uniquely identify this timeseries. repeated opentelemetry.proto.common.v1.StringKeyValue labels = 1; - // start_time_unixnano is the time when the cumulative value was reset to zero. + // start_time_unix_nano is the time when the cumulative value was reset to zero. // - // The cumulative value is over the time interval (start_time_unixnano, timestamp_unixnano]. + // The cumulative value is over the time interval (start_time_unix_nano, time_unix_nano]. // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. // // Value of 0 indicates that the timestamp is unspecified. In that case the timestamp // may be decided by the backend. - fixed64 start_time_unixnano = 2; + fixed64 start_time_unix_nano = 2; - // timestamp_unixnano is the moment when this value was recorded. + // time_unix_nano is the moment when this value was recorded. // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. - fixed64 timestamp_unixnano = 3; + fixed64 time_unix_nano = 3; // The total number of recorded values since start_time. Optional since // some systems don't expose this. @@ -340,6 +412,13 @@ message SummaryDataPoint { double sum = 5; // Represents the value at a given percentile of a distribution. + // + // To record Min and Max values following conventions are used: + // - The 100th percentile is equivalent to the maximum value observed. + // - The 0th percentile is equivalent to the minimum value observed. + // + // See the following issue for more context: + // https://github.com/open-telemetry/opentelemetry-proto/issues/125 message ValueAtPercentile { // The percentile of a distribution. Must be in the interval // [0.0, 100.0]. diff --git a/third_party/opentelemetry-proto/opentelemetry/proto/resource/v1/resource.proto b/third_party/opentelemetry-proto/opentelemetry/proto/resource/v1/resource.proto index a9e1711af4..fa5d97c6f8 100644 --- a/third_party/opentelemetry-proto/opentelemetry/proto/resource/v1/resource.proto +++ b/third_party/opentelemetry-proto/opentelemetry/proto/resource/v1/resource.proto @@ -26,7 +26,7 @@ option go_package = "github.com/open-telemetry/opentelemetry-proto/gen/go/resour // Resource information. message Resource { // Set of labels that describe the resource. - repeated opentelemetry.proto.common.v1.AttributeKeyValue attributes = 1; + repeated opentelemetry.proto.common.v1.KeyValue attributes = 1; // dropped_attributes_count is the number of dropped attributes. If the value is 0, then // no attributes were dropped. diff --git a/third_party/opentelemetry-proto/opentelemetry/proto/trace/v1/trace.proto b/third_party/opentelemetry-proto/opentelemetry/proto/trace/v1/trace.proto index 7f0e4a75c0..5a2350fdee 100644 --- a/third_party/opentelemetry-proto/opentelemetry/proto/trace/v1/trace.proto +++ b/third_party/opentelemetry-proto/opentelemetry/proto/trace/v1/trace.proto @@ -24,13 +24,23 @@ option java_package = "io.opentelemetry.proto.trace.v1"; option java_outer_classname = "TraceProto"; option go_package = "github.com/open-telemetry/opentelemetry-proto/gen/go/trace/v1"; -// A collection of spans from a Resource. +// A collection of InstrumentationLibrarySpans from a Resource. message ResourceSpans { // The resource for the spans in this message. // If this field is not set then no resource info is known. opentelemetry.proto.resource.v1.Resource resource = 1; - // A list of Spans that originate from a resource. + // A list of InstrumentationLibrarySpans that originate from a resource. + repeated InstrumentationLibrarySpans instrumentation_library_spans = 2; +} + +// A collection of Spans produced by an InstrumentationLibrary. +message InstrumentationLibrarySpans { + // The instrumentation library information for the spans in this message. + // If this field is not set then no library info is known. + opentelemetry.proto.common.v1.InstrumentationLibrary instrumentation_library = 1; + + // A list of Spans that originate from an instrumentation library. repeated Span spans = 2; } @@ -123,21 +133,21 @@ message Span { // and `SERVER` (callee) to identify queueing latency associated with the span. SpanKind kind = 6; - // start_time_unixnano is the start time of the span. On the client side, this is the time + // start_time_unix_nano is the start time of the span. On the client side, this is the time // kept by the local machine where the span execution starts. On the server side, this // is the time when the server's application handler starts running. // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. // // This field is semantically required and it is expected that end_time >= start_time. - fixed64 start_time_unixnano = 7; + fixed64 start_time_unix_nano = 7; - // end_time_unixnano is the end time of the span. On the client side, this is the time + // end_time_unix_nano is the end time of the span. On the client side, this is the time // kept by the local machine where the span execution ends. On the server side, this // is the time when the server application handler stops running. // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. // // This field is semantically required and it is expected that end_time >= start_time. - fixed64 end_time_unixnano = 8; + fixed64 end_time_unix_nano = 8; // attributes is a collection of key/value pairs. The value can be a string, // an integer, a double or the Boolean values `true` or `false`. Note, global attributes @@ -147,7 +157,7 @@ message Span { // "/http/server_latency": 300 // "abc.com/myattribute": true // "abc.com/score": 10.239 - repeated opentelemetry.proto.common.v1.AttributeKeyValue attributes = 9; + repeated opentelemetry.proto.common.v1.KeyValue attributes = 9; // dropped_attributes_count is the number of attributes that were discarded. Attributes // can be discarded because their keys are too long or because there are too many @@ -157,15 +167,15 @@ message Span { // Event is a time-stamped annotation of the span, consisting of user-supplied // text description and key-value pairs. message Event { - // time_unixnano is the time the event occurred. - fixed64 time_unixnano = 1; + // time_unix_nano is the time the event occurred. + fixed64 time_unix_nano = 1; // name of the event. // This field is semantically required to be set to non-empty string. string name = 2; // attributes is a collection of attribute key/value pairs on the event. - repeated opentelemetry.proto.common.v1.AttributeKeyValue attributes = 3; + repeated opentelemetry.proto.common.v1.KeyValue attributes = 3; // dropped_attributes_count is the number of dropped attributes. If the value is 0, // then no attributes were dropped. @@ -195,7 +205,7 @@ message Span { string trace_state = 3; // attributes is a collection of attribute key/value pairs on the link. - repeated opentelemetry.proto.common.v1.AttributeKeyValue attributes = 4; + repeated opentelemetry.proto.common.v1.KeyValue attributes = 4; // dropped_attributes_count is the number of dropped attributes. If the value is 0, // then no attributes were dropped. From 4128a69bf191ed9ac4fa3b96ed67ce32c0bd37ff Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Mon, 6 Jul 2020 19:35:55 +0000 Subject: [PATCH 21/42] added context header with dummy methods --- api/include/opentelemetry/context/TBD | 0 api/include/opentelemetry/context/context.h | 69 +++++++++++++++++++++ api/test/context/context_test.cc | 63 +++++++++++++++++++ 3 files changed, 132 insertions(+) delete mode 100644 api/include/opentelemetry/context/TBD create mode 100644 api/include/opentelemetry/context/context.h create mode 100644 api/test/context/context_test.cc diff --git a/api/include/opentelemetry/context/TBD b/api/include/opentelemetry/context/TBD deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/api/include/opentelemetry/context/context.h b/api/include/opentelemetry/context/context.h new file mode 100644 index 0000000000..35990e93e8 --- /dev/null +++ b/api/include/opentelemetry/context/context.h @@ -0,0 +1,69 @@ +#pragma once + +#include "opentelemetry/common/attribute_value.h" +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/trace/key_value_iterable_view.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace context +{ + +// The context class provides a context identifier. +// This is a dummy class that is meant to be overridden, +// the methods return default values. +class Context +{ + +public: + // The Key class is used to obscure access from the + // user to the context map. The identifier is used as a key + // to the context map. + class Key + { + + public: + // Returns the key's identifier. + nostd::string_view GetIdentifier() { return ""; } + + // Returns the key's name + nostd::string_view GetName() { return ""; } + + Key() = default; + + // Constructs a new Key with the passed in name. Sets the identifier as + // the address of this object. + Key(nostd::string_view key_name) {} + + private: + friend class Context; + }; + + // Creates a key with the passed in name and returns it. + Key CreateKey(nostd::string_view key_name) { return Key(key_name); } + + Context() = default; + + // Contructor, creates a context object from a map of keys + // and identifiers. + template ::value> * = nullptr> + Context(const T &attributes) + {} + + // Accepts a new iterable and then returns a new context that + // contains both the original pairs and the new pair. + template ::value> * = nullptr> + Context WriteValues(T &attributes) noexcept + { + return Context(attributes); + } + + // Returns the value associated with the passed in key. + virtual common::AttributeValue GetValue(Key key) { return 0; } + + // Copy Constructors. + Context(const Context &other) = default; + Context &operator=(const Context &other) = default; +}; + +} // namespace context +OPENTELEMETRY_END_NAMESPACE diff --git a/api/test/context/context_test.cc b/api/test/context/context_test.cc new file mode 100644 index 0000000000..5ed00f81a8 --- /dev/null +++ b/api/test/context/context_test.cc @@ -0,0 +1,63 @@ +#include "opentelemetry/context/context.h" + +#include + +#include + +using namespace opentelemetry; + +// Tests that the context default constructor does not cause a crash +TEST(ContextTest, ContextDefaultConstructorCrash) +{ + context::Context context_test = context::Context(); +} + +// Tests that the context constructor does not cause a crash when a map +// is provided. +TEST(ContextTest, ContextIterableConstructorCrash) +{ + std::map map_test = {{"test_key", "123"}}; + context::Context context_test = context::Context(map_test); +} + +// Tests that the WriteValues method does not crash +TEST(ContextTest, ContextWriteValuesCrash) +{ + std::map map_test = {{"test_key", "123"}}; + std::map map_test_write = {{"foo_key", "456"}}; + context::Context context_test = context::Context(map_test); + context_test.WriteValues(map_test_write); +} + +// Tests that the CreateKey method does not crash +TEST(ContextTest, ContextCreateKeyCrash) +{ + context::Context context_test; + context::Context::Key test_key = context_test.CreateKey("key_name"); +} + +// Tests that the GetValue method does not crash +TEST(ContextTest, ContextGetValueCrash) +{ + std::map map_test = {{"test_key", "123"}}; + std::map map_test_write = {{"foo_key", "456"}}; + context::Context context_test = context::Context(map_test); + context::Context::Key test_key = context_test.CreateKey("key_name"); + EXPECT_EQ(nostd::get(context_test.GetValue(test_key)), 0); +} + +// Tests that the Context::Key GetIdentifier method does not crash +TEST(ContextTest, ContextKeyGetIdentifierCrash) +{ + context::Context context_test; + context::Context::Key test_key = context_test.CreateKey("key_name"); + EXPECT_EQ(test_key.GetIdentifier(), ""); +} + +// Tests that the Context::Key GetName method does not crash +TEST(ContextTest, ContextKeyGetNameCrash) +{ + context::Context context_test; + context::Context::Key test_key = context_test.CreateKey("key_name"); + EXPECT_EQ(test_key.GetName(), ""); +} From cba6d5f6d23acb27fb4d4b9ecbc1e32c887d8d3d Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Mon, 6 Jul 2020 19:40:31 +0000 Subject: [PATCH 22/42] Build and CMake files --- api/test/context/BUILD | 11 +++++++++++ api/test/context/CMakeLists.txt | 8 ++++++++ 2 files changed, 19 insertions(+) create mode 100644 api/test/context/BUILD create mode 100644 api/test/context/CMakeLists.txt diff --git a/api/test/context/BUILD b/api/test/context/BUILD new file mode 100644 index 0000000000..22ad910f0f --- /dev/null +++ b/api/test/context/BUILD @@ -0,0 +1,11 @@ +cc_test( + name = "context_test", + srcs = [ + "context_test.cc", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + diff --git a/api/test/context/CMakeLists.txt b/api/test/context/CMakeLists.txt new file mode 100644 index 0000000000..cb7786ade3 --- /dev/null +++ b/api/test/context/CMakeLists.txt @@ -0,0 +1,8 @@ +include(GoogleTest) + +foreach(testname context_test ) + add_executable(${testname} "${testname}.cc") + target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) + gtest_add_tests(TARGET ${testname} TEST_PREFIX context. TEST_LIST ${testname}) +endforeach() From b2e876eda4c09e75564220910ca6f4296f6adc39 Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Mon, 6 Jul 2020 19:43:11 +0000 Subject: [PATCH 23/42] auto formatted --- api/test/context/BUILD | 1 - api/test/context/CMakeLists.txt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/api/test/context/BUILD b/api/test/context/BUILD index 22ad910f0f..26728542b8 100644 --- a/api/test/context/BUILD +++ b/api/test/context/BUILD @@ -8,4 +8,3 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) - diff --git a/api/test/context/CMakeLists.txt b/api/test/context/CMakeLists.txt index cb7786ade3..38d48ef0e8 100644 --- a/api/test/context/CMakeLists.txt +++ b/api/test/context/CMakeLists.txt @@ -1,6 +1,6 @@ include(GoogleTest) -foreach(testname context_test ) +foreach(testname context_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) From 65f6639d5bda7f00e59b0b8985dc2681a6e28e02 Mon Sep 17 00:00:00 2001 From: Oliver Zhang <30583106+ziqizh@users.noreply.github.com> Date: Tue, 7 Jul 2020 12:33:20 -0400 Subject: [PATCH 24/42] Sampler tracer integration (#128) --- sdk/include/opentelemetry/sdk/trace/tracer.h | 11 +++++++- .../opentelemetry/sdk/trace/tracer_provider.h | 16 +++++++++-- sdk/src/trace/tracer.cc | 9 +++++++ sdk/src/trace/tracer_provider.cc | 10 +++++-- sdk/test/trace/tracer_provider_test.cc | 27 +++++++++++++++++++ sdk/test/trace/tracer_test.cc | 20 ++++++++++++++ 6 files changed, 88 insertions(+), 5 deletions(-) diff --git a/sdk/include/opentelemetry/sdk/trace/tracer.h b/sdk/include/opentelemetry/sdk/trace/tracer.h index 577785878a..2d0afde498 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer.h @@ -2,6 +2,7 @@ #include "opentelemetry/sdk/common/atomic_shared_ptr.h" #include "opentelemetry/sdk/trace/processor.h" +#include "opentelemetry/sdk/trace/samplers/always_on.h" #include "opentelemetry/trace/tracer.h" #include "opentelemetry/version.h" @@ -20,7 +21,8 @@ class Tracer final : public trace_api::Tracer, public std::enable_shared_from_th * @param processor The span processor for this tracer. This must not be a * nullptr. */ - explicit Tracer(std::shared_ptr processor) noexcept : processor_{processor} {} + explicit Tracer(std::shared_ptr processor, + std::shared_ptr sampler = std::make_shared()) noexcept; /** * Set the span processor associated with this tracer. @@ -35,6 +37,12 @@ class Tracer final : public trace_api::Tracer, public std::enable_shared_from_th */ std::shared_ptr GetProcessor() const noexcept; + /** + * Obtain the sampler associated with this tracer. + * @return The sampler for this tracer. + */ + std::shared_ptr GetSampler() const noexcept; + nostd::unique_ptr StartSpan( nostd::string_view name, const trace_api::KeyValueIterable &attributes, @@ -46,6 +54,7 @@ class Tracer final : public trace_api::Tracer, public std::enable_shared_from_th private: opentelemetry::sdk::AtomicSharedPtr processor_; + const std::shared_ptr sampler_; }; } // namespace trace } // namespace sdk diff --git a/sdk/include/opentelemetry/sdk/trace/tracer_provider.h b/sdk/include/opentelemetry/sdk/trace/tracer_provider.h index d78fed02fc..6581ad46be 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer_provider.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer_provider.h @@ -6,6 +6,7 @@ #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/sdk/trace/processor.h" +#include "opentelemetry/sdk/trace/samplers/always_on.h" #include "opentelemetry/sdk/trace/tracer.h" #include "opentelemetry/trace/tracer_provider.h" @@ -18,11 +19,15 @@ class TracerProvider final : public opentelemetry::trace::TracerProvider { public: /** - * Initialize a new tracer provider. + * Initialize a new tracer provider with a specified sampler * @param processor The span processor for this tracer provider. This must * not be a nullptr. + * @param sampler The sampler for this tracer provider. This must + * not be a nullptr. */ - explicit TracerProvider(std::shared_ptr processor) noexcept; + explicit TracerProvider( + std::shared_ptr processor, + std::shared_ptr sampler = std::make_shared()) noexcept; opentelemetry::nostd::shared_ptr GetTracer( nostd::string_view library_name, @@ -41,9 +46,16 @@ class TracerProvider final : public opentelemetry::trace::TracerProvider */ std::shared_ptr GetProcessor() const noexcept; + /** + * Obtain the sampler associated with this tracer provider. + * @return The span processor for this tracer provider. + */ + std::shared_ptr GetSampler() const noexcept; + private: opentelemetry::sdk::AtomicSharedPtr processor_; std::shared_ptr tracer_; + const std::shared_ptr sampler_; }; } // namespace trace } // namespace sdk diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 311459060b..959fa35259 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -9,6 +9,10 @@ namespace sdk { namespace trace { +Tracer::Tracer(std::shared_ptr processor, std::shared_ptr sampler) noexcept + : processor_{processor}, sampler_{sampler} +{} + void Tracer::SetProcessor(std::shared_ptr processor) noexcept { processor_.store(processor); @@ -19,6 +23,11 @@ std::shared_ptr Tracer::GetProcessor() const noexcept return processor_.load(); } +std::shared_ptr Tracer::GetSampler() const noexcept +{ + return sampler_; +} + nostd::unique_ptr Tracer::StartSpan( nostd::string_view name, const trace_api::KeyValueIterable &attributes, diff --git a/sdk/src/trace/tracer_provider.cc b/sdk/src/trace/tracer_provider.cc index 3268207510..32144c4c6b 100644 --- a/sdk/src/trace/tracer_provider.cc +++ b/sdk/src/trace/tracer_provider.cc @@ -5,8 +5,9 @@ namespace sdk { namespace trace { -TracerProvider::TracerProvider(std::shared_ptr processor) noexcept - : processor_{processor}, tracer_(new Tracer(std::move(processor))) +TracerProvider::TracerProvider(std::shared_ptr processor, + std::shared_ptr sampler) noexcept + : processor_{processor}, tracer_(new Tracer(std::move(processor))), sampler_(sampler) {} opentelemetry::nostd::shared_ptr TracerProvider::GetTracer( @@ -28,6 +29,11 @@ std::shared_ptr TracerProvider::GetProcessor() const noexcept { return processor_.load(); } + +std::shared_ptr TracerProvider::GetSampler() const noexcept +{ + return sampler_; +} } // namespace trace } // namespace sdk OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/test/trace/tracer_provider_test.cc b/sdk/test/trace/tracer_provider_test.cc index 90dbe7c747..399ea6d453 100644 --- a/sdk/test/trace/tracer_provider_test.cc +++ b/sdk/test/trace/tracer_provider_test.cc @@ -1,4 +1,6 @@ #include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/sdk/trace/samplers/always_off.h" +#include "opentelemetry/sdk/trace/samplers/always_on.h" #include "opentelemetry/sdk/trace/simple_processor.h" #include "opentelemetry/sdk/trace/tracer.h" @@ -27,3 +29,28 @@ TEST(TracerProvider, GetTracer) ASSERT_NE(nullptr, sdkTracer); ASSERT_EQ(processor, sdkTracer->GetProcessor()); } + +TEST(TracerProvider, GetSampler) +{ + std::shared_ptr processor1(new SimpleSpanProcessor(nullptr)); + + // Create a TracerProvicer with a default AlwaysOnSampler. + TracerProvider tf1(processor1); + auto t1 = tf1.GetSampler(); + auto t2 = tf1.GetSampler(); + ASSERT_NE(nullptr, t1); + ASSERT_NE(nullptr, t2); + + // Should return the same sampler each time. + ASSERT_EQ(t1, t2); + + // Should be AlwaysOnSampler + ASSERT_EQ("AlwaysOnSampler", t2->GetDescription()); + + // Create a TracerProvicer with a custom AlwaysOffSampler. + std::shared_ptr processor2(new SimpleSpanProcessor(nullptr)); + TracerProvider tf2(processor2, std::make_shared()); + auto t3 = tf2.GetSampler(); + + ASSERT_EQ("AlwaysOffSampler", t3->GetDescription()); +} diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index 056227aa8d..2c6b891818 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -1,5 +1,7 @@ #include "opentelemetry/sdk/trace/tracer.h" #include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/samplers/always_on.h" +#include "opentelemetry/sdk/trace/samplers/always_off.h" #include "opentelemetry/sdk/trace/span_data.h" #include @@ -139,3 +141,21 @@ TEST(Tracer, StartSpanWithAttributes) ASSERT_EQ(1, span_data2->GetAttributes().size()); ASSERT_EQ(3.0, nostd::get(span_data2->GetAttributes().at("attr3"))); } + + +TEST(Tracer, GetSampler) +{ + // Create a Tracer with a default AlwaysOnSampler + std::shared_ptr processor_1(new SimpleSpanProcessor(nullptr)); + std::shared_ptr tracer_on(new Tracer(std::move(processor_1))); + + auto t1 = tracer_on->GetSampler(); + ASSERT_EQ("AlwaysOnSampler", t1->GetDescription()); + + // Create a Tracer with a AlwaysOffSampler + std::shared_ptr processor_2(new SimpleSpanProcessor(nullptr)); + std::shared_ptr tracer_off(new Tracer(std::move(processor_2), std::make_shared())); + + auto t2 = tracer_off->GetSampler(); + ASSERT_EQ("AlwaysOffSampler", t2->GetDescription()); +} From 5bcf2d5a20765a2ad87d6e2048646e90aea1bd0c Mon Sep 17 00:00:00 2001 From: Yang Hu Date: Wed, 8 Jul 2020 10:09:21 -0700 Subject: [PATCH 25/42] Add badges to README.md (#157) --- .bazelversion | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.bazelversion b/.bazelversion index 15a2799817..bea438e9ad 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -3.3.0 +3.3.1 diff --git a/README.md b/README.md index b9cee55c84..4cc0df677b 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # OpenTelemetry C++ -[![Gitter chat][gitter-image]][gitter-url] - -[gitter-image]: https://badges.gitter.im/open-telemetry/opentelemetry-cpp.svg -[gitter-url]: https://gitter.im/open-telemetry/opentelemetry-cpp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge +[![Gitter chat](https://badges.gitter.im/open-telemetry/opentelemetry-cpp.svg)](https://gitter.im/open-telemetry/opentelemetry-cpp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![codecov.io](https://codecov.io/gh/open-telemetry/opentelemetry-cpp/branch/master/graphs/badge.svg?)](https://codecov.io/gh/open-telemetry/opentelemetry-cpp/) +[![Build Status](https://action-badges.now.sh/open-telemetry/opentelemetry-cpp)](https://github.com/open-telemetry/opentelemetry-cpp/actions) +[![Release](https://img.shields.io/github/v/release/open-telemetry/opentelemetry-cpp?include_prereleases&style=)](https://github.com/open-telemetry/opentelemetry-cpp/releases/) The C++ [OpenTelemetry](https://opentelemetry.io/) client. From 0cf551911f19b46e2f57b03177ead4ae4a2d1d05 Mon Sep 17 00:00:00 2001 From: Nadia Ciobanu Date: Wed, 8 Jul 2020 11:15:52 -0700 Subject: [PATCH 26/42] Add basic OTLP exporter (#152) --- .bazelrc | 3 ++ WORKSPACE | 24 +++++++++ bazel/opentelemetry_proto.BUILD | 24 +++++++++ exporters/otlp/BUILD | 28 ++++++++++ exporters/otlp/otlp_exporter.cc | 81 ++++++++++++++++++++++++++++ exporters/otlp/otlp_exporter.h | 59 ++++++++++++++++++++ exporters/otlp/otlp_exporter_test.cc | 81 ++++++++++++++++++++++++++++ 7 files changed, 300 insertions(+) create mode 100644 exporters/otlp/otlp_exporter.cc create mode 100644 exporters/otlp/otlp_exporter.h create mode 100644 exporters/otlp/otlp_exporter_test.cc diff --git a/.bazelrc b/.bazelrc index 58140be3c9..e893a2e2fa 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,6 +1,9 @@ # bazel configurations for running tests under sanitizers. # Based on https://github.com/bazelment/trunk/blob/master/tools/bazel.rc +# Needed by gRPC to build on some platforms. +build --copt -DGRPC_BAZEL_BUILD + # --config=asan : Address Sanitizer. common:asan --copt -fsanitize=address common:asan --copt -DADDRESS_SANITIZER diff --git a/WORKSPACE b/WORKSPACE index 1dd2ea37fc..84ab876bc7 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -16,6 +16,30 @@ workspace(name = "io_opentelemetry_cpp") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +# Load gRPC dependency +# Note that this dependency needs to be loaded first due to +# https://github.com/bazelbuild/bazel/issues/6664 +http_archive( + name = "com_github_grpc_grpc", + strip_prefix = "grpc-1.28.0", + urls = [ + "https://github.com/grpc/grpc/archive/v1.28.0.tar.gz", + ], +) + +load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps") + +grpc_deps() + +# Load extra gRPC dependencies due to https://github.com/grpc/grpc/issues/20511 +load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps") + +grpc_extra_deps() + +load("@upb//bazel:repository_defs.bzl", "bazel_version_repository") + +bazel_version_repository(name = "upb_bazel_version") + # Uses older protobuf version because of # https://github.com/protocolbuffers/protobuf/issues/7179 http_archive( diff --git a/bazel/opentelemetry_proto.BUILD b/bazel/opentelemetry_proto.BUILD index ddb9915bf2..9c91edc2d0 100644 --- a/bazel/opentelemetry_proto.BUILD +++ b/bazel/opentelemetry_proto.BUILD @@ -15,6 +15,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_proto//proto:defs.bzl", "proto_library") +load("@com_github_grpc_grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library") proto_library( name = "common_proto", @@ -58,3 +59,26 @@ cc_proto_library( name = "trace_proto_cc", deps = [":trace_proto"], ) + +proto_library( + name = "trace_service_proto", + srcs = [ + "opentelemetry/proto/collector/trace/v1/trace_service.proto", + ], + deps = [ + ":trace_proto", + ], +) + +cc_proto_library( + name = "trace_service_proto_cc", + deps = [":trace_service_proto"], +) + +cc_grpc_library( + name = "trace_service_grpc_cc", + srcs = [":trace_service_proto"], + grpc_only = True, + deps = [":trace_service_proto_cc"], + generate_mocks = True, +) diff --git a/exporters/otlp/BUILD b/exporters/otlp/BUILD index fd1f048889..e8c4a8ae7f 100644 --- a/exporters/otlp/BUILD +++ b/exporters/otlp/BUILD @@ -29,6 +29,24 @@ cc_library( ], ) +cc_library( + name = "otlp_exporter", + srcs = [ + 'otlp_exporter.cc', + ], + hdrs = [ + 'otlp_exporter.h', + ], + deps = [ + ":recordable", + "//sdk/src/trace", + + # For gRPC + "@com_github_opentelemetry_proto//:trace_service_grpc_cc", + "@com_github_grpc_grpc//:grpc++", + ], +) + cc_test( name = "recordable_test", srcs = ["recordable_test.cc"], @@ -37,3 +55,13 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "otlp_exporter_test", + srcs = ["otlp_exporter_test.cc"], + deps = [ + ":otlp_exporter", + "//api", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/exporters/otlp/otlp_exporter.cc b/exporters/otlp/otlp_exporter.cc new file mode 100644 index 0000000000..951597044a --- /dev/null +++ b/exporters/otlp/otlp_exporter.cc @@ -0,0 +1,81 @@ +#include "otlp_exporter.h" +#include "recordable.h" + +#include +#include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ + +const std::string kCollectorAddress = "localhost:55678"; + +// ----------------------------- Helper functions ------------------------------ + +/** + * Add span protobufs contained in recordables to request. + * @param spans the spans to export + * @param request the current request + */ +void PopulateRequest(const nostd::span> &spans, + proto::collector::trace::v1::ExportTraceServiceRequest *request) +{ + auto resource_span = request->add_resource_spans(); + auto instrumentation_lib = resource_span->add_instrumentation_library_spans(); + + for (auto &recordable : spans) + { + auto rec = std::unique_ptr(static_cast(recordable.release())); + *instrumentation_lib->add_spans() = std::move(rec->span()); + } +} + +/** + * Create service stub to communicate with the OpenTelemetry Collector. + */ +std::unique_ptr MakeServiceStub() +{ + auto channel = grpc::CreateChannel(kCollectorAddress, grpc::InsecureChannelCredentials()); + return proto::collector::trace::v1::TraceService::NewStub(channel); +} + +// -------------------------------- Contructors -------------------------------- + +OtlpExporter::OtlpExporter() : OtlpExporter(MakeServiceStub()) {} + +OtlpExporter::OtlpExporter( + std::unique_ptr stub) + : trace_service_stub_(std::move(stub)) +{} + +// ----------------------------- Exporter methods ------------------------------ + +std::unique_ptr OtlpExporter::MakeRecordable() noexcept +{ + return std::unique_ptr(new Recordable); +} + +sdk::trace::ExportResult OtlpExporter::Export( + const nostd::span> &spans) noexcept +{ + proto::collector::trace::v1::ExportTraceServiceRequest request; + + PopulateRequest(spans, &request); + + grpc::ClientContext context; + proto::collector::trace::v1::ExportTraceServiceResponse response; + + grpc::Status status = trace_service_stub_->Export(&context, request, &response); + + if (!status.ok()) + { + std::cerr << "[OTLP Exporter] Export() failed: " << status.error_message() << "\n"; + return sdk::trace::ExportResult::kFailure; + } + return sdk::trace::ExportResult::kSuccess; +} +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/otlp/otlp_exporter.h b/exporters/otlp/otlp_exporter.h new file mode 100644 index 0000000000..4ac324f3ca --- /dev/null +++ b/exporters/otlp/otlp_exporter.h @@ -0,0 +1,59 @@ +#pragma once + +#include "opentelemetry/sdk/trace/exporter.h" +#include "opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ +/** + * The OTLP exporter exports span data in OpenTelemetry Protocol (OTLP) format. + */ +class OtlpExporter final : public opentelemetry::sdk::trace::SpanExporter +{ +public: + /** + * Create an OtlpExporter. This constructor initializes a service stub to be + * used for exporting. + */ + OtlpExporter(); + + /** + * Create a span recordable. + * @return a newly initialized Recordable object + */ + std::unique_ptr MakeRecordable() noexcept override; + + /** + * Export a batch of span recordables in OTLP format. + * @param spans a span of unique pointers to span recordables + */ + sdk::trace::ExportResult Export( + const nostd::span> &spans) noexcept override; + + /** + * Shut down the exporter. + * @param timeout an optional timeout, the default timeout of 0 means that no + * timeout is applied. + */ + void Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override {}; + +private: + // For testing + friend class OtlpExporterTestPeer; + + // Store service stub internally. Useful for testing. + std::unique_ptr trace_service_stub_; + + /** + * Create an OtlpExporter using the specified service stub. + * Only tests can call this constructor directly. + * @param stub the service stub to be used for exporting + */ + OtlpExporter(std::unique_ptr stub); +}; +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/otlp/otlp_exporter_test.cc b/exporters/otlp/otlp_exporter_test.cc new file mode 100644 index 0000000000..ea98357054 --- /dev/null +++ b/exporters/otlp/otlp_exporter_test.cc @@ -0,0 +1,81 @@ +#include "otlp_exporter.h" +#include "opentelemetry/proto/collector/trace/v1/trace_service_mock.grpc.pb.h" +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" + +#include + +using namespace testing; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ + +class OtlpExporterTestPeer : public ::testing::Test +{ +public: + std::unique_ptr GetExporter( + std::unique_ptr &stub_interface) + { + return std::unique_ptr(new OtlpExporter(std::move(stub_interface))); + } +}; + +// Call Export() directly +TEST_F(OtlpExporterTestPeer, ExportUnitTest) +{ + auto mock_stub = new proto::collector::trace::v1::MockTraceServiceStub(); + std::unique_ptr stub_interface( + mock_stub); + auto exporter = GetExporter(stub_interface); + + auto recordable_1 = exporter->MakeRecordable(); + recordable_1->SetName("Test span 1"); + auto recordable_2 = exporter->MakeRecordable(); + recordable_2->SetName("Test span 2"); + + // Test successful RPC + nostd::span> batch_1(&recordable_1, 1); + EXPECT_CALL(*mock_stub, Export(_, _, _)).Times(Exactly(1)).WillOnce(Return(grpc::Status::OK)); + auto result = exporter->Export(batch_1); + EXPECT_EQ(sdk::trace::ExportResult::kSuccess, result); + + // Test failed RPC + nostd::span> batch_2(&recordable_2, 1); + EXPECT_CALL(*mock_stub, Export(_, _, _)) + .Times(Exactly(1)) + .WillOnce(Return(grpc::Status::CANCELLED)); + result = exporter->Export(batch_2); + EXPECT_EQ(sdk::trace::ExportResult::kFailure, result); +} + +// Create spans, let processor call Export() +TEST_F(OtlpExporterTestPeer, ExportIntegrationTest) +{ + auto mock_stub = new proto::collector::trace::v1::MockTraceServiceStub(); + std::unique_ptr stub_interface( + mock_stub); + + auto exporter = GetExporter(stub_interface); + + auto processor = std::shared_ptr( + new sdk::trace::SimpleSpanProcessor(std::move(exporter))); + auto provider = + nostd::shared_ptr(new sdk::trace::TracerProvider(processor)); + auto tracer = provider->GetTracer("test"); + + EXPECT_CALL(*mock_stub, Export(_, _, _)) + .Times(AtLeast(1)) + .WillRepeatedly(Return(grpc::Status::OK)); + + auto parent_span = tracer->StartSpan("Test parent span"); + auto child_span = tracer->StartSpan("Test child span"); + child_span->End(); + parent_span->End(); +} +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE From a7480c81cde002bbcbeb31451885cc68bc250ffd Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Thu, 9 Jul 2020 20:03:37 +0000 Subject: [PATCH 27/42] changed variable name from attributes to values --- api/include/opentelemetry/context/context.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/include/opentelemetry/context/context.h b/api/include/opentelemetry/context/context.h index 35990e93e8..478f9324a2 100644 --- a/api/include/opentelemetry/context/context.h +++ b/api/include/opentelemetry/context/context.h @@ -46,15 +46,15 @@ class Context // Contructor, creates a context object from a map of keys // and identifiers. template ::value> * = nullptr> - Context(const T &attributes) + Context(const T values) {} // Accepts a new iterable and then returns a new context that // contains both the original pairs and the new pair. template ::value> * = nullptr> - Context WriteValues(T &attributes) noexcept + Context WriteValues(T &values) noexcept { - return Context(attributes); + return Context(values); } // Returns the value associated with the passed in key. From 96cd32f712da569ae4fe7c7ae4c89bc475b4cdb5 Mon Sep 17 00:00:00 2001 From: Sam Atac <65615762+satac2@users.noreply.github.com> Date: Thu, 9 Jul 2020 15:06:30 -0500 Subject: [PATCH 28/42] Update api/include/opentelemetry/context/context.h Co-authored-by: Reiley Yang --- api/include/opentelemetry/context/context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/include/opentelemetry/context/context.h b/api/include/opentelemetry/context/context.h index 478f9324a2..4c421c469d 100644 --- a/api/include/opentelemetry/context/context.h +++ b/api/include/opentelemetry/context/context.h @@ -49,7 +49,7 @@ class Context Context(const T values) {} - // Accepts a new iterable and then returns a new context that + // Accepts a new iterable and then returns a new context that // contains both the original pairs and the new pair. template ::value> * = nullptr> Context WriteValues(T &values) noexcept From d2f979b6bd215f77e48b9a3c6661fdbb6c22bbd4 Mon Sep 17 00:00:00 2001 From: Oliver Zhang <30583106+ziqizh@users.noreply.github.com> Date: Thu, 9 Jul 2020 17:42:22 -0400 Subject: [PATCH 29/42] Parent-or-else Sampler (#142) --- .../sdk/trace/samplers/parent_or_else.h | 57 +++++++++++++++++++ sdk/src/trace/CMakeLists.txt | 2 +- sdk/src/trace/samplers/parent_or_else.cc | 41 +++++++++++++ sdk/test/trace/BUILD | 15 ++++- sdk/test/trace/CMakeLists.txt | 3 +- sdk/test/trace/parent_or_else_sampler_test.cc | 50 ++++++++++++++++ 6 files changed, 163 insertions(+), 5 deletions(-) create mode 100644 sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h create mode 100644 sdk/src/trace/samplers/parent_or_else.cc create mode 100644 sdk/test/trace/parent_or_else_sampler_test.cc diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h b/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h new file mode 100644 index 0000000000..c562277957 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h @@ -0,0 +1,57 @@ +#pragma once + +#include "opentelemetry/sdk/common/atomic_shared_ptr.h" +#include "opentelemetry/sdk/trace/sampler.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace trace +{ +namespace trace_api = opentelemetry::trace; + +/** + * A placeholder class that stores the states of a span. + * Will be replaced by the real SpanContext class once it is implemented. + */ +class Sampler::SpanContext +{ +public: + inline explicit SpanContext(bool is_recording, bool sampled_flag) + : is_recording(is_recording), sampled_flag(sampled_flag) + {} + + bool is_recording; + bool sampled_flag; +}; + +/** + * The parent or else sampler is a composite sampler. ParentOrElse(delegateSampler) either respects + * the parent span's sampling decision or delegates to delegateSampler for root spans. + */ +class ParentOrElseSampler : public Sampler +{ +public: + explicit ParentOrElseSampler(std::shared_ptr delegate_sampler) noexcept; + /** The decision either respects the parent span's sampling decision or delegates to + * delegateSampler for root spans + * @return Returns NOT_RECORD always + */ + SamplingResult ShouldSample(const SpanContext * parent_context, + trace_api::TraceId trace_id, + nostd::string_view name, + trace_api::SpanKind span_kind, + const trace_api::KeyValueIterable & attributes) noexcept override; + + /** + * @return Description MUST be ParentOrElse{delegate_sampler_.getDescription()} + */ + std::string GetDescription() const noexcept override; + +private: + const std::shared_ptr delegate_sampler_; + const std::string description_; +}; +} // namespace trace +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/src/trace/CMakeLists.txt b/sdk/src/trace/CMakeLists.txt index 455665be68..98f949997e 100644 --- a/sdk/src/trace/CMakeLists.txt +++ b/sdk/src/trace/CMakeLists.txt @@ -1 +1 @@ -add_library(opentelemetry_trace tracer_provider.cc tracer.cc span.cc) +add_library(opentelemetry_trace tracer_provider.cc tracer.cc span.cc samplers/parent_or_else.cc) diff --git a/sdk/src/trace/samplers/parent_or_else.cc b/sdk/src/trace/samplers/parent_or_else.cc new file mode 100644 index 0000000000..fd0d909e84 --- /dev/null +++ b/sdk/src/trace/samplers/parent_or_else.cc @@ -0,0 +1,41 @@ +#include "opentelemetry/sdk/trace/samplers/parent_or_else.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace trace +{ +ParentOrElseSampler::ParentOrElseSampler(std::shared_ptr delegate_sampler) noexcept + : delegate_sampler_(delegate_sampler), + description_("ParentOrElse{" + delegate_sampler->GetDescription() + "}") +{} + +SamplingResult ParentOrElseSampler::ShouldSample( + const SpanContext *parent_context, + trace_api::TraceId trace_id, + nostd::string_view name, + trace_api::SpanKind span_kind, + const trace_api::KeyValueIterable &attributes) noexcept +{ + if (parent_context == nullptr) + { + // If no parent (root span) exists returns the result of the delegateSampler + return delegate_sampler_->ShouldSample(parent_context, trace_id, name, span_kind, attributes); + } + + // If parent exists: + if (parent_context->sampled_flag) + { + return {Decision::RECORD_AND_SAMPLE, nullptr}; + } + + return {Decision::NOT_RECORD, nullptr}; +} + +std::string ParentOrElseSampler::GetDescription() const noexcept +{ + return description_; +} +} // namespace trace +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/test/trace/BUILD b/sdk/test/trace/BUILD index 37018d7eeb..a3c3c77f91 100644 --- a/sdk/test/trace/BUILD +++ b/sdk/test/trace/BUILD @@ -53,8 +53,6 @@ cc_test( ], ) - - cc_test( name = "always_off_sampler_test", srcs = [ @@ -64,4 +62,15 @@ cc_test( "//sdk/src/trace", "@com_google_googletest//:gtest_main", ], -) \ No newline at end of file +) + +cc_test( + name = "parent_or_else_sampler_test", + srcs = [ + "parent_or_else_sampler_test.cc", + ], + deps = [ + "//sdk/src/trace", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/sdk/test/trace/CMakeLists.txt b/sdk/test/trace/CMakeLists.txt index 75bfd4f97a..b4524da0f2 100644 --- a/sdk/test/trace/CMakeLists.txt +++ b/sdk/test/trace/CMakeLists.txt @@ -1,5 +1,6 @@ foreach(testname tracer_provider_test span_data_test simple_processor_test - tracer_test always_off_sampler_test always_on_sampler_test) + tracer_test always_off_sampler_test always_on_sampler_test + parent_or_else_sampler_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_trace) diff --git a/sdk/test/trace/parent_or_else_sampler_test.cc b/sdk/test/trace/parent_or_else_sampler_test.cc new file mode 100644 index 0000000000..152121f4c3 --- /dev/null +++ b/sdk/test/trace/parent_or_else_sampler_test.cc @@ -0,0 +1,50 @@ +#include +#include +#include "opentelemetry/sdk/trace/samplers/always_off.h" +#include "opentelemetry/sdk/trace/samplers/always_on.h" +#include "opentelemetry/sdk/trace/samplers/parent_or_else.h" + +using opentelemetry::sdk::trace::AlwaysOffSampler; +using opentelemetry::sdk::trace::AlwaysOnSampler; +using opentelemetry::sdk::trace::Decision; +using opentelemetry::sdk::trace::ParentOrElseSampler; + +TEST(ParentOrElseSampler, ShouldSample) +{ + ParentOrElseSampler sampler_off(std::make_shared()); + ParentOrElseSampler sampler_on(std::make_shared()); + + // Set up parameters + opentelemetry::trace::TraceId trace_id; + opentelemetry::trace::SpanKind span_kind = opentelemetry::trace::SpanKind::kInternal; + using M = std::map; + M m1 = {{}}; + opentelemetry::trace::KeyValueIterableView view{m1}; + opentelemetry::sdk::trace::Sampler::SpanContext parent_context_sampled(true, true); + opentelemetry::sdk::trace::Sampler::SpanContext parent_context_nonsampled(true, false); + + // Case 1: Parent doesn't exist. Return result of delegateSampler() + auto sampling_result = sampler_off.ShouldSample(nullptr, trace_id, "", span_kind, view); + auto sampling_result2 = sampler_on.ShouldSample(nullptr, trace_id, "", span_kind, view); + + ASSERT_EQ(Decision::NOT_RECORD, sampling_result.decision); + ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result2.decision); + + // Case 2: Parent exists and SampledFlag is true + auto sampling_result3 = + sampler_off.ShouldSample(&parent_context_sampled, trace_id, "", span_kind, view); + ASSERT_EQ(Decision::RECORD_AND_SAMPLE, sampling_result3.decision); + + // Case 3: Parent exists and SampledFlag is false + auto sampling_result4 = + sampler_on.ShouldSample(&parent_context_nonsampled, trace_id, "", span_kind, view); + ASSERT_EQ(Decision::NOT_RECORD, sampling_result4.decision); +} + +TEST(ParentOrElseSampler, GetDescription) +{ + ParentOrElseSampler sampler(std::make_shared()); + ASSERT_EQ("ParentOrElse{AlwaysOffSampler}", sampler.GetDescription()); + ParentOrElseSampler sampler2(std::make_shared()); + ASSERT_EQ("ParentOrElse{AlwaysOnSampler}", sampler2.GetDescription()); +} From 9aa4797a6c06de7a4bd30e7baf7cfeb18f20451a Mon Sep 17 00:00:00 2001 From: Johannes Tax Date: Fri, 10 Jul 2020 11:08:04 -0700 Subject: [PATCH 30/42] Don't move a constant AttributeValue (#141) --- api/include/opentelemetry/plugin/tracer.h | 4 ++-- api/include/opentelemetry/trace/noop.h | 2 +- api/include/opentelemetry/trace/span.h | 2 +- api/test/trace/noop_test.cc | 2 ++ examples/plugin/plugin/tracer.cc | 2 +- exporters/otlp/recordable.cc | 2 +- exporters/otlp/recordable.h | 2 +- .../opentelemetry/sdk/trace/recordable.h | 2 +- .../opentelemetry/sdk/trace/span_data.h | 2 +- sdk/src/trace/span.cc | 6 ++--- sdk/src/trace/span.h | 2 +- sdk/test/trace/tracer_test.cc | 24 +++++++++++++++---- 12 files changed, 35 insertions(+), 17 deletions(-) diff --git a/api/include/opentelemetry/plugin/tracer.h b/api/include/opentelemetry/plugin/tracer.h index 9970e5a533..e2f8bc79f8 100644 --- a/api/include/opentelemetry/plugin/tracer.h +++ b/api/include/opentelemetry/plugin/tracer.h @@ -18,9 +18,9 @@ class Span final : public trace::Span {} // trace::Span - void SetAttribute(nostd::string_view name, const common::AttributeValue &&value) noexcept override + void SetAttribute(nostd::string_view name, const common::AttributeValue &value) noexcept override { - span_->SetAttribute(name, std::move(value)); + span_->SetAttribute(name, value); } void AddEvent(nostd::string_view name) noexcept override { span_->AddEvent(name); } diff --git a/api/include/opentelemetry/trace/noop.h b/api/include/opentelemetry/trace/noop.h index fbb0e0cb68..2d353489d0 100644 --- a/api/include/opentelemetry/trace/noop.h +++ b/api/include/opentelemetry/trace/noop.h @@ -25,7 +25,7 @@ class NoopSpan final : public Span explicit NoopSpan(const std::shared_ptr &tracer) noexcept : tracer_{tracer} {} void SetAttribute(nostd::string_view /*key*/, - const common::AttributeValue && /*value*/) noexcept override + const common::AttributeValue & /*value*/) noexcept override {} void AddEvent(nostd::string_view /*name*/) noexcept override {} diff --git a/api/include/opentelemetry/trace/span.h b/api/include/opentelemetry/trace/span.h index 77265387e6..1f8ae415a9 100644 --- a/api/include/opentelemetry/trace/span.h +++ b/api/include/opentelemetry/trace/span.h @@ -77,7 +77,7 @@ class Span // Sets an attribute on the Span. If the Span previously contained a mapping for // the key, the old value is replaced. virtual void SetAttribute(nostd::string_view key, - const common::AttributeValue &&value) noexcept = 0; + const common::AttributeValue &value) noexcept = 0; // Adds an event to the Span. virtual void AddEvent(nostd::string_view name) noexcept = 0; diff --git a/api/test/trace/noop_test.cc b/api/test/trace/noop_test.cc index 6dad65323b..945a333f33 100644 --- a/api/test/trace/noop_test.cc +++ b/api/test/trace/noop_test.cc @@ -25,4 +25,6 @@ TEST(NoopTest, UseNoopTracers) std::vector>> attributes3; s1->AddEvent("abc", attributes3); + + s1->SetAttribute("abc", 4); } diff --git a/examples/plugin/plugin/tracer.cc b/examples/plugin/plugin/tracer.cc index 3aa68e8b15..f054da7f03 100644 --- a/examples/plugin/plugin/tracer.cc +++ b/examples/plugin/plugin/tracer.cc @@ -25,7 +25,7 @@ class Span final : public trace::Span // opentelemetry::trace::Span void SetAttribute(nostd::string_view /*name*/, - const common::AttributeValue && /*value*/) noexcept override + const common::AttributeValue & /*value*/) noexcept override {} void AddEvent(nostd::string_view /*name*/) noexcept override {} diff --git a/exporters/otlp/recordable.cc b/exporters/otlp/recordable.cc index 1677bb6be1..6092c0f005 100644 --- a/exporters/otlp/recordable.cc +++ b/exporters/otlp/recordable.cc @@ -16,7 +16,7 @@ void Recordable::SetIds(trace::TraceId trace_id, } void Recordable::SetAttribute(nostd::string_view key, - const opentelemetry::common::AttributeValue &&value) noexcept + const opentelemetry::common::AttributeValue &value) noexcept { (void)key; (void)value; diff --git a/exporters/otlp/recordable.h b/exporters/otlp/recordable.h index 8490bc9141..9d55dfd404 100644 --- a/exporters/otlp/recordable.h +++ b/exporters/otlp/recordable.h @@ -19,7 +19,7 @@ class Recordable final : public sdk::trace::Recordable trace::SpanId parent_span_id) noexcept override; void SetAttribute(nostd::string_view key, - const opentelemetry::common::AttributeValue &&value) noexcept override; + const opentelemetry::common::AttributeValue &value) noexcept override; void AddEvent(nostd::string_view name, core::SystemTimestamp timestamp) noexcept override; diff --git a/sdk/include/opentelemetry/sdk/trace/recordable.h b/sdk/include/opentelemetry/sdk/trace/recordable.h index d901dbfa54..a2ac8984dc 100644 --- a/sdk/include/opentelemetry/sdk/trace/recordable.h +++ b/sdk/include/opentelemetry/sdk/trace/recordable.h @@ -40,7 +40,7 @@ class Recordable * @param value the attribute value */ virtual void SetAttribute(nostd::string_view key, - const opentelemetry::common::AttributeValue &&value) noexcept = 0; + const opentelemetry::common::AttributeValue &value) noexcept = 0; /** * Add an event to a span. diff --git a/sdk/include/opentelemetry/sdk/trace/span_data.h b/sdk/include/opentelemetry/sdk/trace/span_data.h index c3b557dc9b..54ef9bcd02 100644 --- a/sdk/include/opentelemetry/sdk/trace/span_data.h +++ b/sdk/include/opentelemetry/sdk/trace/span_data.h @@ -86,7 +86,7 @@ class SpanData final : public Recordable parent_span_id_ = parent_span_id; } - void SetAttribute(nostd::string_view key, const common::AttributeValue &&value) noexcept override + void SetAttribute(nostd::string_view key, const common::AttributeValue &value) noexcept override { attributes_[std::string(key)] = value; } diff --git a/sdk/src/trace/span.cc b/sdk/src/trace/span.cc index dde8710ec2..96154a2799 100644 --- a/sdk/src/trace/span.cc +++ b/sdk/src/trace/span.cc @@ -57,7 +57,7 @@ Span::Span(std::shared_ptr &&tracer, recordable_->SetName(name); attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept { - recordable_->SetAttribute(key, std::move(value)); + recordable_->SetAttribute(key, value); return true; }); @@ -70,11 +70,11 @@ Span::~Span() End(); } -void Span::SetAttribute(nostd::string_view key, const common::AttributeValue &&value) noexcept +void Span::SetAttribute(nostd::string_view key, const common::AttributeValue &value) noexcept { std::lock_guard lock_guard{mu_}; - recordable_->SetAttribute(key, std::move(value)); + recordable_->SetAttribute(key, value); } void Span::AddEvent(nostd::string_view name) noexcept diff --git a/sdk/src/trace/span.h b/sdk/src/trace/span.h index db8d01ab4e..489833703c 100644 --- a/sdk/src/trace/span.h +++ b/sdk/src/trace/span.h @@ -24,7 +24,7 @@ class Span final : public trace_api::Span ~Span() override; // trace_api::Span - void SetAttribute(nostd::string_view key, const common::AttributeValue &&value) noexcept override; + void SetAttribute(nostd::string_view key, const common::AttributeValue &value) noexcept override; void AddEvent(nostd::string_view name) noexcept override; diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index 2c6b891818..75011db536 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -1,7 +1,7 @@ #include "opentelemetry/sdk/trace/tracer.h" -#include "opentelemetry/sdk/trace/simple_processor.h" -#include "opentelemetry/sdk/trace/samplers/always_on.h" #include "opentelemetry/sdk/trace/samplers/always_off.h" +#include "opentelemetry/sdk/trace/samplers/always_on.h" +#include "opentelemetry/sdk/trace/simple_processor.h" #include "opentelemetry/sdk/trace/span_data.h" #include @@ -142,7 +142,6 @@ TEST(Tracer, StartSpanWithAttributes) ASSERT_EQ(3.0, nostd::get(span_data2->GetAttributes().at("attr3"))); } - TEST(Tracer, GetSampler) { // Create a Tracer with a default AlwaysOnSampler @@ -154,8 +153,25 @@ TEST(Tracer, GetSampler) // Create a Tracer with a AlwaysOffSampler std::shared_ptr processor_2(new SimpleSpanProcessor(nullptr)); - std::shared_ptr tracer_off(new Tracer(std::move(processor_2), std::make_shared())); + std::shared_ptr tracer_off( + new Tracer(std::move(processor_2), std::make_shared())); auto t2 = tracer_off->GetSampler(); ASSERT_EQ("AlwaysOffSampler", t2->GetDescription()); } + +TEST(Tracer, SpanSetAttribute) +{ + std::shared_ptr>> spans_received( + new std::vector>); + auto tracer = initTracer(spans_received); + + auto span = tracer->StartSpan("span 1"); + + span->SetAttribute("abc", 3.1); + + span->End(); + ASSERT_EQ(1, spans_received->size()); + auto &span_data = spans_received->at(0); + ASSERT_EQ(3.1, nostd::get(span_data->GetAttributes().at("abc"))); +} From af0a946137fe253aeeaca4ad18ec94c663ab96ca Mon Sep 17 00:00:00 2001 From: Nadia Ciobanu Date: Fri, 10 Jul 2020 13:12:09 -0700 Subject: [PATCH 31/42] Add benchmark tests for OTLP exporter (#163) --- exporters/otlp/BUILD | 10 ++ exporters/otlp/otlp_exporter_benchmark.cc | 165 ++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 exporters/otlp/otlp_exporter_benchmark.cc diff --git a/exporters/otlp/BUILD b/exporters/otlp/BUILD index e8c4a8ae7f..2132ee99c9 100644 --- a/exporters/otlp/BUILD +++ b/exporters/otlp/BUILD @@ -14,6 +14,8 @@ package(default_visibility = ["//visibility:public"]) +load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") + cc_library( name = "recordable", srcs = [ @@ -65,3 +67,11 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +otel_cc_benchmark( + name = "otlp_exporter_benchmark", + srcs = ["otlp_exporter_benchmark.cc"], + deps = [ + ":otlp_exporter", + ], +) diff --git a/exporters/otlp/otlp_exporter_benchmark.cc b/exporters/otlp/otlp_exporter_benchmark.cc new file mode 100644 index 0000000000..81205dd1b3 --- /dev/null +++ b/exporters/otlp/otlp_exporter_benchmark.cc @@ -0,0 +1,165 @@ +#include +#include "otlp_exporter.h" +#include "recordable.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ + +const int kBatchSize = 200; +const int kNumAttributes = 5; +const int kNumIterations = 1000; + +const trace::TraceId kTraceId(std::array( + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})); +const trace::SpanId kSpanId(std::array( + {0, 0, 0, 0, 0, 0, 0, 2})); +const trace::SpanId kParentSpanId(std::array( + {0, 0, 0, 0, 0, 0, 0, 3})); + +// ----------------------- Helper classes and functions ------------------------ + +// Create a fake service stub to avoid dependency on gmock +class FakeServiceStub : public proto::collector::trace::v1::TraceService::StubInterface +{ + grpc::Status Export(grpc::ClientContext *, + const proto::collector::trace::v1::ExportTraceServiceRequest &, + proto::collector::trace::v1::ExportTraceServiceResponse *) override + { + return grpc::Status::OK; + } + + grpc::ClientAsyncResponseReaderInterface + *AsyncExportRaw(grpc::ClientContext *, + const proto::collector::trace::v1::ExportTraceServiceRequest &, + grpc::CompletionQueue *) override + { + return nullptr; + } + + grpc::ClientAsyncResponseReaderInterface + *PrepareAsyncExportRaw(grpc::ClientContext *, + const proto::collector::trace::v1::ExportTraceServiceRequest &, + grpc::CompletionQueue *) override + { + return nullptr; + } +}; + +// OtlpExporterTestPeer is a friend class of OtlpExporter +class OtlpExporterTestPeer +{ +public: + std::unique_ptr GetExporter() + { + auto mock_stub = new FakeServiceStub(); + std::unique_ptr stub_interface( + mock_stub); + return std::unique_ptr( + new exporter::otlp::OtlpExporter(std::move(stub_interface))); + } +}; + +// Helper function to create empty spans +void CreateEmptySpans(std::array, kBatchSize> &recordables) +{ + for (int i = 0; i < kBatchSize; i++) + { + auto recordable = std::unique_ptr(new Recordable); + recordables[i] = std::move(recordable); + } +} + +// Helper function to create sparse spans +void CreateSparseSpans(std::array, kBatchSize> &recordables) +{ + for (int i = 0; i < kBatchSize; i++) + { + auto recordable = std::unique_ptr(new Recordable); + + recordable->SetIds(kTraceId, kSpanId, kParentSpanId); + recordable->SetName("TestSpan"); + recordable->SetStartTime(core::SystemTimestamp(std::chrono::system_clock::now())); + recordable->SetDuration(std::chrono::nanoseconds(10)); + + recordables[i] = std::move(recordable); + } +} + +// Helper function to create dense spans +void CreateDenseSpans(std::array, kBatchSize> &recordables) +{ + for (int i = 0; i < kBatchSize; i++) + { + auto recordable = std::unique_ptr(new Recordable); + + recordable->SetIds(kTraceId, kSpanId, kParentSpanId); + recordable->SetName("TestSpan"); + recordable->SetStartTime(core::SystemTimestamp(std::chrono::system_clock::now())); + recordable->SetDuration(std::chrono::nanoseconds(10)); + + for (int i = 0; i < kNumAttributes; i++) + { + recordable->SetAttribute("int_key_" + i, static_cast(i)); + recordable->SetAttribute("str_key_" + i, "string_val_" + i); + recordable->SetAttribute("bool_key_" + i, true); + } + + recordables[i] = std::move(recordable); + } +} + +// ------------------------------ Benchmark tests ------------------------------ + +// Benchmark Export() with empty spans +void BM_OtlpExporterEmptySpans(benchmark::State &state) +{ + std::unique_ptr testpeer(new OtlpExporterTestPeer()); + auto exporter = testpeer->GetExporter(); + + while(state.KeepRunningBatch(kNumIterations)) + { + std::array, kBatchSize> recordables; + CreateEmptySpans(recordables); + exporter->Export(nostd::span>(recordables)); + } +} +BENCHMARK(BM_OtlpExporterEmptySpans); + +// Benchmark Export() with sparse spans +void BM_OtlpExporterSparseSpans(benchmark::State &state) +{ + std::unique_ptr testpeer(new OtlpExporterTestPeer()); + auto exporter = testpeer->GetExporter(); + + while(state.KeepRunningBatch(kNumIterations)) + { + std::array, kBatchSize> recordables; + CreateSparseSpans(recordables); + exporter->Export(nostd::span>(recordables)); + } +} +BENCHMARK(BM_OtlpExporterSparseSpans); + +// Benchmark Export() with dense spans +void BM_OtlpExporterDenseSpans(benchmark::State &state) +{ + std::unique_ptr testpeer(new OtlpExporterTestPeer()); + auto exporter = testpeer->GetExporter(); + + while(state.KeepRunningBatch(kNumIterations)) + { + std::array, kBatchSize> recordables; + CreateDenseSpans(recordables); + exporter->Export(nostd::span>(recordables)); + } +} +BENCHMARK(BM_OtlpExporterDenseSpans); + +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE + +BENCHMARK_MAIN(); From 5f0634bed72bd93a56555f3291d0bc99220f2879 Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Mon, 13 Jul 2020 04:02:35 +0000 Subject: [PATCH 32/42] changed to follow the spec and added context_value type --- api/include/opentelemetry/context/context.h | 117 ++++++++++-------- .../opentelemetry/context/context_value.h | 28 +++++ api/test/context/context_test.cc | 70 +++++------ 3 files changed, 124 insertions(+), 91 deletions(-) create mode 100644 api/include/opentelemetry/context/context_value.h diff --git a/api/include/opentelemetry/context/context.h b/api/include/opentelemetry/context/context.h index 478f9324a2..9ac35c226c 100644 --- a/api/include/opentelemetry/context/context.h +++ b/api/include/opentelemetry/context/context.h @@ -1,69 +1,78 @@ #pragma once #include "opentelemetry/common/attribute_value.h" +#include "opentelemetry/context/context_value.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/trace/key_value_iterable_view.h" +#include +#include + OPENTELEMETRY_BEGIN_NAMESPACE namespace context { -// The context class provides a context identifier. -// This is a dummy class that is meant to be overridden, -// the methods return default values. -class Context -{ - -public: - // The Key class is used to obscure access from the - // user to the context map. The identifier is used as a key - // to the context map. - class Key + // The context class provides a context identifier. + // This is a dummy class that is meant to be overridden, + // the methods return default values. + class Context { - public: - // Returns the key's identifier. - nostd::string_view GetIdentifier() { return ""; } - - // Returns the key's name - nostd::string_view GetName() { return ""; } - - Key() = default; - - // Constructs a new Key with the passed in name. Sets the identifier as - // the address of this object. - Key(nostd::string_view key_name) {} - - private: - friend class Context; + public: + + Context() = default; + + // Contructor, creates a context object from a map of keys + // and identifiers. + template ::value> * = nullptr> + Context(const T keys_and_values) + { + trace::KeyValueIterableView iterable{keys_and_values}; + iterable.ForEachKeyValue([&](nostd::string_view key, context::ContextValue value) noexcept { + context_map_[std::string(key)] = value; + return true; + }); + + } + + // Accepts a key and a value and then returns a new context that + // contains both the original pairs and the new pair. + template + Context SetValue(nostd::string_view key, T &value) noexcept + { + std::map context_map_copy = context_map_; + context_map_copy[std::string(key)] = value; + return Context(context_map_copy); + } + + // Accepts a new iterable and then returns a new context that + // contains both the original pairs and the new pair. + template ::value> * = nullptr> + Context SetValues(T &keys_and_values) noexcept + { + std::map context_map_copy = context_map_; + trace::KeyValueIterableView iterable{keys_and_values}; + + iterable.ForEachKeyValue([&](nostd::string_view key, context::ContextValue value) noexcept { + context_map_copy[std::string(key)] = value; + return true; + }); + + return Context(context_map_copy); + } + + // Returns the value associated with the passed in key. + context::ContextValue GetValue(nostd::string_view key) { + return context_map_[std::string(key)]; + } + + // Copy Constructors. + Context(const Context &other) = default; + Context &operator=(const Context &other) = default; + + private: + + std::map context_map_; }; - - // Creates a key with the passed in name and returns it. - Key CreateKey(nostd::string_view key_name) { return Key(key_name); } - - Context() = default; - - // Contructor, creates a context object from a map of keys - // and identifiers. - template ::value> * = nullptr> - Context(const T values) - {} - - // Accepts a new iterable and then returns a new context that - // contains both the original pairs and the new pair. - template ::value> * = nullptr> - Context WriteValues(T &values) noexcept - { - return Context(values); - } - - // Returns the value associated with the passed in key. - virtual common::AttributeValue GetValue(Key key) { return 0; } - - // Copy Constructors. - Context(const Context &other) = default; - Context &operator=(const Context &other) = default; -}; - } // namespace context OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/context/context_value.h b/api/include/opentelemetry/context/context_value.h new file mode 100644 index 0000000000..e4b966a4d9 --- /dev/null +++ b/api/include/opentelemetry/context/context_value.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "opentelemetry/nostd/span.h" +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/nostd/variant.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace context +{ + using ContextValue = nostd::variant, + nostd::span, + nostd::span, + nostd::span, + nostd::span, + nostd::span, + nostd::span>; +} // namespace common +OPENTELEMETRY_END_NAMESPACE diff --git a/api/test/context/context_test.cc b/api/test/context/context_test.cc index 5ed00f81a8..065be7f5be 100644 --- a/api/test/context/context_test.cc +++ b/api/test/context/context_test.cc @@ -6,58 +6,54 @@ using namespace opentelemetry; -// Tests that the context default constructor does not cause a crash -TEST(ContextTest, ContextDefaultConstructorCrash) -{ - context::Context context_test = context::Context(); -} -// Tests that the context constructor does not cause a crash when a map -// is provided. -TEST(ContextTest, ContextIterableConstructorCrash) +// Tests that the context constructor accepts an std::map +TEST(ContextTest, ContextIterableAcceptsMap) { - std::map map_test = {{"test_key", "123"}}; + std::map map_test = {{"test_key", "123"}}; context::Context context_test = context::Context(map_test); } -// Tests that the WriteValues method does not crash -TEST(ContextTest, ContextWriteValuesCrash) +// Tests that the GetValue method returns the expected value +TEST(ContextTest, ContextGetValueReturnsExpectedValue) { - std::map map_test = {{"test_key", "123"}}; - std::map map_test_write = {{"foo_key", "456"}}; + std::map map_test = {{"test_key", "123"},{"foo_key", "456"}}; + context::Context context_test = context::Context(map_test); - context_test.WriteValues(map_test_write); + EXPECT_EQ(nostd::get(context_test.GetValue("test_key")), "123"); + EXPECT_EQ(nostd::get(context_test.GetValue("foo_key")), "456"); } -// Tests that the CreateKey method does not crash -TEST(ContextTest, ContextCreateKeyCrash) +// Tests that the SetValues method accepts an std::map +TEST(ContextTest, ContextSetValuesAcceptsMap) { - context::Context context_test; - context::Context::Key test_key = context_test.CreateKey("key_name"); -} - -// Tests that the GetValue method does not crash -TEST(ContextTest, ContextGetValueCrash) -{ - std::map map_test = {{"test_key", "123"}}; - std::map map_test_write = {{"foo_key", "456"}}; + std::map map_test = {{"test_key", "123"}}; + std::map map_test_write = {{"foo_key", "456"}}; context::Context context_test = context::Context(map_test); - context::Context::Key test_key = context_test.CreateKey("key_name"); - EXPECT_EQ(nostd::get(context_test.GetValue(test_key)), 0); + context::Context foo_test = context_test.SetValues(map_test_write); + EXPECT_EQ(nostd::get(foo_test.GetValue("test_key")), "123"); + EXPECT_EQ(nostd::get(foo_test.GetValue("foo_key")), "456"); } -// Tests that the Context::Key GetIdentifier method does not crash -TEST(ContextTest, ContextKeyGetIdentifierCrash) +// Tests that the SetValues method accepts a nostd::string_view and +// context::ContextValue +TEST(ContextTest, ContextSetValuesAcceptsStringViewContextValue) { - context::Context context_test; - context::Context::Key test_key = context_test.CreateKey("key_name"); - EXPECT_EQ(test_key.GetIdentifier(), ""); + nostd::string_view string_view_test = "string_view"; + context::ContextValue context_value_test = "123"; + context::Context context_test = context::Context(); + context::Context foo_test = context_test.SetValue(string_view_test, context_value_test); + EXPECT_EQ(nostd::get(foo_test.GetValue(string_view_test)), "123"); } -// Tests that the Context::Key GetName method does not crash -TEST(ContextTest, ContextKeyGetNameCrash) +// Tests that the original context does not change when a value is +// written to it +TEST(ContextTest, ContextImmutability) { - context::Context context_test; - context::Context::Key test_key = context_test.CreateKey("key_name"); - EXPECT_EQ(test_key.GetName(), ""); + std::map map_test = {{"test_key", "123"}}; + context::Context context_test = context::Context(map_test); + + context::Context context_foo = context_test.SetValue("foo_key", "456"); + + EXPECT_THROW(nostd::get(context_test.GetValue("foo_key")), nostd::bad_variant_access); } From 68a1a70a57f33a6c2996dcaf589dd13c2d883593 Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Mon, 13 Jul 2020 14:14:54 +0000 Subject: [PATCH 33/42] removed tests for this PR --- api/test/context/context_test.cc | 59 -------------------------------- 1 file changed, 59 deletions(-) delete mode 100644 api/test/context/context_test.cc diff --git a/api/test/context/context_test.cc b/api/test/context/context_test.cc deleted file mode 100644 index 065be7f5be..0000000000 --- a/api/test/context/context_test.cc +++ /dev/null @@ -1,59 +0,0 @@ -#include "opentelemetry/context/context.h" - -#include - -#include - -using namespace opentelemetry; - - -// Tests that the context constructor accepts an std::map -TEST(ContextTest, ContextIterableAcceptsMap) -{ - std::map map_test = {{"test_key", "123"}}; - context::Context context_test = context::Context(map_test); -} - -// Tests that the GetValue method returns the expected value -TEST(ContextTest, ContextGetValueReturnsExpectedValue) -{ - std::map map_test = {{"test_key", "123"},{"foo_key", "456"}}; - - context::Context context_test = context::Context(map_test); - EXPECT_EQ(nostd::get(context_test.GetValue("test_key")), "123"); - EXPECT_EQ(nostd::get(context_test.GetValue("foo_key")), "456"); -} - -// Tests that the SetValues method accepts an std::map -TEST(ContextTest, ContextSetValuesAcceptsMap) -{ - std::map map_test = {{"test_key", "123"}}; - std::map map_test_write = {{"foo_key", "456"}}; - context::Context context_test = context::Context(map_test); - context::Context foo_test = context_test.SetValues(map_test_write); - EXPECT_EQ(nostd::get(foo_test.GetValue("test_key")), "123"); - EXPECT_EQ(nostd::get(foo_test.GetValue("foo_key")), "456"); -} - -// Tests that the SetValues method accepts a nostd::string_view and -// context::ContextValue -TEST(ContextTest, ContextSetValuesAcceptsStringViewContextValue) -{ - nostd::string_view string_view_test = "string_view"; - context::ContextValue context_value_test = "123"; - context::Context context_test = context::Context(); - context::Context foo_test = context_test.SetValue(string_view_test, context_value_test); - EXPECT_EQ(nostd::get(foo_test.GetValue(string_view_test)), "123"); -} - -// Tests that the original context does not change when a value is -// written to it -TEST(ContextTest, ContextImmutability) -{ - std::map map_test = {{"test_key", "123"}}; - context::Context context_test = context::Context(map_test); - - context::Context context_foo = context_test.SetValue("foo_key", "456"); - - EXPECT_THROW(nostd::get(context_test.GetValue("foo_key")), nostd::bad_variant_access); -} From 5e685743b98d65e6c909def3f1c3ad6bf34192de Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Mon, 13 Jul 2020 14:44:59 +0000 Subject: [PATCH 34/42] removed line --- api/include/opentelemetry/context/context.h | 1 - 1 file changed, 1 deletion(-) diff --git a/api/include/opentelemetry/context/context.h b/api/include/opentelemetry/context/context.h index 9ac35c226c..e5745c9a10 100644 --- a/api/include/opentelemetry/context/context.h +++ b/api/include/opentelemetry/context/context.h @@ -32,7 +32,6 @@ namespace context context_map_[std::string(key)] = value; return true; }); - } // Accepts a key and a value and then returns a new context that From 16a492ee65c021ffe933b1e57f08dd20e6e55f71 Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Mon, 13 Jul 2020 14:45:59 +0000 Subject: [PATCH 35/42] removed unnecessary include --- api/include/opentelemetry/context/context.h | 1 - 1 file changed, 1 deletion(-) diff --git a/api/include/opentelemetry/context/context.h b/api/include/opentelemetry/context/context.h index e5745c9a10..ecef96cd09 100644 --- a/api/include/opentelemetry/context/context.h +++ b/api/include/opentelemetry/context/context.h @@ -5,7 +5,6 @@ #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/trace/key_value_iterable_view.h" -#include #include OPENTELEMETRY_BEGIN_NAMESPACE From 497eb67c71567d52daee49a341d90766823d206b Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Mon, 13 Jul 2020 14:49:06 +0000 Subject: [PATCH 36/42] changed a function to pass by reference --- api/include/opentelemetry/context/context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/include/opentelemetry/context/context.h b/api/include/opentelemetry/context/context.h index ecef96cd09..968476c2b8 100644 --- a/api/include/opentelemetry/context/context.h +++ b/api/include/opentelemetry/context/context.h @@ -24,7 +24,7 @@ namespace context // Contructor, creates a context object from a map of keys // and identifiers. template ::value> * = nullptr> - Context(const T keys_and_values) + Context(const T &keys_and_values) { trace::KeyValueIterableView iterable{keys_and_values}; iterable.ForEachKeyValue([&](nostd::string_view key, context::ContextValue value) noexcept { From 479dead3acedcff2985d685dfe62c1737ac5bd29 Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Mon, 13 Jul 2020 16:32:01 +0000 Subject: [PATCH 37/42] formatted --- api/include/opentelemetry/context/context.h | 100 +++++++++--------- .../opentelemetry/context/context_value.h | 30 +++--- 2 files changed, 63 insertions(+), 67 deletions(-) diff --git a/api/include/opentelemetry/context/context.h b/api/include/opentelemetry/context/context.h index 968476c2b8..db4f0387ed 100644 --- a/api/include/opentelemetry/context/context.h +++ b/api/include/opentelemetry/context/context.h @@ -11,66 +11,62 @@ OPENTELEMETRY_BEGIN_NAMESPACE namespace context { - // The context class provides a context identifier. - // This is a dummy class that is meant to be overridden, - // the methods return default values. - class Context - { +// The context class provides a context identifier. +// This is a dummy class that is meant to be overridden, +// the methods return default values. +class Context +{ - public: +public: + Context() = default; - Context() = default; + // Contructor, creates a context object from a map of keys + // and identifiers. + template ::value> * = nullptr> + Context(const T &keys_and_values) + { + trace::KeyValueIterableView iterable{keys_and_values}; + iterable.ForEachKeyValue([&](nostd::string_view key, context::ContextValue value) noexcept { + context_map_[std::string(key)] = value; + return true; + }); + } - // Contructor, creates a context object from a map of keys - // and identifiers. - template ::value> * = nullptr> - Context(const T &keys_and_values) - { - trace::KeyValueIterableView iterable{keys_and_values}; - iterable.ForEachKeyValue([&](nostd::string_view key, context::ContextValue value) noexcept { - context_map_[std::string(key)] = value; - return true; - }); - } + // Accepts a key and a value and then returns a new context that + // contains both the original pairs and the new pair. + template + Context SetValue(nostd::string_view key, T &value) noexcept + { + std::map context_map_copy = context_map_; + context_map_copy[std::string(key)] = value; + return Context(context_map_copy); + } - // Accepts a key and a value and then returns a new context that - // contains both the original pairs and the new pair. - template - Context SetValue(nostd::string_view key, T &value) noexcept - { - std::map context_map_copy = context_map_; - context_map_copy[std::string(key)] = value; - return Context(context_map_copy); - } + // Accepts a new iterable and then returns a new context that + // contains both the original pairs and the new pair. + template ::value> * = nullptr> + Context SetValues(T &keys_and_values) noexcept + { + std::map context_map_copy = context_map_; + trace::KeyValueIterableView iterable{keys_and_values}; - // Accepts a new iterable and then returns a new context that - // contains both the original pairs and the new pair. - template ::value> * = nullptr> - Context SetValues(T &keys_and_values) noexcept - { - std::map context_map_copy = context_map_; - trace::KeyValueIterableView iterable{keys_and_values}; - - iterable.ForEachKeyValue([&](nostd::string_view key, context::ContextValue value) noexcept { - context_map_copy[std::string(key)] = value; - return true; - }); - - return Context(context_map_copy); - } + iterable.ForEachKeyValue([&](nostd::string_view key, context::ContextValue value) noexcept { + context_map_copy[std::string(key)] = value; + return true; + }); - // Returns the value associated with the passed in key. - context::ContextValue GetValue(nostd::string_view key) { - return context_map_[std::string(key)]; - } + return Context(context_map_copy); + } - // Copy Constructors. - Context(const Context &other) = default; - Context &operator=(const Context &other) = default; + // Returns the value associated with the passed in key. + context::ContextValue GetValue(nostd::string_view key) { return context_map_[std::string(key)]; } - private: + // Copy Constructors. + Context(const Context &other) = default; + Context &operator=(const Context &other) = default; - std::map context_map_; - }; +private: + std::map context_map_; +}; } // namespace context OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/context/context_value.h b/api/include/opentelemetry/context/context_value.h index e4b966a4d9..bccdac46d1 100644 --- a/api/include/opentelemetry/context/context_value.h +++ b/api/include/opentelemetry/context/context_value.h @@ -10,19 +10,19 @@ OPENTELEMETRY_BEGIN_NAMESPACE namespace context { - using ContextValue = nostd::variant, - nostd::span, - nostd::span, - nostd::span, - nostd::span, - nostd::span, - nostd::span>; -} // namespace common +using ContextValue = nostd::variant, + nostd::span, + nostd::span, + nostd::span, + nostd::span, + nostd::span, + nostd::span>; +} // namespace context OPENTELEMETRY_END_NAMESPACE From 2a78c48a8e03b1fe91ad5dda0280a4f7fdd76ce9 Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Mon, 13 Jul 2020 16:51:46 +0000 Subject: [PATCH 38/42] Added tests. --- api/test/context/context_test.cc | 101 +++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 api/test/context/context_test.cc diff --git a/api/test/context/context_test.cc b/api/test/context/context_test.cc new file mode 100644 index 0000000000..63010ec76a --- /dev/null +++ b/api/test/context/context_test.cc @@ -0,0 +1,101 @@ +#include "opentelemetry/context/context.h" + +#include + +#include + +using namespace opentelemetry; + +// Tests that the context constructor accepts an std::map. +TEST(ContextTest, ContextIterableAcceptsMap) +{ + std::map map_test = {{"test_key", "123"}}; + context::Context context_test = context::Context(map_test); +} + +// Tests that the GetValue method returns the expected value. +TEST(ContextTest, ContextGetValueReturnsExpectedValue) +{ + std::map map_test = {{"test_key", "123"}, {"foo_key", "456"}}; + + context::Context context_test = context::Context(map_test); + EXPECT_EQ(nostd::get(context_test.GetValue("test_key")), "123"); + EXPECT_EQ(nostd::get(context_test.GetValue("foo_key")), "456"); +} + +// Tests that the SetValues method accepts an std::map. +TEST(ContextTest, ContextSetValuesAcceptsMap) +{ + std::map map_test = {{"test_key", "123"}}; + std::map map_test_write = {{"foo_key", "456"}}; + context::Context context_test = context::Context(map_test); + context::Context foo_test = context_test.SetValues(map_test_write); + EXPECT_EQ(nostd::get(foo_test.GetValue("test_key")), "123"); + EXPECT_EQ(nostd::get(foo_test.GetValue("foo_key")), "456"); +} + +// Tests that the SetValues method accepts a nostd::string_view and +// context::ContextValue. +TEST(ContextTest, ContextSetValuesAcceptsStringViewContextValue) +{ + nostd::string_view string_view_test = "string_view"; + context::ContextValue context_value_test = "123"; + context::Context context_test = context::Context(); + context::Context context_foo = context_test.SetValue(string_view_test, context_value_test); + EXPECT_EQ(nostd::get(context_foo.GetValue(string_view_test)), "123"); +} + +// Tests that the original context does not change when a value is +// written to it. +TEST(ContextTest, ContextImmutability) +{ + std::map map_test = {{"test_key", "123"}}; + context::Context context_test = context::Context(map_test); + + context::Context context_foo = context_test.SetValue("foo_key", "456"); + + EXPECT_THROW(nostd::get(context_test.GetValue("foo_key")), + nostd::bad_variant_access); +} + +// Tests that writing the same to a context overwrites the original value. +TEST(ContextTest, ContextKeyOverwrite) +{ + std::map map_test = {{"test_key", "123"}}; + context::Context context_test = context::Context(map_test); + context::Context context_foo = context_test.SetValue("test_key", "456"); + + EXPECT_EQ(nostd::get(context_foo.GetValue("test_key")), "456"); +} + +// Tests that the new Context Objects inherits the keys and values +// of the original context object. +TEST(ContextTest, ContextInheritance) +{ + + using M = std::map; + context::Context test_context = context::Context(); + + M m1 = {{"test_key", "123"}, {"foo_key", "456"}}; + M m2 = {{"other_key", "789"}}; + + context::Context foo_context = test_context.SetValues(m1); + context::Context other_context = foo_context.SetValues(m2); + + EXPECT_EQ(nostd::get(other_context.GetValue("test_key")), "123"); + EXPECT_EQ(nostd::get(other_context.GetValue("foo_key")), "456"); +} + +// Tests that copying a context copies the key value pairs as expected. +TEST(ContextTest, ContextCopyOperator) +{ + std::map test_map = { + {"test_key", "123"}, {"foo_key", "456"}, {"other_key", "789"}}; + + context::Context test_context = context::Context(test_map); + context::Context copied_context = test_context; + + EXPECT_EQ(nostd::get(copied_context.GetValue("test_key")), "123"); + EXPECT_EQ(nostd::get(copied_context.GetValue("foo_key")), "456"); + EXPECT_EQ(nostd::get(copied_context.GetValue("other_key")), "789"); +} From f51748f614bd7b2f79dacafc6a1808dcf7b3ef23 Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Mon, 13 Jul 2020 17:48:52 +0000 Subject: [PATCH 39/42] avoiding ABI compatibility issues --- api/include/opentelemetry/context/context.h | 26 ++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/api/include/opentelemetry/context/context.h b/api/include/opentelemetry/context/context.h index db4f0387ed..35b7920c09 100644 --- a/api/include/opentelemetry/context/context.h +++ b/api/include/opentelemetry/context/context.h @@ -5,6 +5,7 @@ #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/trace/key_value_iterable_view.h" +#include #include OPENTELEMETRY_BEGIN_NAMESPACE @@ -37,8 +38,18 @@ class Context template Context SetValue(nostd::string_view key, T &value) noexcept { - std::map context_map_copy = context_map_; - context_map_copy[std::string(key)] = value; + std::map context_map_copy; + trace::KeyValueIterableView> context_map_iterable{ + context_map_}; + + context_map_iterable.ForEachKeyValue([&](nostd::string_view key, + context::ContextValue value) noexcept { + context_map_copy[std::string(key)] = value; + return true; + }); + + context_map_copy[std::string(key)] = value; + return Context(context_map_copy); } @@ -47,7 +58,16 @@ class Context template ::value> * = nullptr> Context SetValues(T &keys_and_values) noexcept { - std::map context_map_copy = context_map_; + std::map context_map_copy; + trace::KeyValueIterableView> context_map_iterable{ + context_map_}; + + context_map_iterable.ForEachKeyValue([&](nostd::string_view key, + context::ContextValue value) noexcept { + context_map_copy[std::string(key)] = value; + return true; + }); + trace::KeyValueIterableView iterable{keys_and_values}; iterable.ForEachKeyValue([&](nostd::string_view key, context::ContextValue value) noexcept { From 9902d5e1239431e0a39890ba2908f319e7be8c34 Mon Sep 17 00:00:00 2001 From: Nick Holbrook Date: Mon, 13 Jul 2020 13:49:31 -0600 Subject: [PATCH 40/42] Move SpanContext to Separate File (#168) --- .../opentelemetry/trace/span_context.h | 59 +++++++++++++++++++ api/test/trace/BUILD | 11 ++++ api/test/trace/CMakeLists.txt | 2 +- api/test/trace/span_context_test.cc | 38 ++++++++++++ sdk/include/opentelemetry/sdk/trace/sampler.h | 5 +- .../sdk/trace/samplers/always_off.h | 3 +- .../sdk/trace/samplers/always_on.h | 3 +- .../sdk/trace/samplers/parent_or_else.h | 17 +----- sdk/src/trace/samplers/parent_or_else.cc | 4 +- sdk/test/trace/parent_or_else_sampler_test.cc | 5 +- 10 files changed, 121 insertions(+), 26 deletions(-) create mode 100644 api/include/opentelemetry/trace/span_context.h create mode 100644 api/test/trace/span_context_test.cc diff --git a/api/include/opentelemetry/trace/span_context.h b/api/include/opentelemetry/trace/span_context.h new file mode 100644 index 0000000000..fc04ce17e6 --- /dev/null +++ b/api/include/opentelemetry/trace/span_context.h @@ -0,0 +1,59 @@ +// Copyright 2020, OpenTelemetry 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. + +#pragma once + +#include "opentelemetry/nostd/unique_ptr.h" +#include "opentelemetry/trace/span_id.h" +#include "opentelemetry/trace/trace_flags.h" +#include "opentelemetry/trace/trace_id.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace trace +{ +namespace trace_api = opentelemetry::trace; + +/* SpanContext contains the state that must propagate to child Spans and across + * process boundaries. It contains the identifiers TraceId and SpanId, + * TraceFlags, TraceState, and whether it has a remote parent. + * + * TODO: This is currently a placeholder class and requires revisiting + */ +class SpanContext final +{ +public: + /* A temporary constructor for an invalid SpanContext. + * @param sampled_flag a required parameter specifying if child spans should be + * sampled + * @param has_remote_parent a required parameter specifying if this context has + * a remote parent + */ + SpanContext(bool sampled_flag, bool has_remote_parent) : + trace_flags_(trace_api::TraceFlags((uint8_t) sampled_flag)), remote_parent_(has_remote_parent) {}; + + // @returns the trace_flags associated with this span_context + const trace_api::TraceFlags &trace_flags() const noexcept { return trace_flags_; } + + // @returns whether this context has the sampled flag set or not + bool IsSampled() const noexcept { return trace_flags_.IsSampled(); } + + // @returns whether this context has a remote parent or not + bool HasRemoteParent() const noexcept { return remote_parent_; } + +private: + const trace_api::TraceFlags trace_flags_; + const bool remote_parent_ = false; +}; +} // namespace trace +OPENTELEMETRY_END_NAMESPACE diff --git a/api/test/trace/BUILD b/api/test/trace/BUILD index ed3d584712..b3f194baa0 100644 --- a/api/test/trace/BUILD +++ b/api/test/trace/BUILD @@ -71,3 +71,14 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "span_context_test", + srcs = [ + "span_context_test.cc", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/api/test/trace/CMakeLists.txt b/api/test/trace/CMakeLists.txt index f722ae4557..3439146f7a 100644 --- a/api/test/trace/CMakeLists.txt +++ b/api/test/trace/CMakeLists.txt @@ -1,5 +1,5 @@ foreach(testname key_value_iterable_view_test noop_test provider_test - span_id_test trace_id_test trace_flags_test) + span_id_test trace_id_test trace_flags_test span_context_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) diff --git a/api/test/trace/span_context_test.cc b/api/test/trace/span_context_test.cc new file mode 100644 index 0000000000..661bba00bc --- /dev/null +++ b/api/test/trace/span_context_test.cc @@ -0,0 +1,38 @@ +#include "opentelemetry/trace/span_context.h" + +#include + +using opentelemetry::trace::SpanContext; + +TEST(SpanContextTest, IsSampled) +{ + SpanContext s1(true, true); + + ASSERT_EQ(s1.IsSampled(), true); + + SpanContext s2(false, true); + + ASSERT_EQ(s2.IsSampled(), false); +} + +TEST(SpanContextTest, HasRemoteParent) +{ + SpanContext s1(true, true); + + ASSERT_EQ(s1.HasRemoteParent(), true); + + SpanContext s2(true, false); + + ASSERT_EQ(s2.HasRemoteParent(), false); +} + +TEST(SpanContextTest, TraceFlags) +{ + SpanContext s1(true, true); + + ASSERT_EQ(s1.trace_flags().flags(), 1); + + SpanContext s2(false, true); + + ASSERT_EQ(s2.trace_flags().flags(), 0); +} diff --git a/sdk/include/opentelemetry/sdk/trace/sampler.h b/sdk/include/opentelemetry/sdk/trace/sampler.h index 27071b458c..35a0927404 100644 --- a/sdk/include/opentelemetry/sdk/trace/sampler.h +++ b/sdk/include/opentelemetry/sdk/trace/sampler.h @@ -4,6 +4,7 @@ #include "opentelemetry/trace/span.h" #include "opentelemetry/trace/trace_id.h" #include "opentelemetry/version.h" +#include "opentelemetry/trace/span_context.h" #include #include @@ -48,8 +49,6 @@ struct SamplingResult class Sampler { public: - // TODO: Remove this placeholder with real class - class SpanContext; virtual ~Sampler() = default; /** * Called during Span creation to make a sampling decision. @@ -66,7 +65,7 @@ class Sampler * @since 0.1.0 */ - virtual SamplingResult ShouldSample(const SpanContext *parent_context, + virtual SamplingResult ShouldSample(const trace_api::SpanContext *parent_context, trace_api::TraceId trace_id, nostd::string_view name, trace_api::SpanKind span_kind, diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h b/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h index 0547068280..252cd9e4fd 100644 --- a/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h +++ b/sdk/include/opentelemetry/sdk/trace/samplers/always_off.h @@ -8,6 +8,7 @@ namespace sdk namespace trace { namespace trace_api = opentelemetry::trace; + /** * The always off sampler always returns NOT_RECORD, effectively disabling * tracing functionality. @@ -19,7 +20,7 @@ class AlwaysOffSampler : public Sampler * @return Returns NOT_RECORD always */ SamplingResult ShouldSample( - const SpanContext * /*parent_context*/, + const trace_api::SpanContext * /*parent_context*/, trace_api::TraceId /*trace_id*/, nostd::string_view /*name*/, trace_api::SpanKind /*span_kind*/, diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h b/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h index e50d15829f..5dd5f86457 100644 --- a/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h +++ b/sdk/include/opentelemetry/sdk/trace/samplers/always_on.h @@ -8,6 +8,7 @@ namespace sdk namespace trace { namespace trace_api = opentelemetry::trace; + /** * The always on sampler is a default sampler which always return Decision::RECORD_AND_SAMPLE */ @@ -17,7 +18,7 @@ class AlwaysOnSampler : public Sampler /** * @return Always return Decision RECORD_AND_SAMPLE */ - inline SamplingResult ShouldSample(const SpanContext * /*parent_context*/, + inline SamplingResult ShouldSample(const trace_api::SpanContext * /*parent_context*/, trace_api::TraceId /*trace_id*/, nostd::string_view /*name*/, trace_api::SpanKind /*span_kind*/, diff --git a/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h b/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h index c562277957..aec9934604 100644 --- a/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h +++ b/sdk/include/opentelemetry/sdk/trace/samplers/parent_or_else.h @@ -10,21 +10,6 @@ namespace trace { namespace trace_api = opentelemetry::trace; -/** - * A placeholder class that stores the states of a span. - * Will be replaced by the real SpanContext class once it is implemented. - */ -class Sampler::SpanContext -{ -public: - inline explicit SpanContext(bool is_recording, bool sampled_flag) - : is_recording(is_recording), sampled_flag(sampled_flag) - {} - - bool is_recording; - bool sampled_flag; -}; - /** * The parent or else sampler is a composite sampler. ParentOrElse(delegateSampler) either respects * the parent span's sampling decision or delegates to delegateSampler for root spans. @@ -37,7 +22,7 @@ class ParentOrElseSampler : public Sampler * delegateSampler for root spans * @return Returns NOT_RECORD always */ - SamplingResult ShouldSample(const SpanContext * parent_context, + SamplingResult ShouldSample(const trace_api::SpanContext * parent_context, trace_api::TraceId trace_id, nostd::string_view name, trace_api::SpanKind span_kind, diff --git a/sdk/src/trace/samplers/parent_or_else.cc b/sdk/src/trace/samplers/parent_or_else.cc index fd0d909e84..2b56ab9d4b 100644 --- a/sdk/src/trace/samplers/parent_or_else.cc +++ b/sdk/src/trace/samplers/parent_or_else.cc @@ -11,7 +11,7 @@ ParentOrElseSampler::ParentOrElseSampler(std::shared_ptr delegate_sampl {} SamplingResult ParentOrElseSampler::ShouldSample( - const SpanContext *parent_context, + const trace_api::SpanContext *parent_context, trace_api::TraceId trace_id, nostd::string_view name, trace_api::SpanKind span_kind, @@ -24,7 +24,7 @@ SamplingResult ParentOrElseSampler::ShouldSample( } // If parent exists: - if (parent_context->sampled_flag) + if (parent_context->IsSampled()) { return {Decision::RECORD_AND_SAMPLE, nullptr}; } diff --git a/sdk/test/trace/parent_or_else_sampler_test.cc b/sdk/test/trace/parent_or_else_sampler_test.cc index 152121f4c3..93ce56dfb1 100644 --- a/sdk/test/trace/parent_or_else_sampler_test.cc +++ b/sdk/test/trace/parent_or_else_sampler_test.cc @@ -8,6 +8,7 @@ using opentelemetry::sdk::trace::AlwaysOffSampler; using opentelemetry::sdk::trace::AlwaysOnSampler; using opentelemetry::sdk::trace::Decision; using opentelemetry::sdk::trace::ParentOrElseSampler; +using opentelemetry::trace::SpanContext; TEST(ParentOrElseSampler, ShouldSample) { @@ -20,8 +21,8 @@ TEST(ParentOrElseSampler, ShouldSample) using M = std::map; M m1 = {{}}; opentelemetry::trace::KeyValueIterableView view{m1}; - opentelemetry::sdk::trace::Sampler::SpanContext parent_context_sampled(true, true); - opentelemetry::sdk::trace::Sampler::SpanContext parent_context_nonsampled(true, false); + SpanContext parent_context_sampled(true, false); + SpanContext parent_context_nonsampled(false, false); // Case 1: Parent doesn't exist. Return result of delegateSampler() auto sampling_result = sampler_off.ShouldSample(nullptr, trace_id, "", span_kind, view); From 3f85aa510e680191b8cfd6f8bebbaa0dcd8db8b4 Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Tue, 14 Jul 2020 14:50:59 +0000 Subject: [PATCH 41/42] added throw capture --- api/test/context/context_test.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/api/test/context/context_test.cc b/api/test/context/context_test.cc index 63010ec76a..de49e7ac4e 100644 --- a/api/test/context/context_test.cc +++ b/api/test/context/context_test.cc @@ -53,9 +53,12 @@ TEST(ContextTest, ContextImmutability) context::Context context_test = context::Context(map_test); context::Context context_foo = context_test.SetValue("foo_key", "456"); - +#if __EXCEPTIONS EXPECT_THROW(nostd::get(context_test.GetValue("foo_key")), nostd::bad_variant_access); +#else + EXPECT_DEATH({nostd::get(context_test.GetValue("foo_key"))}, ""); +#endif } // Tests that writing the same to a context overwrites the original value. From 21ea872e1af3d76687e2a315a01e27317c4d0cee Mon Sep 17 00:00:00 2001 From: Sam Atac Date: Tue, 14 Jul 2020 15:06:53 +0000 Subject: [PATCH 42/42] minor exception syntax error --- api/test/context/context_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/test/context/context_test.cc b/api/test/context/context_test.cc index de49e7ac4e..ee366d1a1a 100644 --- a/api/test/context/context_test.cc +++ b/api/test/context/context_test.cc @@ -57,7 +57,7 @@ TEST(ContextTest, ContextImmutability) EXPECT_THROW(nostd::get(context_test.GetValue("foo_key")), nostd::bad_variant_access); #else - EXPECT_DEATH({nostd::get(context_test.GetValue("foo_key"))}, ""); + EXPECT_DEATH({ nostd::get(context_test.GetValue("foo_key")); }, ""); #endif }