Skip to content
Open
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
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
10 changes: 6 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,8 @@ 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_;
};
} // 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
6 changes: 4 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,8 @@ 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_;

#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
8 changes: 5 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,8 @@ 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_;
};
} // 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
82 changes: 67 additions & 15 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,31 @@ opentelemetry::nostd::shared_ptr<opentelemetry::logs::Logger> LoggerProvider::Ge
}
}

std::unique_ptr<instrumentationscope::InstrumentationScope> lib =
instrumentationscope::InstrumentationScope::Create(name, version, schema_url, attributes);

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)
{
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");
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