From 1271d6fdaa5f57e78e695a7bb33351ca5faab446 Mon Sep 17 00:00:00 2001 From: elix3r <157088510+22elix3r@users.noreply.github.com> Date: Fri, 21 Aug 2026 23:04:23 +0530 Subject: [PATCH 1/5] [SDK] Handle instrumentation object construction failures safely Remove noexcept from SDK TracerProvider, LoggerProvider, MeterProvider, Tracer, Logger, and Meter constructors so initialization-time allocation failures can propagate. Keep GetTracer/GetLogger/GetMeter noexcept and return a pre-allocated noop object if constructing a new instrumentation object fails, without caching the failed attempt. Fixes #4361 Signed-off-by: elix3r <157088510+22elix3r@users.noreply.github.com> --- CHANGELOG.md | 5 + sdk/include/opentelemetry/sdk/logs/logger.h | 2 +- .../opentelemetry/sdk/logs/logger_provider.h | 10 +- sdk/include/opentelemetry/sdk/metrics/meter.h | 2 +- .../sdk/metrics/meter_provider.h | 6 +- sdk/include/opentelemetry/sdk/trace/tracer.h | 2 +- .../opentelemetry/sdk/trace/tracer_provider.h | 8 +- sdk/src/logs/logger.cc | 2 +- sdk/src/logs/logger_provider.cc | 78 +++++++++++++--- sdk/src/metrics/meter.cc | 2 +- sdk/src/metrics/meter_provider.cc | 70 +++++++++++--- sdk/src/trace/tracer.cc | 2 +- sdk/src/trace/tracer_provider.cc | 76 ++++++++++++--- sdk/test/logs/logger_provider_sdk_test.cc | 93 +++++++++++++++++++ sdk/test/metrics/meter_provider_sdk_test.cc | 73 +++++++++++++++ sdk/test/trace/tracer_provider_test.cc | 77 +++++++++++++++ 16 files changed, 455 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4206a30157..a2f65fe009 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ Increment the: ## [Unreleased] +* [SDK] Allow SDK provider and instrumentation constructors to throw during + initialization. `GetTracer`, `GetLogger`, and `GetMeter` stay `noexcept` and + return a pre-allocated noop object if constructing a new instrumentation + object fails, without caching the failure. + [#4361](https://github.com/open-telemetry/opentelemetry-cpp/issues/4361) * [CONFIGURATION] Add a configuration builder for the host resource detector [#4451](https://github.com/open-telemetry/opentelemetry-cpp/issues/4451) * [CONFIGURATION] Build the configured resource detectors in SdkBuilder, apply diff --git a/sdk/include/opentelemetry/sdk/logs/logger.h b/sdk/include/opentelemetry/sdk/logs/logger.h index 44ed4ec1ee..7ad7a7cd62 100644 --- a/sdk/include/opentelemetry/sdk/logs/logger.h +++ b/sdk/include/opentelemetry/sdk/logs/logger.h @@ -42,7 +42,7 @@ class Logger final : public opentelemetry::logs::Logger opentelemetry::nostd::string_view name, std::shared_ptr context, std::unique_ptr instrumentation_scope = - instrumentationscope::InstrumentationScope::Create("")) noexcept; + instrumentationscope::InstrumentationScope::Create("")); /** * Returns the name of this logger. diff --git a/sdk/include/opentelemetry/sdk/logs/logger_provider.h b/sdk/include/opentelemetry/sdk/logs/logger_provider.h index 06ef66cc6a..75454836c2 100644 --- a/sdk/include/opentelemetry/sdk/logs/logger_provider.h +++ b/sdk/include/opentelemetry/sdk/logs/logger_provider.h @@ -45,7 +45,7 @@ class OPENTELEMETRY_EXPORT LoggerProvider final : public opentelemetry::logs::Lo std::make_unique>( instrumentationscope::ScopeConfigurator::Builder( LoggerConfig::Default()) - .Build())) noexcept; + .Build())); /** * Initialize a new logger provider. @@ -62,19 +62,19 @@ class OPENTELEMETRY_EXPORT LoggerProvider final : public opentelemetry::logs::Lo std::make_unique>( instrumentationscope::ScopeConfigurator::Builder( LoggerConfig::Default()) - .Build())) noexcept; + .Build())); /** * Initialize a new logger provider. A processor must later be assigned * to this logger provider via the AddProcessor() method. */ - explicit LoggerProvider() noexcept; + explicit LoggerProvider(); /** * Initialize a new logger provider with a specified context * @param context The owned logger configuration/pipeline for this provider. */ - explicit LoggerProvider(std::unique_ptr context) noexcept; + explicit LoggerProvider(std::unique_ptr context); LoggerProvider(const LoggerProvider &) = delete; LoggerProvider(LoggerProvider &&) = delete; @@ -144,6 +144,8 @@ class OPENTELEMETRY_EXPORT LoggerProvider final : public opentelemetry::logs::Lo std::vector> loggers_; std::shared_ptr context_; std::mutex lock_; + // Allocated during provider construction so GetLogger can return it without allocating. + nostd::shared_ptr noop_logger_; }; } // namespace logs } // namespace sdk diff --git a/sdk/include/opentelemetry/sdk/metrics/meter.h b/sdk/include/opentelemetry/sdk/metrics/meter.h index e0ed7acdbb..92d61471fa 100644 --- a/sdk/include/opentelemetry/sdk/metrics/meter.h +++ b/sdk/include/opentelemetry/sdk/metrics/meter.h @@ -45,7 +45,7 @@ class Meter final : public opentelemetry::metrics::Meter explicit Meter( std::weak_ptr meter_context, std::unique_ptr scope = - opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create("")) noexcept; + opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create("")); nostd::unique_ptr> CreateUInt64Counter( nostd::string_view name, diff --git a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h index fccaae690b..a6c01e2e77 100644 --- a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h +++ b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h @@ -51,13 +51,13 @@ class OPENTELEMETRY_EXPORT MeterProvider final : public opentelemetry::metrics:: std::unique_ptr> meter_configurator = std::make_unique>( instrumentationscope::ScopeConfigurator::Builder(MeterConfig::Default()) - .Build())) noexcept; + .Build())); /** * Initialize a new meter provider with a specified context * @param context The owned meter configuration/pipeline for this provider. */ - explicit MeterProvider(std::unique_ptr context) noexcept; + explicit MeterProvider(std::unique_ptr context); MeterProvider(const MeterProvider &) = delete; MeterProvider(MeterProvider &&) = delete; @@ -144,6 +144,8 @@ class OPENTELEMETRY_EXPORT MeterProvider final : public opentelemetry::metrics:: private: std::shared_ptr context_; std::mutex lock_; + // Allocated during provider construction so GetMeter can return it without allocating. + nostd::shared_ptr noop_meter_; #if defined(__cpp_lib_atomic_value_initialization) && \ __cpp_lib_atomic_value_initialization >= 201911L diff --git a/sdk/include/opentelemetry/sdk/trace/tracer.h b/sdk/include/opentelemetry/sdk/trace/tracer.h index 88e12ab16d..edd7eb73ec 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer.h @@ -40,7 +40,7 @@ class Tracer final : public opentelemetry::trace::Tracer, /** Construct a new Tracer with the given context pipeline. */ explicit Tracer(std::shared_ptr context, std::unique_ptr instrumentation_scope = - InstrumentationScope::Create("")) noexcept; + InstrumentationScope::Create("")); nostd::shared_ptr StartSpan( nostd::string_view name, diff --git a/sdk/include/opentelemetry/sdk/trace/tracer_provider.h b/sdk/include/opentelemetry/sdk/trace/tracer_provider.h index 5b9986a4c3..8c3f6358ff 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer_provider.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer_provider.h @@ -56,7 +56,7 @@ class OPENTELEMETRY_EXPORT TracerProvider final : public opentelemetry::trace::T instrumentationscope::ScopeConfigurator::Builder( TracerConfig::Default()) .Build()), - SpanLimits span_limits = SpanLimits::NoLimits()) noexcept; + SpanLimits span_limits = SpanLimits::NoLimits()); explicit TracerProvider( std::vector> &&processors, @@ -70,13 +70,13 @@ class OPENTELEMETRY_EXPORT TracerProvider final : public opentelemetry::trace::T instrumentationscope::ScopeConfigurator::Builder( TracerConfig::Default()) .Build()), - SpanLimits span_limits = SpanLimits::NoLimits()) noexcept; + SpanLimits span_limits = SpanLimits::NoLimits()); /** * Initialize a new tracer provider with a specified context * @param context The owned tracer configuration/pipeline for this provider. */ - explicit TracerProvider(std::unique_ptr context) noexcept; + explicit TracerProvider(std::unique_ptr context); TracerProvider(const TracerProvider &) = delete; TracerProvider(TracerProvider &&) = delete; @@ -155,6 +155,8 @@ class OPENTELEMETRY_EXPORT TracerProvider final : public opentelemetry::trace::T std::vector> tracers_; std::shared_ptr context_; std::mutex lock_; + // Allocated during provider construction so GetTracer can return it without allocating. + nostd::shared_ptr noop_tracer_; }; } // namespace trace } // namespace sdk diff --git a/sdk/src/logs/logger.cc b/sdk/src/logs/logger.cc index c04b1dfe68..4ea5f5d203 100644 --- a/sdk/src/logs/logger.cc +++ b/sdk/src/logs/logger.cc @@ -99,7 +99,7 @@ opentelemetry::logs::NoopLogger Logger::kNoopLogger = opentelemetry::logs::NoopL Logger::Logger( opentelemetry::nostd::string_view name, std::shared_ptr context, - std::unique_ptr instrumentation_scope) noexcept + std::unique_ptr instrumentation_scope) : logger_name_(std::string(name)), instrumentation_scope_(std::move(instrumentation_scope)), context_(std::move(context)) diff --git a/sdk/src/logs/logger_provider.cc b/sdk/src/logs/logger_provider.cc index 235c3bb4f8..397559a798 100644 --- a/sdk/src/logs/logger_provider.cc +++ b/sdk/src/logs/logger_provider.cc @@ -2,10 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include +#include #include #include #include +#include "opentelemetry/common/macros.h" +#include "opentelemetry/logs/noop.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/sdk/common/global_log_handler.h" @@ -25,11 +29,37 @@ namespace sdk namespace logs { +namespace +{ + +nostd::shared_ptr CreateNoopLoggerFallback() +{ + return nostd::shared_ptr(new opentelemetry::logs::NoopLogger()); +} + +void LogGetLoggerConstructionFailure(const char *detail) noexcept +{ +#if OPENTELEMETRY_HAVE_EXCEPTIONS + try + { +#endif + OTEL_INTERNAL_LOG_ERROR("[LoggerProvider::GetLogger] Failed to construct logger: " + << detail << "; returning noop logger."); +#if OPENTELEMETRY_HAVE_EXCEPTIONS + } + catch (...) + { + } +#endif +} + +} // namespace + LoggerProvider::LoggerProvider( std::unique_ptr &&processor, const opentelemetry::sdk::resource::Resource &resource, - std::unique_ptr> - logger_configurator) noexcept + std::unique_ptr> logger_configurator) + : noop_logger_(CreateNoopLoggerFallback()) { std::vector> processors; processors.emplace_back(std::move(processor)); @@ -41,19 +71,20 @@ LoggerProvider::LoggerProvider( LoggerProvider::LoggerProvider( std::vector> &&processors, const opentelemetry::sdk::resource::Resource &resource, - std::unique_ptr> - logger_configurator) noexcept + std::unique_ptr> logger_configurator) : context_{std::make_shared(std::move(processors), resource, - std::move(logger_configurator))} + std::move(logger_configurator))}, + noop_logger_(CreateNoopLoggerFallback()) {} -LoggerProvider::LoggerProvider() noexcept - : context_{std::make_shared(std::vector>{})} +LoggerProvider::LoggerProvider() + : context_{std::make_shared(std::vector>{})}, + noop_logger_(CreateNoopLoggerFallback()) {} -LoggerProvider::LoggerProvider(std::unique_ptr context) noexcept - : context_(std::move(context)) +LoggerProvider::LoggerProvider(std::unique_ptr context) + : context_(std::move(context)), noop_logger_(CreateNoopLoggerFallback()) {} LoggerProvider::~LoggerProvider() @@ -94,12 +125,29 @@ opentelemetry::nostd::shared_ptr LoggerProvider::Ge } } - std::unique_ptr lib = - instrumentationscope::InstrumentationScope::Create(name, version, schema_url, attributes); - - loggers_.push_back(std::shared_ptr( - new Logger(logger_name, context_, std::move(lib)))); - return opentelemetry::nostd::shared_ptr{loggers_.back()}; +#if OPENTELEMETRY_HAVE_EXCEPTIONS + try + { +#endif + std::unique_ptr lib = + instrumentationscope::InstrumentationScope::Create(name, version, schema_url, attributes); + + auto logger = std::make_shared(logger_name, context_, std::move(lib)); + loggers_.push_back(logger); + return opentelemetry::nostd::shared_ptr{logger}; +#if OPENTELEMETRY_HAVE_EXCEPTIONS + } + catch (const std::exception &ex) + { + LogGetLoggerConstructionFailure(ex.what()); + return noop_logger_; + } + catch (...) + { + LogGetLoggerConstructionFailure("unknown exception"); + return noop_logger_; + } +#endif } void LoggerProvider::AddProcessor(std::unique_ptr processor) noexcept diff --git a/sdk/src/metrics/meter.cc b/sdk/src/metrics/meter.cc index 0abd75265e..d442877a26 100644 --- a/sdk/src/metrics/meter.cc +++ b/sdk/src/metrics/meter.cc @@ -97,7 +97,7 @@ metrics::NoopMeter Meter::kNoopMeter = metrics::NoopMeter(); Meter::Meter( std::weak_ptr meter_context, - std::unique_ptr instrumentation_scope) noexcept + std::unique_ptr instrumentation_scope) : scope_{std::move(instrumentation_scope)}, meter_context_{std::move(meter_context)}, observable_registry_(new ObservableRegistry()), diff --git a/sdk/src/metrics/meter_provider.cc b/sdk/src/metrics/meter_provider.cc index f550d9bafa..900fdbfe0d 100644 --- a/sdk/src/metrics/meter_provider.cc +++ b/sdk/src/metrics/meter_provider.cc @@ -3,10 +3,14 @@ #include #include +#include +#include #include #include #include "opentelemetry/common/key_value_iterable.h" // IWYU pragma: keep +#include "opentelemetry/common/macros.h" +#include "opentelemetry/metrics/noop.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/span.h" #include "opentelemetry/nostd/string_view.h" @@ -38,16 +42,43 @@ namespace metrics namespace resource = opentelemetry::sdk::resource; namespace metrics_api = opentelemetry::metrics; -MeterProvider::MeterProvider(std::unique_ptr context) noexcept - : context_(std::move(context)) +namespace +{ + +nostd::shared_ptr CreateNoopMeterFallback() +{ + return nostd::shared_ptr(new metrics_api::NoopMeter()); +} + +void LogGetMeterConstructionFailure(const char *detail) noexcept +{ +#if OPENTELEMETRY_HAVE_EXCEPTIONS + try + { +#endif + OTEL_INTERNAL_LOG_ERROR("[MeterProvider::GetMeter] Failed to construct meter: " + << detail << "; returning noop meter."); +#if OPENTELEMETRY_HAVE_EXCEPTIONS + } + catch (...) + { + } +#endif +} + +} // namespace + +MeterProvider::MeterProvider(std::unique_ptr context) + : context_(std::move(context)), noop_meter_(CreateNoopMeterFallback()) {} MeterProvider::MeterProvider(std::unique_ptr views, const sdk::resource::Resource &resource, std::unique_ptr> - meter_configurator) noexcept + meter_configurator) : context_( - std::make_shared(std::move(views), resource, std::move(meter_configurator))) + std::make_shared(std::move(views), resource, std::move(meter_configurator))), + noop_meter_(CreateNoopMeterFallback()) { OTEL_INTERNAL_LOG_DEBUG("[MeterProvider] MeterProvider created."); } @@ -86,13 +117,30 @@ nostd::shared_ptr MeterProvider::GetMeter( } } - instrumentationscope::InstrumentationScopeAttributes attrs_map(attributes); - auto scope = - instrumentationscope::InstrumentationScope::Create(name, version, schema_url, attrs_map); - - auto meter = std::shared_ptr(new Meter(context_, std::move(scope))); - context_->AddMeter(meter); - return nostd::shared_ptr{meter}; +#if OPENTELEMETRY_HAVE_EXCEPTIONS + try + { +#endif + instrumentationscope::InstrumentationScopeAttributes attrs_map(attributes); + auto scope = + instrumentationscope::InstrumentationScope::Create(name, version, schema_url, attrs_map); + + auto meter = std::make_shared(context_, std::move(scope)); + context_->AddMeter(meter); + return nostd::shared_ptr{meter}; +#if OPENTELEMETRY_HAVE_EXCEPTIONS + } + catch (const std::exception &ex) + { + LogGetMeterConstructionFailure(ex.what()); + return noop_meter_; + } + catch (...) + { + LogGetMeterConstructionFailure("unknown exception"); + return noop_meter_; + } +#endif } #if OPENTELEMETRY_ABI_VERSION_NO >= 2 diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 88e84b953d..8509dd6c5b 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -94,7 +94,7 @@ OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk } // namespace Tracer::Tracer(std::shared_ptr context, - std::unique_ptr instrumentation_scope) noexcept + std::unique_ptr instrumentation_scope) : instrumentation_scope_{std::move(instrumentation_scope)}, context_{std::move(context)}, tracer_config_(context_->GetTracerConfigurator().ComputeConfig(*instrumentation_scope_)), diff --git a/sdk/src/trace/tracer_provider.cc b/sdk/src/trace/tracer_provider.cc index 47d3bb98b9..545cb1bdcc 100644 --- a/sdk/src/trace/tracer_provider.cc +++ b/sdk/src/trace/tracer_provider.cc @@ -2,11 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include +#include #include #include #include #include "opentelemetry/common/key_value_iterable.h" // IWYU pragma: keep +#include "opentelemetry/common/macros.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/sdk/common/global_log_handler.h" @@ -21,6 +24,7 @@ #include "opentelemetry/sdk/trace/tracer_config.h" #include "opentelemetry/sdk/trace/tracer_context.h" #include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/noop.h" #include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -31,8 +35,37 @@ namespace trace namespace resource = opentelemetry::sdk::resource; namespace trace_api = opentelemetry::trace; -TracerProvider::TracerProvider(std::unique_ptr context) noexcept - : context_(std::move(context)) +namespace +{ + +nostd::shared_ptr CreateNoopTracerFallback() +{ + // Construct as NoopTracer so enable_shared_from_this is initialized; StartSpan + // relies on shared_from_this() for the static noop span. + nostd::shared_ptr tracer(new trace_api::NoopTracer()); + return nostd::shared_ptr(std::move(tracer)); +} + +void LogGetTracerConstructionFailure(const char *detail) noexcept +{ +#if OPENTELEMETRY_HAVE_EXCEPTIONS + try + { +#endif + OTEL_INTERNAL_LOG_ERROR("[TracerProvider::GetTracer] Failed to construct tracer: " + << detail << "; returning noop tracer."); +#if OPENTELEMETRY_HAVE_EXCEPTIONS + } + catch (...) + { + } +#endif +} + +} // namespace + +TracerProvider::TracerProvider(std::unique_ptr context) + : context_(std::move(context)), noop_tracer_(CreateNoopTracerFallback()) { OTEL_INTERNAL_LOG_DEBUG("[TracerProvider] TracerProvider created."); } @@ -43,7 +76,8 @@ TracerProvider::TracerProvider( std::unique_ptr sampler, std::unique_ptr id_generator, std::unique_ptr> tracer_configurator, - SpanLimits span_limits) noexcept + SpanLimits span_limits) + : noop_tracer_(CreateNoopTracerFallback()) { std::vector> processors; processors.push_back(std::move(processor)); @@ -58,13 +92,14 @@ TracerProvider::TracerProvider( std::unique_ptr sampler, std::unique_ptr id_generator, std::unique_ptr> tracer_configurator, - SpanLimits span_limits) noexcept + SpanLimits span_limits) : context_(std::make_shared(std::move(processors), resource, std::move(sampler), std::move(id_generator), std::move(tracer_configurator), - span_limits)) + span_limits)), + noop_tracer_(CreateNoopTracerFallback()) {} TracerProvider::~TracerProvider() @@ -116,13 +151,30 @@ nostd::shared_ptr TracerProvider::GetTracer( } } - instrumentationscope::InstrumentationScopeAttributes attrs_map(attributes); - auto scope = - instrumentationscope::InstrumentationScope::Create(name, version, schema_url, attrs_map); - - auto tracer = std::shared_ptr(new Tracer(context_, std::move(scope))); - tracers_.push_back(tracer); - return nostd::shared_ptr{tracer}; +#if OPENTELEMETRY_HAVE_EXCEPTIONS + try + { +#endif + instrumentationscope::InstrumentationScopeAttributes attrs_map(attributes); + auto scope = + instrumentationscope::InstrumentationScope::Create(name, version, schema_url, attrs_map); + + auto tracer = std::make_shared(context_, std::move(scope)); + tracers_.push_back(tracer); + return nostd::shared_ptr{tracer}; +#if OPENTELEMETRY_HAVE_EXCEPTIONS + } + catch (const std::exception &ex) + { + LogGetTracerConstructionFailure(ex.what()); + return noop_tracer_; + } + catch (...) + { + LogGetTracerConstructionFailure("unknown exception"); + return noop_tracer_; + } +#endif } void TracerProvider::AddProcessor(std::unique_ptr processor) noexcept diff --git a/sdk/test/logs/logger_provider_sdk_test.cc b/sdk/test/logs/logger_provider_sdk_test.cc index 3db9dcefc2..931e4397f2 100644 --- a/sdk/test/logs/logger_provider_sdk_test.cc +++ b/sdk/test/logs/logger_provider_sdk_test.cc @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -16,8 +18,10 @@ #include "opentelemetry/common/attribute_value.h" #include "opentelemetry/common/timestamp.h" +#include "opentelemetry/common/macros.h" #include "opentelemetry/logs/logger.h" #include "opentelemetry/logs/logger_provider.h" +#include "opentelemetry/logs/noop.h" #include "opentelemetry/logs/provider.h" #include "opentelemetry/logs/severity.h" #include "opentelemetry/nostd/shared_ptr.h" @@ -270,6 +274,29 @@ class DummyProcessor : public LogRecordProcessor bool ForceFlush(std::chrono::microseconds /* timeout */) noexcept override { return true; } bool Shutdown(std::chrono::microseconds /* timeout */) noexcept override { return true; } }; + +class CountingProcessor : public LogRecordProcessor +{ +public: + std::unique_ptr MakeRecordable() noexcept override + { + return std::unique_ptr(new DummyLogRecordable()); + } + + void OnEmit(std::unique_ptr &&record) noexcept override + { + ++emit_count_; + auto record_ptr = std::move(record); + } + + bool ForceFlush(std::chrono::microseconds /* timeout */) noexcept override { return true; } + bool Shutdown(std::chrono::microseconds /* timeout */) noexcept override { return true; } + + std::size_t emit_count() const { return emit_count_; } + +private: + std::size_t emit_count_{0}; +}; } // namespace TEST(LoggerProviderSDK, GetResource) @@ -641,3 +668,69 @@ TEST(LoggerProviderSDK, UpdateLoggerConfiguratorConcurrentEmit) stop.store(true, std::memory_order_relaxed); worker.join(); } + +TEST(LoggerProviderSDK, ConstructorsAreNotNoexcept) +{ + static_assert(!noexcept(LoggerProvider()), "LoggerProvider construction must be allowed to throw"); + static_assert(!noexcept(LoggerProvider(std::unique_ptr{})), + "LoggerProvider construction must be allowed to throw"); + static_assert(!noexcept(Logger("", std::shared_ptr{})), + "Logger construction must be allowed to throw"); +} + +#if OPENTELEMETRY_HAVE_EXCEPTIONS +TEST(LoggerProviderSDK, GetLoggerReturnsNoopOnConstructionFailure) +{ + auto should_throw = std::make_shared(true); + auto throwing_configurator = std::make_unique>( + scope_sdk::ScopeConfigurator::Builder(LoggerConfig::Default()) + .AddCondition( + [should_throw](const scope_sdk::InstrumentationScope &scope) { + if (scope.GetName() == "throwing-scope" && *should_throw) + { + throw std::runtime_error("injected logger construction failure"); + } + return false; + }, + LoggerConfig::Default()) + .Build()); + + auto *counting_processor = new CountingProcessor(); + std::unique_ptr processor(counting_processor); + LoggerProvider provider(std::move(processor), opentelemetry::sdk::resource::Resource::Create({}), + std::move(throwing_configurator)); + + auto cached = provider.GetLogger("cached-logger", "cached-scope"); + ASSERT_NE(cached, nullptr); +#ifdef OPENTELEMETRY_RTTI_ENABLED + ASSERT_NE(dynamic_cast(cached.get()), nullptr); +#endif + EXPECT_EQ(provider.GetLogger("cached-logger", "cached-scope"), cached); + + auto failed = provider.GetLogger("throwing-logger", "throwing-scope"); + ASSERT_NE(failed, nullptr); +#ifdef OPENTELEMETRY_RTTI_ENABLED + EXPECT_EQ(dynamic_cast(failed.get()), nullptr); +#endif + EXPECT_EQ(failed->GetName(), "noop logger"); + failed->Info("should-not-emit"); + provider.ForceFlush(); + EXPECT_EQ(counting_processor->emit_count(), 0u); + + auto failed_again = provider.GetLogger("throwing-logger", "throwing-scope"); + EXPECT_EQ(failed, failed_again); + + *should_throw = false; + auto recovered = provider.GetLogger("throwing-logger", "throwing-scope"); + ASSERT_NE(recovered, nullptr); + EXPECT_NE(recovered, failed); +#ifdef OPENTELEMETRY_RTTI_ENABLED + EXPECT_NE(dynamic_cast(recovered.get()), nullptr); +#endif + recovered->Info("should-emit"); + provider.ForceFlush(); + EXPECT_EQ(counting_processor->emit_count(), 1u); + + EXPECT_EQ(provider.GetLogger("cached-logger", "cached-scope"), cached); +} +#endif // OPENTELEMETRY_HAVE_EXCEPTIONS diff --git a/sdk/test/metrics/meter_provider_sdk_test.cc b/sdk/test/metrics/meter_provider_sdk_test.cc index 501273b597..25f4608187 100644 --- a/sdk/test/metrics/meter_provider_sdk_test.cc +++ b/sdk/test/metrics/meter_provider_sdk_test.cc @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -16,9 +17,15 @@ #include "opentelemetry/metrics/meter.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/sdk/common/global_log_handler.h" +#include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h" +#include "opentelemetry/sdk/instrumentationscope/scope_configurator.h" #include "opentelemetry/sdk/metrics/instruments.h" #include "opentelemetry/sdk/metrics/meter.h" +#include "opentelemetry/sdk/metrics/meter_config.h" +#include "opentelemetry/sdk/metrics/meter_context.h" #include "opentelemetry/sdk/metrics/meter_provider.h" +#include "opentelemetry/sdk/metrics/view/view_registry.h" +#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/metrics/meter_provider_factory.h" #include "opentelemetry/sdk/metrics/metric_reader.h" #include "opentelemetry/sdk/metrics/push_metric_exporter.h" @@ -520,3 +527,69 @@ TEST(MeterProvider, ExplicitShutdownNotWarnOnDestructionCheck) logs = log_handler.Drain(); EXPECT_TRUE(logs.empty()); } + +TEST(MeterProvider, ConstructorsAreNotNoexcept) +{ + static_assert(!noexcept(MeterProvider(std::unique_ptr{})), + "MeterProvider construction must be allowed to throw"); + static_assert(!noexcept(Meter(std::weak_ptr{})), + "Meter construction must be allowed to throw"); +} + +#if OPENTELEMETRY_HAVE_EXCEPTIONS +TEST(MeterProvider, GetMeterReturnsNoopOnConstructionFailure) +{ + auto should_throw = std::make_shared(true); + auto throwing_configurator = + std::make_unique>( + opentelemetry::sdk::instrumentationscope::ScopeConfigurator::Builder( + MeterConfig::Default()) + .AddCondition( + [should_throw]( + const opentelemetry::sdk::instrumentationscope::InstrumentationScope &scope) { + if (scope.GetName() == "throwing-scope" && *should_throw) + { + throw std::runtime_error("injected meter construction failure"); + } + return false; + }, + MeterConfig::Default()) + .Build()); + + MeterProvider provider(std::unique_ptr(new ViewRegistry()), + opentelemetry::sdk::resource::Resource::Create({}), + std::move(throwing_configurator)); + + auto cached = provider.GetMeter("cached-scope"); + ASSERT_NE(cached, nullptr); +#ifdef OPENTELEMETRY_RTTI_ENABLED + ASSERT_NE(dynamic_cast(cached.get()), nullptr); +#endif + EXPECT_EQ(provider.GetMeter("cached-scope"), cached); + + auto failed = provider.GetMeter("throwing-scope"); + ASSERT_NE(failed, nullptr); +#ifdef OPENTELEMETRY_RTTI_ENABLED + EXPECT_EQ(dynamic_cast(failed.get()), nullptr); +#endif + auto failed_counter = failed->CreateUInt64Counter("requests"); + ASSERT_NE(failed_counter, nullptr); + failed_counter->Add(1); + + auto failed_again = provider.GetMeter("throwing-scope"); + EXPECT_EQ(failed, failed_again); + + *should_throw = false; + auto recovered = provider.GetMeter("throwing-scope"); + ASSERT_NE(recovered, nullptr); + EXPECT_NE(recovered, failed); +#ifdef OPENTELEMETRY_RTTI_ENABLED + EXPECT_NE(dynamic_cast(recovered.get()), nullptr); +#endif + auto recovered_counter = recovered->CreateUInt64Counter("requests"); + ASSERT_NE(recovered_counter, nullptr); + recovered_counter->Add(1); + + EXPECT_EQ(provider.GetMeter("cached-scope"), cached); +} +#endif // OPENTELEMETRY_HAVE_EXCEPTIONS diff --git a/sdk/test/trace/tracer_provider_test.cc b/sdk/test/trace/tracer_provider_test.cc index 09868fd687..323b3c0a9e 100644 --- a/sdk/test/trace/tracer_provider_test.cc +++ b/sdk/test/trace/tracer_provider_test.cc @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -56,6 +58,7 @@ using opentelemetry::sdk::common::unsetenv; using namespace opentelemetry::sdk::trace; using namespace opentelemetry::sdk::resource; +using opentelemetry::sdk::instrumentationscope::InstrumentationScope; using opentelemetry::sdk::instrumentationscope::ScopeConfigurator; TEST(TracerProvider, GetTracer) @@ -699,3 +702,77 @@ TEST(TracerProvider, SpanLimitsTracerProviderFactoryCreateDefault) EXPECT_EQ(limits.link_attribute_count_limit, no_limits.link_attribute_count_limit); EXPECT_EQ(limits.attribute_value_length_limit, no_limits.attribute_value_length_limit); } + +TEST(TracerProvider, ConstructorsAreNotNoexcept) +{ + static_assert(!noexcept(TracerProvider(std::unique_ptr{})), + "TracerProvider construction must be allowed to throw"); + static_assert(!noexcept(Tracer(std::shared_ptr{})), + "Tracer construction must be allowed to throw"); +} + +#if OPENTELEMETRY_HAVE_EXCEPTIONS +TEST(TracerProvider, GetTracerReturnsNoopOnConstructionFailure) +{ + auto should_throw = std::make_shared(true); + auto throwing_configurator = std::make_unique>( + ScopeConfigurator::Builder(TracerConfig::Default()) + .AddCondition( + [should_throw](const InstrumentationScope &scope) { + if (scope.GetName() == "throwing-scope" && *should_throw) + { + throw std::runtime_error("injected tracer construction failure"); + } + return false; + }, + TracerConfig::Default()) + .Build()); + + std::unique_ptr exporter( + new opentelemetry::exporter::memory::InMemorySpanExporter()); + auto span_data = exporter->GetData(); + auto processor = SimpleSpanProcessorFactory::Create(std::move(exporter)); + TracerProvider provider(std::move(processor), Resource::Create({}), + std::unique_ptr(new AlwaysOnSampler()), + std::unique_ptr(new RandomIdGenerator()), + std::move(throwing_configurator)); + + auto cached = provider.GetTracer("cached-scope"); + ASSERT_NE(cached, nullptr); +#ifdef OPENTELEMETRY_RTTI_ENABLED + ASSERT_NE(dynamic_cast(cached.get()), nullptr); +#endif + auto cached_again = provider.GetTracer("cached-scope"); + EXPECT_EQ(cached, cached_again); + + auto failed = provider.GetTracer("throwing-scope"); + ASSERT_NE(failed, nullptr); +#ifdef OPENTELEMETRY_RTTI_ENABLED + EXPECT_EQ(dynamic_cast(failed.get()), nullptr); +#endif + auto failed_span = failed->StartSpan("should-not-record"); + ASSERT_NE(failed_span, nullptr); + EXPECT_FALSE(failed_span->IsRecording()); + failed_span->End(); + provider.ForceFlush(); + EXPECT_EQ(span_data->GetSpans().size(), 0u); + + auto failed_again = provider.GetTracer("throwing-scope"); + EXPECT_EQ(failed, failed_again); + + *should_throw = false; + auto recovered = provider.GetTracer("throwing-scope"); + ASSERT_NE(recovered, nullptr); + EXPECT_NE(recovered, failed); +#ifdef OPENTELEMETRY_RTTI_ENABLED + EXPECT_NE(dynamic_cast(recovered.get()), nullptr); +#endif + auto recovered_span = recovered->StartSpan("should-record"); + EXPECT_TRUE(recovered_span->IsRecording()); + recovered_span->End(); + provider.ForceFlush(); + EXPECT_EQ(span_data->GetSpans().size(), 1u); + + EXPECT_EQ(provider.GetTracer("cached-scope"), cached); +} +#endif // OPENTELEMETRY_HAVE_EXCEPTIONS From a25cb86cbf5aa3cc648853ee1f19f3d66a739a24 Mon Sep 17 00:00:00 2001 From: elix3r <157088510+22elix3r@users.noreply.github.com> Date: Sat, 22 Aug 2026 18:59:49 +0530 Subject: [PATCH 2/5] [SDK] Format provider construction changes and fix empty catch Signed-off-by: elix3r <157088510+22elix3r@users.noreply.github.com> --- sdk/src/logs/logger.cc | 7 +++---- sdk/src/logs/logger_provider.cc | 2 +- sdk/src/metrics/meter.cc | 5 ++--- sdk/src/metrics/meter_provider.cc | 15 +++++++------- sdk/src/trace/tracer_provider.cc | 2 +- sdk/test/logs/logger_provider_sdk_test.cc | 22 ++++++++++---------- sdk/test/metrics/meter_provider_sdk_test.cc | 18 ++++++++-------- sdk/test/trace/tracer_provider_test.cc | 23 ++++++++++----------- 8 files changed, 46 insertions(+), 48 deletions(-) diff --git a/sdk/src/logs/logger.cc b/sdk/src/logs/logger.cc index 4ea5f5d203..c60057e6a8 100644 --- a/sdk/src/logs/logger.cc +++ b/sdk/src/logs/logger.cc @@ -96,10 +96,9 @@ void StampSpanContextFromVariant( opentelemetry::logs::NoopLogger Logger::kNoopLogger = opentelemetry::logs::NoopLogger(); -Logger::Logger( - opentelemetry::nostd::string_view name, - std::shared_ptr context, - std::unique_ptr instrumentation_scope) +Logger::Logger(opentelemetry::nostd::string_view name, + std::shared_ptr context, + std::unique_ptr instrumentation_scope) : logger_name_(std::string(name)), instrumentation_scope_(std::move(instrumentation_scope)), context_(std::move(context)) diff --git a/sdk/src/logs/logger_provider.cc b/sdk/src/logs/logger_provider.cc index 397559a798..c6f8ee1e21 100644 --- a/sdk/src/logs/logger_provider.cc +++ b/sdk/src/logs/logger_provider.cc @@ -8,7 +8,6 @@ #include #include -#include "opentelemetry/common/macros.h" #include "opentelemetry/logs/noop.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" @@ -49,6 +48,7 @@ void LogGetLoggerConstructionFailure(const char *detail) noexcept } catch (...) { + // Logging must not throw from a noexcept GetLogger path. } #endif } diff --git a/sdk/src/metrics/meter.cc b/sdk/src/metrics/meter.cc index d442877a26..0f7ee6992b 100644 --- a/sdk/src/metrics/meter.cc +++ b/sdk/src/metrics/meter.cc @@ -95,9 +95,8 @@ namespace metrics = opentelemetry::metrics; metrics::NoopMeter Meter::kNoopMeter = metrics::NoopMeter(); -Meter::Meter( - std::weak_ptr meter_context, - std::unique_ptr instrumentation_scope) +Meter::Meter(std::weak_ptr meter_context, + std::unique_ptr instrumentation_scope) : scope_{std::move(instrumentation_scope)}, meter_context_{std::move(meter_context)}, observable_registry_(new ObservableRegistry()), diff --git a/sdk/src/metrics/meter_provider.cc b/sdk/src/metrics/meter_provider.cc index 900fdbfe0d..6cf4727288 100644 --- a/sdk/src/metrics/meter_provider.cc +++ b/sdk/src/metrics/meter_provider.cc @@ -9,7 +9,6 @@ #include #include "opentelemetry/common/key_value_iterable.h" // IWYU pragma: keep -#include "opentelemetry/common/macros.h" #include "opentelemetry/metrics/noop.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/span.h" @@ -62,6 +61,7 @@ void LogGetMeterConstructionFailure(const char *detail) noexcept } catch (...) { + // Logging must not throw from a noexcept GetMeter path. } #endif } @@ -72,12 +72,13 @@ MeterProvider::MeterProvider(std::unique_ptr context) : context_(std::move(context)), noop_meter_(CreateNoopMeterFallback()) {} -MeterProvider::MeterProvider(std::unique_ptr views, - const sdk::resource::Resource &resource, - std::unique_ptr> - meter_configurator) - : context_( - std::make_shared(std::move(views), resource, std::move(meter_configurator))), +MeterProvider::MeterProvider( + std::unique_ptr views, + const sdk::resource::Resource &resource, + std::unique_ptr> meter_configurator) + : context_(std::make_shared(std::move(views), + resource, + std::move(meter_configurator))), noop_meter_(CreateNoopMeterFallback()) { OTEL_INTERNAL_LOG_DEBUG("[MeterProvider] MeterProvider created."); diff --git a/sdk/src/trace/tracer_provider.cc b/sdk/src/trace/tracer_provider.cc index 545cb1bdcc..b12d7e86b0 100644 --- a/sdk/src/trace/tracer_provider.cc +++ b/sdk/src/trace/tracer_provider.cc @@ -9,7 +9,6 @@ #include #include "opentelemetry/common/key_value_iterable.h" // IWYU pragma: keep -#include "opentelemetry/common/macros.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/sdk/common/global_log_handler.h" @@ -58,6 +57,7 @@ void LogGetTracerConstructionFailure(const char *detail) noexcept } catch (...) { + // Logging must not throw from a noexcept GetTracer path. } #endif } diff --git a/sdk/test/logs/logger_provider_sdk_test.cc b/sdk/test/logs/logger_provider_sdk_test.cc index 931e4397f2..aba5d42fac 100644 --- a/sdk/test/logs/logger_provider_sdk_test.cc +++ b/sdk/test/logs/logger_provider_sdk_test.cc @@ -17,11 +17,10 @@ #include #include "opentelemetry/common/attribute_value.h" -#include "opentelemetry/common/timestamp.h" #include "opentelemetry/common/macros.h" +#include "opentelemetry/common/timestamp.h" #include "opentelemetry/logs/logger.h" #include "opentelemetry/logs/logger_provider.h" -#include "opentelemetry/logs/noop.h" #include "opentelemetry/logs/provider.h" #include "opentelemetry/logs/severity.h" #include "opentelemetry/nostd/shared_ptr.h" @@ -671,7 +670,8 @@ TEST(LoggerProviderSDK, UpdateLoggerConfiguratorConcurrentEmit) TEST(LoggerProviderSDK, ConstructorsAreNotNoexcept) { - static_assert(!noexcept(LoggerProvider()), "LoggerProvider construction must be allowed to throw"); + static_assert(!noexcept(LoggerProvider()), + "LoggerProvider construction must be allowed to throw"); static_assert(!noexcept(LoggerProvider(std::unique_ptr{})), "LoggerProvider construction must be allowed to throw"); static_assert(!noexcept(Logger("", std::shared_ptr{})), @@ -681,7 +681,7 @@ TEST(LoggerProviderSDK, ConstructorsAreNotNoexcept) #if OPENTELEMETRY_HAVE_EXCEPTIONS TEST(LoggerProviderSDK, GetLoggerReturnsNoopOnConstructionFailure) { - auto should_throw = std::make_shared(true); + auto should_throw = std::make_shared(true); auto throwing_configurator = std::make_unique>( scope_sdk::ScopeConfigurator::Builder(LoggerConfig::Default()) .AddCondition( @@ -702,16 +702,16 @@ TEST(LoggerProviderSDK, GetLoggerReturnsNoopOnConstructionFailure) auto cached = provider.GetLogger("cached-logger", "cached-scope"); ASSERT_NE(cached, nullptr); -#ifdef OPENTELEMETRY_RTTI_ENABLED +# ifdef OPENTELEMETRY_RTTI_ENABLED ASSERT_NE(dynamic_cast(cached.get()), nullptr); -#endif +# endif EXPECT_EQ(provider.GetLogger("cached-logger", "cached-scope"), cached); auto failed = provider.GetLogger("throwing-logger", "throwing-scope"); ASSERT_NE(failed, nullptr); -#ifdef OPENTELEMETRY_RTTI_ENABLED +# ifdef OPENTELEMETRY_RTTI_ENABLED EXPECT_EQ(dynamic_cast(failed.get()), nullptr); -#endif +# endif EXPECT_EQ(failed->GetName(), "noop logger"); failed->Info("should-not-emit"); provider.ForceFlush(); @@ -720,13 +720,13 @@ TEST(LoggerProviderSDK, GetLoggerReturnsNoopOnConstructionFailure) auto failed_again = provider.GetLogger("throwing-logger", "throwing-scope"); EXPECT_EQ(failed, failed_again); - *should_throw = false; + *should_throw = false; auto recovered = provider.GetLogger("throwing-logger", "throwing-scope"); ASSERT_NE(recovered, nullptr); EXPECT_NE(recovered, failed); -#ifdef OPENTELEMETRY_RTTI_ENABLED +# ifdef OPENTELEMETRY_RTTI_ENABLED EXPECT_NE(dynamic_cast(recovered.get()), nullptr); -#endif +# endif recovered->Info("should-emit"); provider.ForceFlush(); EXPECT_EQ(counting_processor->emit_count(), 1u); diff --git a/sdk/test/metrics/meter_provider_sdk_test.cc b/sdk/test/metrics/meter_provider_sdk_test.cc index 25f4608187..e4d2d7495f 100644 --- a/sdk/test/metrics/meter_provider_sdk_test.cc +++ b/sdk/test/metrics/meter_provider_sdk_test.cc @@ -24,14 +24,14 @@ #include "opentelemetry/sdk/metrics/meter_config.h" #include "opentelemetry/sdk/metrics/meter_context.h" #include "opentelemetry/sdk/metrics/meter_provider.h" -#include "opentelemetry/sdk/metrics/view/view_registry.h" -#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/metrics/meter_provider_factory.h" #include "opentelemetry/sdk/metrics/metric_reader.h" #include "opentelemetry/sdk/metrics/push_metric_exporter.h" #include "opentelemetry/sdk/metrics/view/instrument_selector.h" #include "opentelemetry/sdk/metrics/view/meter_selector.h" #include "opentelemetry/sdk/metrics/view/view.h" +#include "opentelemetry/sdk/metrics/view/view_registry.h" +#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/test_common/sdk/common/scoped_test_log_handler.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW @@ -562,16 +562,16 @@ TEST(MeterProvider, GetMeterReturnsNoopOnConstructionFailure) auto cached = provider.GetMeter("cached-scope"); ASSERT_NE(cached, nullptr); -#ifdef OPENTELEMETRY_RTTI_ENABLED +# ifdef OPENTELEMETRY_RTTI_ENABLED ASSERT_NE(dynamic_cast(cached.get()), nullptr); -#endif +# endif EXPECT_EQ(provider.GetMeter("cached-scope"), cached); auto failed = provider.GetMeter("throwing-scope"); ASSERT_NE(failed, nullptr); -#ifdef OPENTELEMETRY_RTTI_ENABLED +# ifdef OPENTELEMETRY_RTTI_ENABLED EXPECT_EQ(dynamic_cast(failed.get()), nullptr); -#endif +# endif auto failed_counter = failed->CreateUInt64Counter("requests"); ASSERT_NE(failed_counter, nullptr); failed_counter->Add(1); @@ -579,13 +579,13 @@ TEST(MeterProvider, GetMeterReturnsNoopOnConstructionFailure) auto failed_again = provider.GetMeter("throwing-scope"); EXPECT_EQ(failed, failed_again); - *should_throw = false; + *should_throw = false; auto recovered = provider.GetMeter("throwing-scope"); ASSERT_NE(recovered, nullptr); EXPECT_NE(recovered, failed); -#ifdef OPENTELEMETRY_RTTI_ENABLED +# ifdef OPENTELEMETRY_RTTI_ENABLED EXPECT_NE(dynamic_cast(recovered.get()), nullptr); -#endif +# endif auto recovered_counter = recovered->CreateUInt64Counter("requests"); ASSERT_NE(recovered_counter, nullptr); recovered_counter->Add(1); diff --git a/sdk/test/trace/tracer_provider_test.cc b/sdk/test/trace/tracer_provider_test.cc index 323b3c0a9e..e640e3d8b6 100644 --- a/sdk/test/trace/tracer_provider_test.cc +++ b/sdk/test/trace/tracer_provider_test.cc @@ -714,7 +714,7 @@ TEST(TracerProvider, ConstructorsAreNotNoexcept) #if OPENTELEMETRY_HAVE_EXCEPTIONS TEST(TracerProvider, GetTracerReturnsNoopOnConstructionFailure) { - auto should_throw = std::make_shared(true); + auto should_throw = std::make_shared(true); auto throwing_configurator = std::make_unique>( ScopeConfigurator::Builder(TracerConfig::Default()) .AddCondition( @@ -732,24 +732,23 @@ TEST(TracerProvider, GetTracerReturnsNoopOnConstructionFailure) new opentelemetry::exporter::memory::InMemorySpanExporter()); auto span_data = exporter->GetData(); auto processor = SimpleSpanProcessorFactory::Create(std::move(exporter)); - TracerProvider provider(std::move(processor), Resource::Create({}), - std::unique_ptr(new AlwaysOnSampler()), - std::unique_ptr(new RandomIdGenerator()), - std::move(throwing_configurator)); + TracerProvider provider( + std::move(processor), Resource::Create({}), std::unique_ptr(new AlwaysOnSampler()), + std::unique_ptr(new RandomIdGenerator()), std::move(throwing_configurator)); auto cached = provider.GetTracer("cached-scope"); ASSERT_NE(cached, nullptr); -#ifdef OPENTELEMETRY_RTTI_ENABLED +# ifdef OPENTELEMETRY_RTTI_ENABLED ASSERT_NE(dynamic_cast(cached.get()), nullptr); -#endif +# endif auto cached_again = provider.GetTracer("cached-scope"); EXPECT_EQ(cached, cached_again); auto failed = provider.GetTracer("throwing-scope"); ASSERT_NE(failed, nullptr); -#ifdef OPENTELEMETRY_RTTI_ENABLED +# ifdef OPENTELEMETRY_RTTI_ENABLED EXPECT_EQ(dynamic_cast(failed.get()), nullptr); -#endif +# endif auto failed_span = failed->StartSpan("should-not-record"); ASSERT_NE(failed_span, nullptr); EXPECT_FALSE(failed_span->IsRecording()); @@ -760,13 +759,13 @@ TEST(TracerProvider, GetTracerReturnsNoopOnConstructionFailure) auto failed_again = provider.GetTracer("throwing-scope"); EXPECT_EQ(failed, failed_again); - *should_throw = false; + *should_throw = false; auto recovered = provider.GetTracer("throwing-scope"); ASSERT_NE(recovered, nullptr); EXPECT_NE(recovered, failed); -#ifdef OPENTELEMETRY_RTTI_ENABLED +# ifdef OPENTELEMETRY_RTTI_ENABLED EXPECT_NE(dynamic_cast(recovered.get()), nullptr); -#endif +# endif auto recovered_span = recovered->StartSpan("should-record"); EXPECT_TRUE(recovered_span->IsRecording()); recovered_span->End(); From 38e1c26305e2c7c13856fe83a0677f14c633cc35 Mon Sep 17 00:00:00 2001 From: elix3r <157088510+22elix3r@users.noreply.github.com> Date: Sat, 22 Aug 2026 20:56:43 +0530 Subject: [PATCH 3/5] [SDK] Drop unused OnEmit local in CountingProcessor Signed-off-by: elix3r <157088510+22elix3r@users.noreply.github.com> --- sdk/test/logs/logger_provider_sdk_test.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sdk/test/logs/logger_provider_sdk_test.cc b/sdk/test/logs/logger_provider_sdk_test.cc index aba5d42fac..dc703986e6 100644 --- a/sdk/test/logs/logger_provider_sdk_test.cc +++ b/sdk/test/logs/logger_provider_sdk_test.cc @@ -282,11 +282,7 @@ class CountingProcessor : public LogRecordProcessor return std::unique_ptr(new DummyLogRecordable()); } - void OnEmit(std::unique_ptr &&record) noexcept override - { - ++emit_count_; - auto record_ptr = std::move(record); - } + void OnEmit(std::unique_ptr && /* record */) noexcept override { ++emit_count_; } bool ForceFlush(std::chrono::microseconds /* timeout */) noexcept override { return true; } bool Shutdown(std::chrono::microseconds /* timeout */) noexcept override { return true; } From 923789d3db30f9accead43f33c8f6c4f10de5fd2 Mon Sep 17 00:00:00 2001 From: elix3r <157088510+22elix3r@users.noreply.github.com> Date: Wed, 26 Aug 2026 03:44:19 +0530 Subject: [PATCH 4/5] [SDK] Fix IWYU and clang-tidy on construction fallback Restore CountingProcessor ownership of the OnEmit record via std::move. Add the includes IWYU asked for, and mark empty logging catches so clang-tidy does not count them against the unique-warning limit. Signed-off-by: elix3r <157088510+22elix3r@users.noreply.github.com> --- sdk/src/logs/logger_provider.cc | 5 +++-- sdk/src/metrics/meter_provider.cc | 5 +++-- sdk/src/trace/tracer_provider.cc | 5 +++-- sdk/test/logs/logger_provider_sdk_test.cc | 6 +++++- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/sdk/src/logs/logger_provider.cc b/sdk/src/logs/logger_provider.cc index c6f8ee1e21..3eda509c8a 100644 --- a/sdk/src/logs/logger_provider.cc +++ b/sdk/src/logs/logger_provider.cc @@ -3,11 +3,12 @@ #include #include -#include #include +#include #include #include +#include "opentelemetry/logs/logger.h" #include "opentelemetry/logs/noop.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" @@ -46,7 +47,7 @@ void LogGetLoggerConstructionFailure(const char *detail) noexcept << detail << "; returning noop logger."); #if OPENTELEMETRY_HAVE_EXCEPTIONS } - catch (...) + catch (...) // NOLINT(bugprone-empty-catch) { // Logging must not throw from a noexcept GetLogger path. } diff --git a/sdk/src/metrics/meter_provider.cc b/sdk/src/metrics/meter_provider.cc index 6cf4727288..081211c278 100644 --- a/sdk/src/metrics/meter_provider.cc +++ b/sdk/src/metrics/meter_provider.cc @@ -4,11 +4,12 @@ #include #include #include -#include #include +#include #include #include "opentelemetry/common/key_value_iterable.h" // IWYU pragma: keep +#include "opentelemetry/metrics/meter.h" #include "opentelemetry/metrics/noop.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/span.h" @@ -59,7 +60,7 @@ void LogGetMeterConstructionFailure(const char *detail) noexcept << detail << "; returning noop meter."); #if OPENTELEMETRY_HAVE_EXCEPTIONS } - catch (...) + catch (...) // NOLINT(bugprone-empty-catch) { // Logging must not throw from a noexcept GetMeter path. } diff --git a/sdk/src/trace/tracer_provider.cc b/sdk/src/trace/tracer_provider.cc index b12d7e86b0..efd5aca0cf 100644 --- a/sdk/src/trace/tracer_provider.cc +++ b/sdk/src/trace/tracer_provider.cc @@ -3,8 +3,8 @@ #include #include -#include #include +#include #include #include @@ -24,6 +24,7 @@ #include "opentelemetry/sdk/trace/tracer_context.h" #include "opentelemetry/sdk/trace/tracer_provider.h" #include "opentelemetry/trace/noop.h" +#include "opentelemetry/trace/tracer.h" #include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -55,7 +56,7 @@ void LogGetTracerConstructionFailure(const char *detail) noexcept << detail << "; returning noop tracer."); #if OPENTELEMETRY_HAVE_EXCEPTIONS } - catch (...) + catch (...) // NOLINT(bugprone-empty-catch) { // Logging must not throw from a noexcept GetTracer path. } diff --git a/sdk/test/logs/logger_provider_sdk_test.cc b/sdk/test/logs/logger_provider_sdk_test.cc index dc703986e6..23483e62ba 100644 --- a/sdk/test/logs/logger_provider_sdk_test.cc +++ b/sdk/test/logs/logger_provider_sdk_test.cc @@ -282,7 +282,11 @@ class CountingProcessor : public LogRecordProcessor return std::unique_ptr(new DummyLogRecordable()); } - void OnEmit(std::unique_ptr && /* record */) noexcept override { ++emit_count_; } + void OnEmit(std::unique_ptr &&record) noexcept override + { + auto record_ptr = std::move(record); + ++emit_count_; + } bool ForceFlush(std::chrono::microseconds /* timeout */) noexcept override { return true; } bool Shutdown(std::chrono::microseconds /* timeout */) noexcept override { return true; } From ff059b949870e89f5e752c887cd65abcc9da7bb9 Mon Sep 17 00:00:00 2001 From: elix3r <157088510+22elix3r@users.noreply.github.com> Date: Thu, 27 Aug 2026 02:40:15 +0530 Subject: [PATCH 5/5] [SDK] Catch std::exception from Get* failure logging Logging can throw std::bad_alloc from the string stream. Catch std::exception in the GetTracer/GetLogger/GetMeter logging helpers instead of (...). Document why the construction catch-all remains: user scope configurators can throw any exception type. Signed-off-by: elix3r <157088510+22elix3r@users.noreply.github.com> --- sdk/src/logs/logger_provider.cc | 7 +++++-- sdk/src/metrics/meter_provider.cc | 7 +++++-- sdk/src/trace/tracer_provider.cc | 7 +++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/sdk/src/logs/logger_provider.cc b/sdk/src/logs/logger_provider.cc index 3eda509c8a..37670e3ebb 100644 --- a/sdk/src/logs/logger_provider.cc +++ b/sdk/src/logs/logger_provider.cc @@ -47,9 +47,10 @@ void LogGetLoggerConstructionFailure(const char *detail) noexcept << detail << "; returning noop logger."); #if OPENTELEMETRY_HAVE_EXCEPTIONS } - catch (...) // NOLINT(bugprone-empty-catch) + catch (const std::exception &) // NOLINT(bugprone-empty-catch) { - // Logging must not throw from a noexcept GetLogger path. + // Logging can throw (typically std::bad_alloc from the string stream). + // Swallow it so the noexcept GetLogger path cannot throw. } #endif } @@ -143,6 +144,8 @@ opentelemetry::nostd::shared_ptr LoggerProvider::Ge LogGetLoggerConstructionFailure(ex.what()); return noop_logger_; } + // User-provided scope configurators can throw any exception type, not just + // std::exception. Catch everything so GetLogger stays noexcept. catch (...) { LogGetLoggerConstructionFailure("unknown exception"); diff --git a/sdk/src/metrics/meter_provider.cc b/sdk/src/metrics/meter_provider.cc index 42630244e1..38d8496c02 100644 --- a/sdk/src/metrics/meter_provider.cc +++ b/sdk/src/metrics/meter_provider.cc @@ -60,9 +60,10 @@ void LogGetMeterConstructionFailure(const char *detail) noexcept << detail << "; returning noop meter."); #if OPENTELEMETRY_HAVE_EXCEPTIONS } - catch (...) // NOLINT(bugprone-empty-catch) + catch (const std::exception &) // NOLINT(bugprone-empty-catch) { - // Logging must not throw from a noexcept GetMeter path. + // Logging can throw (typically std::bad_alloc from the string stream). + // Swallow it so the noexcept GetMeter path cannot throw. } #endif } @@ -147,6 +148,8 @@ nostd::shared_ptr MeterProvider::GetMeter( LogGetMeterConstructionFailure(ex.what()); return noop_meter_; } + // User-provided scope configurators can throw any exception type, not just + // std::exception. Catch everything so GetMeter stays noexcept. catch (...) { LogGetMeterConstructionFailure("unknown exception"); diff --git a/sdk/src/trace/tracer_provider.cc b/sdk/src/trace/tracer_provider.cc index efd5aca0cf..dae9996b6f 100644 --- a/sdk/src/trace/tracer_provider.cc +++ b/sdk/src/trace/tracer_provider.cc @@ -56,9 +56,10 @@ void LogGetTracerConstructionFailure(const char *detail) noexcept << detail << "; returning noop tracer."); #if OPENTELEMETRY_HAVE_EXCEPTIONS } - catch (...) // NOLINT(bugprone-empty-catch) + catch (const std::exception &) // NOLINT(bugprone-empty-catch) { - // Logging must not throw from a noexcept GetTracer path. + // Logging can throw (typically std::bad_alloc from the string stream). + // Swallow it so the noexcept GetTracer path cannot throw. } #endif } @@ -170,6 +171,8 @@ nostd::shared_ptr TracerProvider::GetTracer( LogGetTracerConstructionFailure(ex.what()); return noop_tracer_; } + // User-provided scope configurators can throw any exception type, not just + // std::exception. Catch everything so GetTracer stays noexcept. catch (...) { LogGetTracerConstructionFailure("unknown exception");