From c86794e41b96337ef999dd513d380c3970737f2e Mon Sep 17 00:00:00 2001 From: Ankit Bhargava Date: Fri, 19 Jun 2020 13:14:59 -0400 Subject: [PATCH 1/6] 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 2/6] 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 3/6] 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 4/6] 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 5/6] 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 6/6] 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()); +}