diff --git a/CHANGELOG.md b/CHANGELOG.md index 49274a68e6..1c42855fee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ Increment the: * [CMAKE] Bump cmake minimum required version to 3.14 [#3349](https://github.com/open-telemetry/opentelemetry-cpp/pull/3349) +* [API] Add Enabled method to Tracer + [#3357](https://github.com/open-telemetry/opentelemetry-cpp/pull/3357) + ## [1.20 2025-04-01] * [BUILD] Update opentelemetry-proto version diff --git a/api/include/opentelemetry/common/macros.h b/api/include/opentelemetry/common/macros.h index b74c1048fc..71d12a57bf 100644 --- a/api/include/opentelemetry/common/macros.h +++ b/api/include/opentelemetry/common/macros.h @@ -341,7 +341,7 @@ point. // Atomic wrappers based on compiler intrinsics for memory read/write. // The tailing number is read/write length in bits. // -// N.B. Compiler instrinsic is used because the usage of C++ standard library is restricted in the +// N.B. Compiler intrinsic is used because the usage of C++ standard library is restricted in the // OpenTelemetry C++ API. // #if defined(__GNUC__) diff --git a/api/include/opentelemetry/plugin/tracer.h b/api/include/opentelemetry/plugin/tracer.h index 3b0c5ff2cc..99d1fc4c27 100644 --- a/api/include/opentelemetry/plugin/tracer.h +++ b/api/include/opentelemetry/plugin/tracer.h @@ -87,7 +87,11 @@ class Tracer final : public trace::Tracer, public std::enable_shared_from_this library_handle, std::unique_ptr &&tracer_handle) noexcept : library_handle_{std::move(library_handle)}, tracer_handle_{std::move(tracer_handle)} - {} + { +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + UpdateEnabled(true); +#endif + } // trace::Tracer nostd::shared_ptr StartSpan( diff --git a/api/include/opentelemetry/trace/noop.h b/api/include/opentelemetry/trace/noop.h index fa0c7957df..14e7c9c33d 100644 --- a/api/include/opentelemetry/trace/noop.h +++ b/api/include/opentelemetry/trace/noop.h @@ -96,6 +96,13 @@ class OPENTELEMETRY_EXPORT NoopTracer final : public Tracer, { public: // Tracer + NoopTracer() + { +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + UpdateEnabled(false); +#endif + } + nostd::shared_ptr StartSpan(nostd::string_view /*name*/, const common::KeyValueIterable & /*attributes*/, const SpanContextKeyValueIterable & /*links*/, diff --git a/api/include/opentelemetry/trace/tracer.h b/api/include/opentelemetry/trace/tracer.h index c10fff6c60..ab09843526 100644 --- a/api/include/opentelemetry/trace/tracer.h +++ b/api/include/opentelemetry/trace/tracer.h @@ -163,6 +163,18 @@ class Tracer } } +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + /** + * Reports if the tracer is enabled or not. A disabled tracer will not create spans. + * + * The instrumentation authors should call this method before creating a spans to + * potentially avoid performing computationally expensive operations for disabled tracers. + * + * @since ABI_VERSION 2 + */ + bool Enabled() const noexcept { return OPENTELEMETRY_ATOMIC_READ_8(&this->enabled_) != 0; } +#endif + #if OPENTELEMETRY_ABI_VERSION_NO == 1 /* @@ -197,6 +209,36 @@ class Tracer virtual void CloseWithMicroseconds(uint64_t timeout) noexcept = 0; #endif /* OPENTELEMETRY_ABI_VERSION_NO */ + +protected: +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + + /** + * Updates the enabled state of the tracer. Calling this method will affect the result of the + * subsequent calls to {@code opentelemetry::v2::trace::Tracer::Enabled()}. + * + * This method should be used by SDK implementations to indicate the tracer's updated state + * whenever a tracer transitions from enabled to disabled state and vice versa. + * + * @param enabled The new state of the tracer. False would indicate that the tracer is no longer + * enabled and will not produce as + * + * @since ABI_VERSION 2 + */ + void UpdateEnabled(const bool enabled) noexcept + { + OPENTELEMETRY_ATOMIC_WRITE_8(&this->enabled_, enabled); + } +#endif + +private: +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + // Variable to support implementation of Enabled method introduced in ABI V2. + // Mutable allows enabled_ to be used as 'bool *' (instead of 'const bool *'), with the + // OPENTELEMETRY_ATOMIC_READ_8 macro's internal casts when used from a const function. + // std::atomic can not be used here because it is not ABI compatible for OpenTelemetry C++ API. + mutable bool enabled_ = true; +#endif }; } // namespace trace OPENTELEMETRY_END_NAMESPACE diff --git a/api/test/singleton/singleton_test.cc b/api/test/singleton/singleton_test.cc index 5f3dcf0b96..1616f6bc89 100644 --- a/api/test/singleton/singleton_test.cc +++ b/api/test/singleton/singleton_test.cc @@ -169,6 +169,13 @@ void reset_counts() class MyTracer : public trace::Tracer { public: + MyTracer() + { +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + UpdateEnabled(true); +#endif + } + nostd::shared_ptr StartSpan( nostd::string_view name, const common::KeyValueIterable & /* attributes */, diff --git a/api/test/trace/noop_test.cc b/api/test/trace/noop_test.cc index 55c788d227..0a4a3294ae 100644 --- a/api/test/trace/noop_test.cc +++ b/api/test/trace/noop_test.cc @@ -70,6 +70,8 @@ TEST(NoopTest, UseNoopTracersAbiv2) s1->AddLink(target, {{"noop1", 1}}); s1->AddLinks({{trace_api::SpanContext(false, false), {{"noop2", 2}}}}); + + EXPECT_FALSE(tracer->Enabled()); } #endif /* OPENTELEMETRY_ABI_VERSION_NO >= 2 */ diff --git a/examples/plugin/plugin/tracer.cc b/examples/plugin/plugin/tracer.cc index 5361197584..a89640e000 100644 --- a/examples/plugin/plugin/tracer.cc +++ b/examples/plugin/plugin/tracer.cc @@ -81,7 +81,12 @@ class Span final : public trace::Span }; } // namespace -Tracer::Tracer(nostd::string_view /*output*/) {} +Tracer::Tracer(nostd::string_view /*output*/) +{ +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + UpdateEnabled(true); +#endif +} nostd::shared_ptr Tracer::StartSpan(nostd::string_view name, const common::KeyValueIterable &attributes, diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h index 5d0603454e..c6c7f0ed67 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h @@ -590,6 +590,20 @@ class Tracer : public opentelemetry::trace::Tracer, return result; } +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + /** + * Reports if the tracer is enabled or not. A disabled tracer will not create spans. + * Note: The etw_tracer currently does not accept a TracerConfig and can therefore not be disabled + * based on the instrumentation scope. + * + * The instrumentation authors should call this method before creating a spans to + * potentially avoid performing computationally expensive operations for disabled tracers. + * + * @since ABI_VERSION 2 + */ + virtual bool Enabled() const noexcept { return true; } +#endif + #if OPENTELEMETRY_ABI_VERSION_NO == 1 /** * @brief Force flush data to Tracer, spending up to given amount of microseconds to flush. diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index c166885600..263638955b 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -46,7 +46,11 @@ Tracer::Tracer(std::shared_ptr context, : instrumentation_scope_{std::move(instrumentation_scope)}, context_{std::move(context)}, tracer_config_(context_->GetTracerConfigurator().ComputeConfig(*instrumentation_scope_)) -{} +{ +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + UpdateEnabled(tracer_config_.IsEnabled()); +#endif +} nostd::shared_ptr Tracer::StartSpan( nostd::string_view name, diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index 1f31e2336d..00c92ec682 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -508,6 +508,11 @@ TEST(Tracer, StartSpanWithDisabledConfig) std::make_shared(); auto noop_span = noop_tracer->StartSpan("noop"); EXPECT_TRUE(span.get() == noop_span.get()); + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + EXPECT_FALSE(noop_tracer->Enabled()); + EXPECT_FALSE(tracer->Enabled()); +#endif } TEST(Tracer, StartSpanWithEnabledConfig) @@ -524,6 +529,11 @@ TEST(Tracer, StartSpanWithEnabledConfig) std::make_shared(); auto noop_span = noop_tracer->StartSpan("noop"); EXPECT_FALSE(span.get() == noop_span.get()); + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + EXPECT_FALSE(noop_tracer->Enabled()); + EXPECT_TRUE(tracer->Enabled()); +#endif } TEST(Tracer, StartSpanWithCustomConfig) @@ -567,6 +577,14 @@ TEST(Tracer, StartSpanWithCustomConfig) new RandomIdGenerator(), custom_configurator, std::move(bar_scope)); auto span_bar_scope = tracer_bar_scope->StartSpan("span 1"); EXPECT_FALSE(span_bar_scope == noop_span); + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + EXPECT_FALSE(noop_tracer->Enabled()); + EXPECT_FALSE(tracer_default_scope->Enabled()); + EXPECT_FALSE(tracer_foo_scope->Enabled()); + EXPECT_TRUE(tracer_foo_scope_with_version->Enabled()); + EXPECT_TRUE(tracer_bar_scope->Enabled()); +#endif } TEST(Tracer, StartSpanWithCustomConfigDifferingConditionOrder) @@ -608,6 +626,11 @@ TEST(Tracer, StartSpanWithCustomConfigDifferingConditionOrder) // evaluating other condition const auto span_foo_scope_with_version_2 = tracer_foo_scope_with_version_2->StartSpan("span 1"); EXPECT_TRUE(span_foo_scope_with_version_2 == noop_span); + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + EXPECT_TRUE(tracer_foo_scope_with_version_1->Enabled()); + EXPECT_FALSE(tracer_foo_scope_with_version_2->Enabled()); +#endif } TEST(Tracer, SpanSetLinks)