Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ Increment the:
to compile standalone on newer standard library implementations.
[#4574](https://github.com/open-telemetry/opentelemetry-cpp/pull/4574)

Breaking changes:

* [SDK] Remove `noexcept` from the public SDK `TracerProvider`,
`LoggerProvider`, `MeterProvider`, `Tracer`, `Logger`, and `Meter`
constructors so initialization failures can propagate to callers.
`GetTracer`, `GetLogger`, and `GetMeter` remain `noexcept` and return a
pre-allocated noop object if constructing a new instrumentation object
fails. After the first failure, later uncached `Get*` calls return the same
noop immediately without retrying construction. Existing cached objects
continue to be returned.
[#4361](https://github.com/open-telemetry/opentelemetry-cpp/issues/4361)

## [1.29.0] 2026-09-13

* [RELEASE] Bump main branch to 1.29.0-dev (#4259)
Expand Down
2 changes: 1 addition & 1 deletion sdk/include/opentelemetry/sdk/logs/logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class Logger final : public opentelemetry::logs::Logger
opentelemetry::nostd::string_view name,
std::shared_ptr<LoggerContext> context,
std::unique_ptr<instrumentationscope::InstrumentationScope> instrumentation_scope =
instrumentationscope::InstrumentationScope::Create("")) noexcept;
instrumentationscope::InstrumentationScope::Create(""));

/**
* Returns the name of this logger.
Expand Down
13 changes: 9 additions & 4 deletions sdk/include/opentelemetry/sdk/logs/logger_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class OPENTELEMETRY_EXPORT LoggerProvider final : public opentelemetry::logs::Lo
std::make_unique<instrumentationscope::ScopeConfigurator<LoggerConfig>>(
instrumentationscope::ScopeConfigurator<LoggerConfig>::Builder(
LoggerConfig::Default())
.Build())) noexcept;
.Build()));

/**
* Initialize a new logger provider.
Expand All @@ -62,19 +62,19 @@ class OPENTELEMETRY_EXPORT LoggerProvider final : public opentelemetry::logs::Lo
std::make_unique<instrumentationscope::ScopeConfigurator<LoggerConfig>>(
instrumentationscope::ScopeConfigurator<LoggerConfig>::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<LoggerContext> context) noexcept;
explicit LoggerProvider(std::unique_ptr<LoggerContext> context);

LoggerProvider(const LoggerProvider &) = delete;
LoggerProvider(LoggerProvider &&) = delete;
Expand Down Expand Up @@ -144,6 +144,11 @@ class OPENTELEMETRY_EXPORT LoggerProvider final : public opentelemetry::logs::Lo
std::vector<std::shared_ptr<opentelemetry::sdk::logs::Logger>> loggers_;
std::shared_ptr<LoggerContext> context_;
std::mutex lock_;
// Allocated during provider construction so GetLogger can return it without allocating.
nostd::shared_ptr<opentelemetry::logs::Logger> noop_logger_;
// Set on the first GetLogger construction failure. Later uncached GetLogger
// calls return the preallocated noop without retrying construction.
bool construction_failed_{false};
};
} // namespace logs
} // namespace sdk
Expand Down
2 changes: 1 addition & 1 deletion sdk/include/opentelemetry/sdk/metrics/meter.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class Meter final : public opentelemetry::metrics::Meter
explicit Meter(
std::weak_ptr<sdk::metrics::MeterContext> meter_context,
std::unique_ptr<opentelemetry::sdk::instrumentationscope::InstrumentationScope> scope =
opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create("")) noexcept;
opentelemetry::sdk::instrumentationscope::InstrumentationScope::Create(""));

nostd::unique_ptr<opentelemetry::metrics::Counter<uint64_t>> CreateUInt64Counter(
nostd::string_view name,
Expand Down
9 changes: 7 additions & 2 deletions sdk/include/opentelemetry/sdk/metrics/meter_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,13 @@ class OPENTELEMETRY_EXPORT MeterProvider final : public opentelemetry::metrics::
std::unique_ptr<instrumentationscope::ScopeConfigurator<MeterConfig>> meter_configurator =
std::make_unique<instrumentationscope::ScopeConfigurator<MeterConfig>>(
instrumentationscope::ScopeConfigurator<MeterConfig>::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<MeterContext> context) noexcept;
explicit MeterProvider(std::unique_ptr<MeterContext> context);

MeterProvider(const MeterProvider &) = delete;
MeterProvider(MeterProvider &&) = delete;
Expand Down Expand Up @@ -152,6 +152,11 @@ class OPENTELEMETRY_EXPORT MeterProvider final : public opentelemetry::metrics::
private:
std::shared_ptr<MeterContext> context_;
std::mutex lock_;
// Allocated during provider construction so GetMeter can return it without allocating.
nostd::shared_ptr<opentelemetry::metrics::Meter> noop_meter_;
// Set on the first GetMeter construction failure. Later uncached GetMeter
// calls return the preallocated noop without retrying construction.
bool construction_failed_{false};

#if defined(__cpp_lib_atomic_value_initialization) && \
__cpp_lib_atomic_value_initialization >= 201911L
Expand Down
2 changes: 1 addition & 1 deletion sdk/include/opentelemetry/sdk/trace/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<TracerContext> context,
std::unique_ptr<InstrumentationScope> instrumentation_scope =
InstrumentationScope::Create("")) noexcept;
InstrumentationScope::Create(""));

nostd::shared_ptr<opentelemetry::trace::Span> StartSpan(
nostd::string_view name,
Expand Down
11 changes: 8 additions & 3 deletions sdk/include/opentelemetry/sdk/trace/tracer_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class OPENTELEMETRY_EXPORT TracerProvider final : public opentelemetry::trace::T
instrumentationscope::ScopeConfigurator<TracerConfig>::Builder(
TracerConfig::Default())
.Build()),
SpanLimits span_limits = SpanLimits::NoLimits()) noexcept;
SpanLimits span_limits = SpanLimits::NoLimits());

explicit TracerProvider(
std::vector<std::unique_ptr<SpanProcessor>> &&processors,
Expand All @@ -70,13 +70,13 @@ class OPENTELEMETRY_EXPORT TracerProvider final : public opentelemetry::trace::T
instrumentationscope::ScopeConfigurator<TracerConfig>::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<TracerContext> context) noexcept;
explicit TracerProvider(std::unique_ptr<TracerContext> context);

TracerProvider(const TracerProvider &) = delete;
TracerProvider(TracerProvider &&) = delete;
Expand Down Expand Up @@ -155,6 +155,11 @@ class OPENTELEMETRY_EXPORT TracerProvider final : public opentelemetry::trace::T
std::vector<std::shared_ptr<Tracer>> tracers_;
std::shared_ptr<TracerContext> context_;
std::mutex lock_;
// Allocated during provider construction so GetTracer can return it without allocating.
nostd::shared_ptr<opentelemetry::trace::Tracer> noop_tracer_;
// Set on the first GetTracer construction failure. Later uncached GetTracer
// calls return the preallocated noop without retrying construction.
bool construction_failed_{false};
};
} // namespace trace
} // namespace sdk
Expand Down
7 changes: 3 additions & 4 deletions sdk/src/logs/logger.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,9 @@ void StampSpanContextFromVariant(

opentelemetry::logs::NoopLogger Logger::kNoopLogger = opentelemetry::logs::NoopLogger();

Logger::Logger(
opentelemetry::nostd::string_view name,
std::shared_ptr<LoggerContext> context,
std::unique_ptr<instrumentationscope::InstrumentationScope> instrumentation_scope) noexcept
Logger::Logger(opentelemetry::nostd::string_view name,
std::shared_ptr<LoggerContext> context,
std::unique_ptr<instrumentationscope::InstrumentationScope> instrumentation_scope)
: logger_name_(std::string(name)),
instrumentation_scope_(std::move(instrumentation_scope)),
context_(std::move(context))
Expand Down
91 changes: 77 additions & 14 deletions sdk/src/logs/logger_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
// SPDX-License-Identifier: Apache-2.0

#include <chrono>
#include <exception>
#include <mutex>
#include <ostream>
#include <utility>
#include <vector>

#include "opentelemetry/logs/logger.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"
Expand All @@ -25,11 +29,39 @@ namespace sdk
namespace logs
{

namespace
{

nostd::shared_ptr<opentelemetry::logs::Logger> CreateNoopLoggerFallback()
{
return nostd::shared_ptr<opentelemetry::logs::Logger>(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 (const std::exception &) // NOLINT(bugprone-empty-catch)
{
// Logging can throw (typically std::bad_alloc from the string stream).
// Swallow it so the noexcept GetLogger path cannot throw.
}
#endif
}

} // namespace

LoggerProvider::LoggerProvider(
std::unique_ptr<LogRecordProcessor> &&processor,
const opentelemetry::sdk::resource::Resource &resource,
std::unique_ptr<instrumentationscope::ScopeConfigurator<LoggerConfig>>
logger_configurator) noexcept
std::unique_ptr<instrumentationscope::ScopeConfigurator<LoggerConfig>> logger_configurator)
: noop_logger_(CreateNoopLoggerFallback())
{
std::vector<std::unique_ptr<LogRecordProcessor>> processors;
processors.emplace_back(std::move(processor));
Expand All @@ -41,19 +73,20 @@ LoggerProvider::LoggerProvider(
LoggerProvider::LoggerProvider(
std::vector<std::unique_ptr<LogRecordProcessor>> &&processors,
const opentelemetry::sdk::resource::Resource &resource,
std::unique_ptr<instrumentationscope::ScopeConfigurator<LoggerConfig>>
logger_configurator) noexcept
std::unique_ptr<instrumentationscope::ScopeConfigurator<LoggerConfig>> logger_configurator)
: context_{std::make_shared<LoggerContext>(std::move(processors),
resource,
std::move(logger_configurator))}
std::move(logger_configurator))},
noop_logger_(CreateNoopLoggerFallback())
{}

LoggerProvider::LoggerProvider() noexcept
: context_{std::make_shared<LoggerContext>(std::vector<std::unique_ptr<LogRecordProcessor>>{})}
LoggerProvider::LoggerProvider()
: context_{std::make_shared<LoggerContext>(std::vector<std::unique_ptr<LogRecordProcessor>>{})},
noop_logger_(CreateNoopLoggerFallback())
{}

LoggerProvider::LoggerProvider(std::unique_ptr<LoggerContext> context) noexcept
: context_(std::move(context))
LoggerProvider::LoggerProvider(std::unique_ptr<LoggerContext> context)
: context_(std::move(context)), noop_logger_(CreateNoopLoggerFallback())
{}

LoggerProvider::~LoggerProvider()
Expand Down Expand Up @@ -94,12 +127,42 @@ opentelemetry::nostd::shared_ptr<opentelemetry::logs::Logger> LoggerProvider::Ge
}
}

std::unique_ptr<instrumentationscope::InstrumentationScope> lib =
instrumentationscope::InstrumentationScope::Create(name, version, schema_url, attributes);
// GetLogger is noexcept and does not surface an error, so callers cannot
// recover after a construction failure. Retrying would re-throw, catch, and
// log on later GetLogger calls. After the first failure, treat the provider
// as non-functional for new loggers.
if (construction_failed_)
{
return noop_logger_;
}

loggers_.push_back(std::shared_ptr<opentelemetry::sdk::logs::Logger>(
new Logger(logger_name, context_, std::move(lib))));
return opentelemetry::nostd::shared_ptr<opentelemetry::logs::Logger>{loggers_.back()};
#if OPENTELEMETRY_HAVE_EXCEPTIONS
try
{
#endif
std::unique_ptr<instrumentationscope::InstrumentationScope> lib =
instrumentationscope::InstrumentationScope::Create(name, version, schema_url, attributes);

auto logger = std::make_shared<Logger>(logger_name, context_, std::move(lib));
loggers_.push_back(logger);
return opentelemetry::nostd::shared_ptr<opentelemetry::logs::Logger>{logger};
#if OPENTELEMETRY_HAVE_EXCEPTIONS
}
catch (const std::exception &ex)
{
construction_failed_ = true;
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 (...)
{
construction_failed_ = true;
LogGetLoggerConstructionFailure("unknown exception");
return noop_logger_;
}
#endif
}

void LoggerProvider::AddProcessor(std::unique_ptr<LogRecordProcessor> processor) noexcept
Expand Down
5 changes: 2 additions & 3 deletions sdk/src/metrics/meter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,8 @@ namespace metrics = opentelemetry::metrics;

metrics::NoopMeter Meter::kNoopMeter = metrics::NoopMeter();

Meter::Meter(
std::weak_ptr<MeterContext> meter_context,
std::unique_ptr<sdk::instrumentationscope::InstrumentationScope> instrumentation_scope) noexcept
Meter::Meter(std::weak_ptr<MeterContext> meter_context,
std::unique_ptr<sdk::instrumentationscope::InstrumentationScope> instrumentation_scope)
: scope_{std::move(instrumentation_scope)},
meter_context_{std::move(meter_context)},
observable_registry_(new ObservableRegistry()),
Expand Down
Loading
Loading