From c82730a5a708b06aebffeda5becb826951ac3db1 Mon Sep 17 00:00:00 2001 From: ayush-singh-0601 Date: Fri, 21 Aug 2026 20:59:36 +0530 Subject: [PATCH 1/6] [CONFIGURATION] Apply general attribute_limits to tracer and logger providers The YAML parser already accepted attribute_limits, but SdkBuilder ignored them. Pass the general limits into CreateTracerProvider and CreateLoggerProvider, and use them when the provider has no model-specific limits. Provider limits still take precedence. Fixes #4467 --- CHANGELOG.md | 5 + .../sdk/configuration/sdk_builder.h | 11 ++ sdk/src/configuration/sdk_builder.cc | 76 +++++++++-- .../programmatic_configuration_test.cc | 121 ++++++++++++++++++ sdk/test/configuration/sdk_builder_test.cc | 50 ++++++++ 5 files changed, 254 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4206a3015..4ed61d433 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ Increment the: ## [Unreleased] +* [CONFIGURATION] Apply general `attribute_limits` to the tracer and logger + providers when their model-specific `limits` are not set. Provider `limits` + continue to take precedence. + [#4467](https://github.com/open-telemetry/opentelemetry-cpp/issues/4467) + * [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/configuration/sdk_builder.h b/sdk/include/opentelemetry/sdk/configuration/sdk_builder.h index 637756bb3..588b5f00a 100644 --- a/sdk/include/opentelemetry/sdk/configuration/sdk_builder.h +++ b/sdk/include/opentelemetry/sdk/configuration/sdk_builder.h @@ -7,6 +7,7 @@ #include #include "opentelemetry/sdk/configuration/always_off_sampler_configuration.h" +#include "opentelemetry/sdk/configuration/attribute_limits_configuration.h" #include "opentelemetry/sdk/configuration/base2_exponential_bucket_histogram_aggregation_configuration.h" #include "opentelemetry/sdk/configuration/batch_log_record_processor_configuration.h" #include "opentelemetry/sdk/configuration/batch_span_processor_configuration.h" @@ -163,6 +164,11 @@ class SdkBuilder const std::unique_ptr &model, const opentelemetry::sdk::resource::Resource &resource) const; + std::unique_ptr CreateTracerProvider( + const std::unique_ptr &model, + const opentelemetry::sdk::resource::Resource &resource, + const AttributeLimitsConfiguration *attribute_limits) const; + std::unique_ptr CreateTextMapPropagator( const std::string &name) const; @@ -288,6 +294,11 @@ class SdkBuilder const std::unique_ptr &model, const opentelemetry::sdk::resource::Resource &resource) const; + std::unique_ptr CreateLoggerProvider( + const std::unique_ptr &model, + const opentelemetry::sdk::resource::Resource &resource, + const AttributeLimitsConfiguration *attribute_limits) const; + std::unique_ptr CreateContainerResourceDetector( const opentelemetry::sdk::configuration::ContainerResourceDetectorConfiguration *model) const; diff --git a/sdk/src/configuration/sdk_builder.cc b/sdk/src/configuration/sdk_builder.cc index 27aad69cb..187020421 100644 --- a/sdk/src/configuration/sdk_builder.cc +++ b/sdk/src/configuration/sdk_builder.cc @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -24,6 +25,7 @@ #include "opentelemetry/sdk/configuration/always_off_sampler_configuration.h" #include "opentelemetry/sdk/configuration/always_on_sampler_builder.h" #include "opentelemetry/sdk/configuration/always_on_sampler_configuration.h" +#include "opentelemetry/sdk/configuration/attribute_limits_configuration.h" #include "opentelemetry/sdk/configuration/attribute_value_configuration.h" #include "opentelemetry/sdk/configuration/attribute_value_configuration_visitor.h" #include "opentelemetry/sdk/configuration/attributes_configuration.h" @@ -254,6 +256,43 @@ static opentelemetry::sdk::metrics::CardinalityLimits ToCardinalityLimits( return limits; } +static std::uint32_t ToUint32Limit(std::size_t value) +{ + constexpr auto kMax = (std::numeric_limits::max)(); + if (value > kMax) + { + return kMax; + } + return static_cast(value); +} + +/// Apply general attribute_limits when model-specific provider limits are not +/// configured. Model-specific limits take precedence; see +/// https://opentelemetry.io/docs/specs/otel/common/#attribute-limits +static void ApplyGeneralAttributeLimits( + opentelemetry::sdk::trace::SpanLimits &span_limits, + const opentelemetry::sdk::configuration::AttributeLimitsConfiguration *attribute_limits) +{ + if (attribute_limits == nullptr) + { + return; + } + span_limits.attribute_value_length_limit = attribute_limits->attribute_value_length_limit; + span_limits.attribute_count_limit = ToUint32Limit(attribute_limits->attribute_count_limit); +} + +static void ApplyGeneralAttributeLimits( + opentelemetry::sdk::logs::LogRecordLimits &log_record_limits, + const opentelemetry::sdk::configuration::AttributeLimitsConfiguration *attribute_limits) +{ + if (attribute_limits == nullptr) + { + return; + } + log_record_limits.attribute_value_length_limit = attribute_limits->attribute_value_length_limit; + log_record_limits.attribute_count_limit = attribute_limits->attribute_count_limit; +} + class ResourceAttributeValueSetter : public opentelemetry::sdk::configuration::AttributeValueConfigurationVisitor { @@ -1422,6 +1461,14 @@ SdkBuilder::CreateTracerConfigurator( std::unique_ptr SdkBuilder::CreateTracerProvider( const std::unique_ptr &model, const opentelemetry::sdk::resource::Resource &resource) const +{ + return CreateTracerProvider(model, resource, nullptr); +} + +std::unique_ptr SdkBuilder::CreateTracerProvider( + const std::unique_ptr &model, + const opentelemetry::sdk::resource::Resource &resource, + const AttributeLimitsConfiguration *attribute_limits) const { std::unique_ptr sdk; @@ -1458,6 +1505,10 @@ std::unique_ptr SdkBuilder::CreateTra span_limits.event_attribute_count_limit = model->limits->event_attribute_count_limit; span_limits.link_attribute_count_limit = model->limits->link_attribute_count_limit; } + else + { + ApplyGeneralAttributeLimits(span_limits, attribute_limits); + } if (model->tracer_configurator) { @@ -2348,6 +2399,14 @@ SdkBuilder::CreateLoggerConfigurator( std::unique_ptr SdkBuilder::CreateLoggerProvider( const std::unique_ptr &model, const opentelemetry::sdk::resource::Resource &resource) const +{ + return CreateLoggerProvider(model, resource, nullptr); +} + +std::unique_ptr SdkBuilder::CreateLoggerProvider( + const std::unique_ptr &model, + const opentelemetry::sdk::resource::Resource &resource, + const AttributeLimitsConfiguration *attribute_limits) const { std::unique_ptr sdk; @@ -2364,6 +2423,10 @@ std::unique_ptr SdkBuilder::CreateLogg log_record_limits.attribute_value_length_limit = model->limits->attribute_value_length_limit; log_record_limits.attribute_count_limit = model->limits->attribute_count_limit; } + else + { + ApplyGeneralAttributeLimits(log_record_limits, attribute_limits); + } std::unique_ptr> @@ -2634,16 +2697,10 @@ std::unique_ptr SdkBuilder::CreateConfiguredSdk( { SetResource(sdk->resource, model->resource); - if (model->attribute_limits) - { - // FIXME-SDK: https://github.com/open-telemetry/opentelemetry-cpp/issues/3303 - // FIXME-SDK: Implement attribute limits - OTEL_INTERNAL_LOG_WARN("attribute_limits not supported, ignoring"); - } - if (model->tracer_provider) { - sdk->tracer_provider = CreateTracerProvider(model->tracer_provider, sdk->resource); + sdk->tracer_provider = CreateTracerProvider(model->tracer_provider, sdk->resource, + model->attribute_limits.get()); } if (model->propagator) @@ -2658,7 +2715,8 @@ std::unique_ptr SdkBuilder::CreateConfiguredSdk( if (model->logger_provider) { - sdk->logger_provider = CreateLoggerProvider(model->logger_provider, sdk->resource); + sdk->logger_provider = CreateLoggerProvider(model->logger_provider, sdk->resource, + model->attribute_limits.get()); } } diff --git a/sdk/test/configuration/programmatic_configuration_test.cc b/sdk/test/configuration/programmatic_configuration_test.cc index b57b9fd05..cc5a1cd80 100644 --- a/sdk/test/configuration/programmatic_configuration_test.cc +++ b/sdk/test/configuration/programmatic_configuration_test.cc @@ -42,6 +42,7 @@ #include "opentelemetry/sdk/configuration/aggregation_configuration.h" #include "opentelemetry/sdk/configuration/always_off_sampler_configuration.h" +#include "opentelemetry/sdk/configuration/attribute_limits_configuration.h" #include "opentelemetry/sdk/configuration/base2_exponential_bucket_histogram_aggregation_configuration.h" #include "opentelemetry/sdk/configuration/batch_log_record_processor_builder.h" #include "opentelemetry/sdk/configuration/batch_log_record_processor_configuration.h" @@ -82,6 +83,7 @@ #include "opentelemetry/sdk/configuration/simple_log_record_processor_configuration.h" #include "opentelemetry/sdk/configuration/simple_span_processor_configuration.h" #include "opentelemetry/sdk/configuration/span_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/span_limits_configuration.h" #include "opentelemetry/sdk/configuration/span_processor_configuration.h" #include "opentelemetry/sdk/configuration/tracer_config_configuration.h" #include "opentelemetry/sdk/configuration/tracer_configurator_configuration.h" @@ -98,6 +100,7 @@ #include "opentelemetry/sdk/metrics/meter_provider.h" #include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/trace/span_data.h" +#include "opentelemetry/sdk/trace/span_limits.h" #include "opentelemetry/sdk/trace/tracer_provider.h" #include "config_test_common.h" @@ -333,6 +336,124 @@ TEST_F(ProgrammaticConfigTest, LoggerProviderWithLogRecordLimits) } } +TEST_F(ProgrammaticConfigTest, AttributeLimitsApplyToLoggerProvider) +{ + auto attribute_limits = std::make_unique(); + attribute_limits->attribute_count_limit = 2; + attribute_limits->attribute_value_length_limit = 5; + + auto model = std::make_unique(); + model->attribute_limits = std::move(attribute_limits); + model->logger_provider = MakeLoggerProviderConfig(); + + CreateAndInstallSdk(model); + ASSERT_NE(sdk_->logger_provider, nullptr); + + auto logger = logs::Provider::GetLoggerProvider()->GetLogger("test"); + logger->EmitLogRecord( + logs::Severity::kInfo, nostd::string_view("test-message"), + common::MakeAttributes({{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}})); + + ASSERT_TRUE(sdk_->logger_provider->ForceFlush(std::chrono::milliseconds(kProcessTimeout))); + ASSERT_TRUE(sdk_->logger_provider->Shutdown(std::chrono::milliseconds(kProcessTimeout))); + + EXPECT_EQ(log_buffer_->size(), 1); + auto *record = log_buffer_->front().get(); + const auto &attributes = record->GetAttributes(); + EXPECT_EQ(attributes.size(), 2); + for (const auto &attr : attributes) + { + EXPECT_EQ(nostd::get(attr.second).size(), 5); + } +} + +TEST_F(ProgrammaticConfigTest, LoggerProviderLimitsOverrideAttributeLimits) +{ + auto attribute_limits = std::make_unique(); + attribute_limits->attribute_count_limit = 1; + attribute_limits->attribute_value_length_limit = 3; + + config_sdk::LogRecordLimitsConfiguration limits; + limits.attribute_count_limit = 2; + limits.attribute_value_length_limit = 5; + + auto logger_provider_config = MakeLoggerProviderConfig(); + logger_provider_config->limits = + std::make_unique(limits); + + auto model = std::make_unique(); + model->attribute_limits = std::move(attribute_limits); + model->logger_provider = std::move(logger_provider_config); + + CreateAndInstallSdk(model); + ASSERT_NE(sdk_->logger_provider, nullptr); + + auto logger = logs::Provider::GetLoggerProvider()->GetLogger("test"); + logger->EmitLogRecord( + logs::Severity::kInfo, nostd::string_view("test-message"), + common::MakeAttributes({{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}})); + + ASSERT_TRUE(sdk_->logger_provider->ForceFlush(std::chrono::milliseconds(kProcessTimeout))); + ASSERT_TRUE(sdk_->logger_provider->Shutdown(std::chrono::milliseconds(kProcessTimeout))); + + EXPECT_EQ(log_buffer_->size(), 1); + auto *record = log_buffer_->front().get(); + const auto &attributes = record->GetAttributes(); + EXPECT_EQ(attributes.size(), limits.attribute_count_limit); + for (const auto &attr : attributes) + { + EXPECT_EQ(nostd::get(attr.second).size(), limits.attribute_value_length_limit); + } +} + +TEST_F(ProgrammaticConfigTest, AttributeLimitsApplyToTracerProvider) +{ + auto attribute_limits = std::make_unique(); + attribute_limits->attribute_count_limit = 7; + attribute_limits->attribute_value_length_limit = 9; + + auto model = std::make_unique(); + model->attribute_limits = std::move(attribute_limits); + model->tracer_provider = MakeTracerProviderConfig(); + + CreateAndInstallSdk(model); + ASSERT_NE(sdk_->tracer_provider, nullptr); + + const auto limits = sdk_->tracer_provider->GetSpanLimits(); + const auto default_limits = opentelemetry::sdk::trace::SpanLimits{}; + EXPECT_EQ(limits.attribute_count_limit, 7); + EXPECT_EQ(limits.attribute_value_length_limit, 9); + EXPECT_EQ(limits.event_count_limit, default_limits.event_count_limit); + EXPECT_EQ(limits.link_count_limit, default_limits.link_count_limit); +} + +TEST_F(ProgrammaticConfigTest, TracerProviderLimitsOverrideAttributeLimits) +{ + auto attribute_limits = std::make_unique(); + attribute_limits->attribute_count_limit = 7; + attribute_limits->attribute_value_length_limit = 9; + + auto span_limits = std::make_unique(); + span_limits->attribute_count_limit = 22; + span_limits->attribute_value_length_limit = 11; + span_limits->event_count_limit = 33; + + auto tracer_provider_config = MakeTracerProviderConfig(); + tracer_provider_config->limits = std::move(span_limits); + + auto model = std::make_unique(); + model->attribute_limits = std::move(attribute_limits); + model->tracer_provider = std::move(tracer_provider_config); + + CreateAndInstallSdk(model); + ASSERT_NE(sdk_->tracer_provider, nullptr); + + const auto limits = sdk_->tracer_provider->GetSpanLimits(); + EXPECT_EQ(limits.attribute_count_limit, 22); + EXPECT_EQ(limits.attribute_value_length_limit, 11); + EXPECT_EQ(limits.event_count_limit, 33); +} + TEST_F(ProgrammaticConfigTest, LoggerProviderWithLoggerConfigurator) { auto error_logger_matcher = config_sdk::LoggerMatcherAndConfigConfiguration(); diff --git a/sdk/test/configuration/sdk_builder_test.cc b/sdk/test/configuration/sdk_builder_test.cc index 7550c44fd..d4b285dc8 100644 --- a/sdk/test/configuration/sdk_builder_test.cc +++ b/sdk/test/configuration/sdk_builder_test.cc @@ -28,6 +28,7 @@ #include "opentelemetry/sdk/configuration/aggregation_configuration.h" #include "opentelemetry/sdk/configuration/always_off_sampler_configuration.h" #include "opentelemetry/sdk/configuration/always_on_sampler_configuration.h" +#include "opentelemetry/sdk/configuration/attribute_limits_configuration.h" #include "opentelemetry/sdk/configuration/attribute_value_configuration.h" #include "opentelemetry/sdk/configuration/attributes_configuration.h" #include "opentelemetry/sdk/configuration/cardinality_limits_configuration.h" @@ -120,6 +121,7 @@ using opentelemetry::sdk::common::unsetenv; # endif #endif +using opentelemetry::sdk::configuration::AttributeLimitsConfiguration; using opentelemetry::sdk::configuration::Registry; using opentelemetry::sdk::configuration::RegistryFactory; using opentelemetry::sdk::configuration::SdkBuilder; @@ -261,6 +263,54 @@ TEST(SdkBuilder, SpanLimitsConfiguration) EXPECT_EQ(limits.link_attribute_count_limit, model->limits->link_attribute_count_limit); } +TEST(SdkBuilder, SpanLimitsFromAttributeLimits) +{ + auto model = std::make_unique(); + model->limits = nullptr; + + AttributeLimitsConfiguration attribute_limits; + attribute_limits.attribute_count_limit = 7; + attribute_limits.attribute_value_length_limit = 9; + + SdkBuilder builder(RegistryFactory::Create()); + auto resource = opentelemetry::sdk::resource::Resource::Create({}); + auto provider = builder.CreateTracerProvider(model, resource, &attribute_limits); + ASSERT_NE(provider, nullptr); + + const auto limits = provider->GetSpanLimits(); + const auto default_limits = opentelemetry::sdk::trace::SpanLimits{}; + + EXPECT_EQ(limits.attribute_count_limit, attribute_limits.attribute_count_limit); + EXPECT_EQ(limits.attribute_value_length_limit, attribute_limits.attribute_value_length_limit); + EXPECT_EQ(limits.event_count_limit, default_limits.event_count_limit); + EXPECT_EQ(limits.link_count_limit, default_limits.link_count_limit); + EXPECT_EQ(limits.event_attribute_count_limit, default_limits.event_attribute_count_limit); + EXPECT_EQ(limits.link_attribute_count_limit, default_limits.link_attribute_count_limit); +} + +TEST(SdkBuilder, SpanLimitsOverrideAttributeLimits) +{ + auto model = std::make_unique(); + model->limits = std::make_unique(); + model->limits->attribute_value_length_limit = 1111; + model->limits->attribute_count_limit = 2222; + model->limits->event_count_limit = 3333; + + AttributeLimitsConfiguration attribute_limits; + attribute_limits.attribute_count_limit = 7; + attribute_limits.attribute_value_length_limit = 9; + + SdkBuilder builder(RegistryFactory::Create()); + auto resource = opentelemetry::sdk::resource::Resource::Create({}); + auto provider = builder.CreateTracerProvider(model, resource, &attribute_limits); + ASSERT_NE(provider, nullptr); + + const auto limits = provider->GetSpanLimits(); + EXPECT_EQ(limits.attribute_value_length_limit, model->limits->attribute_value_length_limit); + EXPECT_EQ(limits.attribute_count_limit, model->limits->attribute_count_limit); + EXPECT_EQ(limits.event_count_limit, model->limits->event_count_limit); +} + #if defined(ENABLE_METRICS_EXEMPLAR_PREVIEW) && !defined(NO_GETENV) TEST_F(SdkBuilderExemplarFilterEnvironmentTest, DeclarativeExemplarFilterDoesNotReadEnvironment) { From 65d8341742bb49b05efec856f507e6d599e54712 Mon Sep 17 00:00:00 2001 From: ayush-singh-0601 Date: Sat, 22 Aug 2026 18:25:39 +0530 Subject: [PATCH 2/6] [CONFIGURATION] Fix clang-format alignment in attribute_limits tests --- sdk/test/configuration/programmatic_configuration_test.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/test/configuration/programmatic_configuration_test.cc b/sdk/test/configuration/programmatic_configuration_test.cc index cc5a1cd80..377ec37d2 100644 --- a/sdk/test/configuration/programmatic_configuration_test.cc +++ b/sdk/test/configuration/programmatic_configuration_test.cc @@ -358,8 +358,8 @@ TEST_F(ProgrammaticConfigTest, AttributeLimitsApplyToLoggerProvider) ASSERT_TRUE(sdk_->logger_provider->Shutdown(std::chrono::milliseconds(kProcessTimeout))); EXPECT_EQ(log_buffer_->size(), 1); - auto *record = log_buffer_->front().get(); - const auto &attributes = record->GetAttributes(); + auto *record = log_buffer_->front().get(); + const auto &attributes = record->GetAttributes(); EXPECT_EQ(attributes.size(), 2); for (const auto &attr : attributes) { @@ -433,8 +433,8 @@ TEST_F(ProgrammaticConfigTest, TracerProviderLimitsOverrideAttributeLimits) attribute_limits->attribute_count_limit = 7; attribute_limits->attribute_value_length_limit = 9; - auto span_limits = std::make_unique(); - span_limits->attribute_count_limit = 22; + auto span_limits = std::make_unique(); + span_limits->attribute_count_limit = 22; span_limits->attribute_value_length_limit = 11; span_limits->event_count_limit = 33; From 66cf2361d163d369557f1411bf77b6edac131324 Mon Sep 17 00:00:00 2001 From: ayush-singh-0601 Date: Sun, 23 Aug 2026 22:26:36 +0530 Subject: [PATCH 3/6] [CONFIGURATION] Add defaulted attribute_limits arg to Create*Provider --- .../opentelemetry/sdk/configuration/sdk_builder.h | 12 ++---------- sdk/src/configuration/sdk_builder.cc | 14 -------------- 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/sdk/include/opentelemetry/sdk/configuration/sdk_builder.h b/sdk/include/opentelemetry/sdk/configuration/sdk_builder.h index 588b5f00a..69d96f673 100644 --- a/sdk/include/opentelemetry/sdk/configuration/sdk_builder.h +++ b/sdk/include/opentelemetry/sdk/configuration/sdk_builder.h @@ -160,14 +160,10 @@ class SdkBuilder opentelemetry::sdk::trace::TracerConfig>> CreateTracerConfigurator(const std::unique_ptr &model) const; - std::unique_ptr CreateTracerProvider( - const std::unique_ptr &model, - const opentelemetry::sdk::resource::Resource &resource) const; - std::unique_ptr CreateTracerProvider( const std::unique_ptr &model, const opentelemetry::sdk::resource::Resource &resource, - const AttributeLimitsConfiguration *attribute_limits) const; + const AttributeLimitsConfiguration *attribute_limits = nullptr) const; std::unique_ptr CreateTextMapPropagator( const std::string &name) const; @@ -290,14 +286,10 @@ class SdkBuilder opentelemetry::sdk::logs::LoggerConfig>> CreateLoggerConfigurator(const std::unique_ptr &model) const; - std::unique_ptr CreateLoggerProvider( - const std::unique_ptr &model, - const opentelemetry::sdk::resource::Resource &resource) const; - std::unique_ptr CreateLoggerProvider( const std::unique_ptr &model, const opentelemetry::sdk::resource::Resource &resource, - const AttributeLimitsConfiguration *attribute_limits) const; + const AttributeLimitsConfiguration *attribute_limits = nullptr) const; std::unique_ptr CreateContainerResourceDetector( const opentelemetry::sdk::configuration::ContainerResourceDetectorConfiguration *model) const; diff --git a/sdk/src/configuration/sdk_builder.cc b/sdk/src/configuration/sdk_builder.cc index 187020421..7b4938ca5 100644 --- a/sdk/src/configuration/sdk_builder.cc +++ b/sdk/src/configuration/sdk_builder.cc @@ -1458,13 +1458,6 @@ SdkBuilder::CreateTracerConfigurator( throw UnsupportedException(die); } -std::unique_ptr SdkBuilder::CreateTracerProvider( - const std::unique_ptr &model, - const opentelemetry::sdk::resource::Resource &resource) const -{ - return CreateTracerProvider(model, resource, nullptr); -} - std::unique_ptr SdkBuilder::CreateTracerProvider( const std::unique_ptr &model, const opentelemetry::sdk::resource::Resource &resource, @@ -2396,13 +2389,6 @@ SdkBuilder::CreateLoggerConfigurator( throw UnsupportedException(die); } -std::unique_ptr SdkBuilder::CreateLoggerProvider( - const std::unique_ptr &model, - const opentelemetry::sdk::resource::Resource &resource) const -{ - return CreateLoggerProvider(model, resource, nullptr); -} - std::unique_ptr SdkBuilder::CreateLoggerProvider( const std::unique_ptr &model, const opentelemetry::sdk::resource::Resource &resource, From a336cf9ae1af389f7e5fcc50de68ff9e8f0abf50 Mon Sep 17 00:00:00 2001 From: ayush-singh-0601 Date: Mon, 24 Aug 2026 20:42:15 +0530 Subject: [PATCH 4/6] [CONFIGURATION] Resolve attribute limits per field Make each limit on AttributeLimits, SpanLimits, and LogRecordLimits optional so omitted keys and YAML null are unset. Merge uses the model-specific value if set, else the general attribute_limits value, else the model-specific default. --- CHANGELOG.md | 10 +- install/test/src/test_sdk.cc | 1 + .../attribute_limits_configuration.h | 5 +- .../sdk/configuration/document_node.h | 2 + .../log_record_limits_configuration.h | 5 +- .../sdk/configuration/optional_value.h | 46 ++++++++ .../sdk/configuration/ryml_document_node.h | 2 + .../configuration/span_limits_configuration.h | 14 ++- sdk/src/configuration/configuration_parser.cc | 52 ++++----- sdk/src/configuration/ryml_document_node.cc | 25 ++++ sdk/src/configuration/sdk_builder.cc | 108 +++++++++++++----- .../programmatic_configuration_test.cc | 48 +++++++- sdk/test/configuration/sdk_builder_test.cc | 72 ++++++++++-- sdk/test/configuration/yaml_logs_test.cc | 35 +++++- sdk/test/configuration/yaml_test.cc | 38 ++++-- sdk/test/configuration/yaml_trace_test.cc | 57 ++++++--- 16 files changed, 402 insertions(+), 118 deletions(-) create mode 100644 sdk/include/opentelemetry/sdk/configuration/optional_value.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ea5ec367..d72d16829 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,9 +15,13 @@ Increment the: ## [Unreleased] -* [CONFIGURATION] Apply general `attribute_limits` to the tracer and logger - providers when their model-specific `limits` are not set. Provider `limits` - continue to take precedence. +* [CONFIGURATION] Apply general `attribute_limits` per individual limit field. + If a model-specific limit is set it is used, otherwise the matching general + limit, otherwise the model-specific default. Limit fields on + `AttributeLimitsConfiguration`, `SpanLimitsConfiguration`, and + `LogRecordLimitsConfiguration` are now optional so omitted keys and YAML + `null` are distinct from explicit values. This is a breaking change to the + experimental configuration model. [#4467](https://github.com/open-telemetry/opentelemetry-cpp/issues/4467) * [CONFIGURATION] Add a configuration builder for the host resource detector diff --git a/install/test/src/test_sdk.cc b/install/test/src/test_sdk.cc index 128c8385b..bb5fb4080 100644 --- a/install/test/src/test_sdk.cc +++ b/install/test/src/test_sdk.cc @@ -189,6 +189,7 @@ #include #include #include +#include #include #include #include diff --git a/sdk/include/opentelemetry/sdk/configuration/attribute_limits_configuration.h b/sdk/include/opentelemetry/sdk/configuration/attribute_limits_configuration.h index 755069ea0..98a0042de 100644 --- a/sdk/include/opentelemetry/sdk/configuration/attribute_limits_configuration.h +++ b/sdk/include/opentelemetry/sdk/configuration/attribute_limits_configuration.h @@ -6,6 +6,7 @@ #include #include +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -23,8 +24,8 @@ class AttributeLimitsConfiguration (std::numeric_limits::max)(); static constexpr std::size_t kDefaultAttributeCountLimit = 128; - std::size_t attribute_value_length_limit{kDefaultAttributeValueLengthLimit}; - std::size_t attribute_count_limit{kDefaultAttributeCountLimit}; + OptionalValue attribute_value_length_limit; + OptionalValue attribute_count_limit; }; } // namespace configuration diff --git a/sdk/include/opentelemetry/sdk/configuration/document_node.h b/sdk/include/opentelemetry/sdk/configuration/document_node.h index 2dc715eec..607ad6c44 100644 --- a/sdk/include/opentelemetry/sdk/configuration/document_node.h +++ b/sdk/include/opentelemetry/sdk/configuration/document_node.h @@ -7,6 +7,7 @@ #include #include +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -49,6 +50,7 @@ class DocumentNode virtual std::size_t GetRequiredInteger(const std::string &name) const = 0; virtual std::size_t GetInteger(const std::string &name, std::size_t default_value) const = 0; + virtual OptionalValue GetOptionalInteger(const std::string &name) const = 0; virtual std::int64_t GetSignedInteger(const std::string &name, std::int64_t default_value) const = 0; diff --git a/sdk/include/opentelemetry/sdk/configuration/log_record_limits_configuration.h b/sdk/include/opentelemetry/sdk/configuration/log_record_limits_configuration.h index 64bf93242..d7c427ae9 100644 --- a/sdk/include/opentelemetry/sdk/configuration/log_record_limits_configuration.h +++ b/sdk/include/opentelemetry/sdk/configuration/log_record_limits_configuration.h @@ -6,6 +6,7 @@ #include #include +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -23,8 +24,8 @@ class LogRecordLimitsConfiguration (std::numeric_limits::max)(); static constexpr std::size_t kDefaultAttributeCountLimit = 128; - std::size_t attribute_value_length_limit{kDefaultAttributeValueLengthLimit}; - std::size_t attribute_count_limit{kDefaultAttributeCountLimit}; + OptionalValue attribute_value_length_limit; + OptionalValue attribute_count_limit; }; } // namespace configuration diff --git a/sdk/include/opentelemetry/sdk/configuration/optional_value.h b/sdk/include/opentelemetry/sdk/configuration/optional_value.h new file mode 100644 index 000000000..c9cf73d9f --- /dev/null +++ b/sdk/include/opentelemetry/sdk/configuration/optional_value.h @@ -0,0 +1,46 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace configuration +{ + +/** + * C++14-friendly optional for configuration fields that may be set, omitted, or + * explicitly null in YAML. + */ +template +class OptionalValue +{ +public: + OptionalValue() = default; + + explicit OptionalValue(T value) : has_value_(true), value_(value) {} + + bool HasValue() const { return has_value_; } + + const T &Value() const { return value_; } + + T ValueOr(T fallback) const { return has_value_ ? value_ : fallback; } + + OptionalValue &operator=(T value) + { + has_value_ = true; + value_ = value; + return *this; + } + +private: + bool has_value_{false}; + T value_{}; +}; + +} // namespace configuration +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/configuration/ryml_document_node.h b/sdk/include/opentelemetry/sdk/configuration/ryml_document_node.h index f22c75f79..831ce98a7 100644 --- a/sdk/include/opentelemetry/sdk/configuration/ryml_document_node.h +++ b/sdk/include/opentelemetry/sdk/configuration/ryml_document_node.h @@ -10,6 +10,7 @@ #include #include "opentelemetry/sdk/configuration/document_node.h" +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -49,6 +50,7 @@ class RymlDocumentNode : public DocumentNode std::size_t GetRequiredInteger(const std::string &name) const override; std::size_t GetInteger(const std::string &name, std::size_t default_value) const override; + OptionalValue GetOptionalInteger(const std::string &name) const override; std::int64_t GetSignedInteger(const std::string &name, std::int64_t default_value) const override; diff --git a/sdk/include/opentelemetry/sdk/configuration/span_limits_configuration.h b/sdk/include/opentelemetry/sdk/configuration/span_limits_configuration.h index db0e4ca72..f6ad99290 100644 --- a/sdk/include/opentelemetry/sdk/configuration/span_limits_configuration.h +++ b/sdk/include/opentelemetry/sdk/configuration/span_limits_configuration.h @@ -4,8 +4,10 @@ #pragma once #include +#include #include +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -27,12 +29,12 @@ class SpanLimitsConfiguration static constexpr std::uint32_t kDefaultEventAttributeCountLimit = 128; static constexpr std::uint32_t kDefaultLinkAttributeCountLimit = 128; - std::size_t attribute_value_length_limit{kDefaultAttributeValueLengthLimit}; - std::uint32_t attribute_count_limit{kDefaultAttributeCountLimit}; - std::uint32_t event_count_limit{kDefaultEventCountLimit}; - std::uint32_t link_count_limit{kDefaultLinkCountLimit}; - std::uint32_t event_attribute_count_limit{kDefaultEventAttributeCountLimit}; - std::uint32_t link_attribute_count_limit{kDefaultLinkAttributeCountLimit}; + OptionalValue attribute_value_length_limit; + OptionalValue attribute_count_limit; + OptionalValue event_count_limit; + OptionalValue link_count_limit; + OptionalValue event_attribute_count_limit; + OptionalValue link_attribute_count_limit; }; } // namespace configuration diff --git a/sdk/src/configuration/configuration_parser.cc b/sdk/src/configuration/configuration_parser.cc index 58f7fed86..1923f36c0 100644 --- a/sdk/src/configuration/configuration_parser.cc +++ b/sdk/src/configuration/configuration_parser.cc @@ -17,6 +17,7 @@ #include "opentelemetry/sdk/configuration/always_off_sampler_configuration.h" #include "opentelemetry/sdk/configuration/always_on_sampler_configuration.h" #include "opentelemetry/sdk/configuration/attribute_limits_configuration.h" +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/sdk/configuration/attribute_value_configuration.h" #include "opentelemetry/sdk/configuration/attributes_configuration.h" #include "opentelemetry/sdk/configuration/base2_exponential_bucket_histogram_aggregation_configuration.h" @@ -360,13 +361,10 @@ std::unique_ptr ConfigurationParser::ParseAttributeLimitsConfiguration( const std::unique_ptr &node) const { - using Config = AttributeLimitsConfiguration; - auto model = std::make_unique(); + auto model = std::make_unique(); - model->attribute_value_length_limit = - node->GetInteger("attribute_value_length_limit", Config::kDefaultAttributeValueLengthLimit); - model->attribute_count_limit = - node->GetInteger("attribute_count_limit", Config::kDefaultAttributeCountLimit); + model->attribute_value_length_limit = node->GetOptionalInteger("attribute_value_length_limit"); + model->attribute_count_limit = node->GetOptionalInteger("attribute_count_limit"); return model; } @@ -640,13 +638,10 @@ std::unique_ptr ConfigurationParser::ParseLogRecordLimitsConfiguration( const std::unique_ptr &node) const { - using Config = LogRecordLimitsConfiguration; - auto model = std::make_unique(); + auto model = std::make_unique(); - model->attribute_value_length_limit = - node->GetInteger("attribute_value_length_limit", Config::kDefaultAttributeValueLengthLimit); - model->attribute_count_limit = - node->GetInteger("attribute_count_limit", Config::kDefaultAttributeCountLimit); + model->attribute_value_length_limit = node->GetOptionalInteger("attribute_value_length_limit"); + model->attribute_count_limit = node->GetOptionalInteger("attribute_count_limit"); return model; } @@ -1673,29 +1668,28 @@ std::unique_ptr ConfigurationParser::ParsePropagatorCon std::unique_ptr ConfigurationParser::ParseSpanLimitsConfiguration( const std::unique_ptr &node) const { - using Config = SpanLimitsConfiguration; - auto model = std::make_unique(); + auto model = std::make_unique(); - const auto get_valid_uint32 = [&node](const std::string &name, std::size_t default_value) { - std::size_t value = node->GetInteger(name, default_value); - if (value > std::numeric_limits::max()) + const auto get_optional_uint32 = [&node](const std::string &name) { + OptionalValue value = node->GetOptionalInteger(name); + if (!value.HasValue()) { - std::string message = "Invalid value for " + name + ": " + std::to_string(value); + return OptionalValue{}; + } + if (value.Value() > std::numeric_limits::max()) + { + std::string message = "Invalid value for " + name + ": " + std::to_string(value.Value()); throw InvalidSchemaException(node->Location(), message); } - return static_cast(value); + return OptionalValue{static_cast(value.Value())}; }; - model->attribute_value_length_limit = - node->GetInteger("attribute_value_length_limit", Config::kDefaultAttributeValueLengthLimit); - model->attribute_count_limit = - get_valid_uint32("attribute_count_limit", Config::kDefaultAttributeCountLimit); - model->event_count_limit = get_valid_uint32("event_count_limit", Config::kDefaultEventCountLimit); - model->link_count_limit = get_valid_uint32("link_count_limit", Config::kDefaultLinkCountLimit); - model->event_attribute_count_limit = - get_valid_uint32("event_attribute_count_limit", Config::kDefaultEventAttributeCountLimit); - model->link_attribute_count_limit = - get_valid_uint32("link_attribute_count_limit", Config::kDefaultLinkAttributeCountLimit); + model->attribute_value_length_limit = node->GetOptionalInteger("attribute_value_length_limit"); + model->attribute_count_limit = get_optional_uint32("attribute_count_limit"); + model->event_count_limit = get_optional_uint32("event_count_limit"); + model->link_count_limit = get_optional_uint32("link_count_limit"); + model->event_attribute_count_limit = get_optional_uint32("event_attribute_count_limit"); + model->link_attribute_count_limit = get_optional_uint32("link_attribute_count_limit"); return model; } diff --git a/sdk/src/configuration/ryml_document_node.cc b/sdk/src/configuration/ryml_document_node.cc index b24a312d8..c7744f924 100644 --- a/sdk/src/configuration/ryml_document_node.cc +++ b/sdk/src/configuration/ryml_document_node.cc @@ -13,6 +13,7 @@ #include "opentelemetry/sdk/common/global_log_handler.h" #include "opentelemetry/sdk/configuration/document_node.h" #include "opentelemetry/sdk/configuration/invalid_schema_exception.h" +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/sdk/configuration/ryml_document.h" #include "opentelemetry/sdk/configuration/ryml_document_node.h" #include "opentelemetry/version.h" @@ -282,6 +283,30 @@ size_t RymlDocumentNode::GetInteger(const std::string &name, size_t default_valu return IntegerFromString(value); } +OptionalValue RymlDocumentNode::GetOptionalInteger(const std::string &name) const +{ + OTEL_INTERNAL_LOG_DEBUG("RymlDocumentNode::GetOptionalInteger(" << name << ")"); + + auto ryml_child = GetRymlChildNode(name); + + if (ryml_child.invalid() || !ryml_child.has_val()) + { + return OptionalValue{}; + } + + ryml::csubstr view = ryml_child.val(); + std::string value(view.str, view.len); + + value = DoSubstitution(value); + + if (value.empty() || value == "~" || value == "null" || value == "Null" || value == "NULL") + { + return OptionalValue{}; + } + + return OptionalValue{IntegerFromString(value)}; +} + std::int64_t RymlDocumentNode::GetSignedInteger(const std::string &name, std::int64_t default_value) const { diff --git a/sdk/src/configuration/sdk_builder.cc b/sdk/src/configuration/sdk_builder.cc index 9319e7393..492f84323 100644 --- a/sdk/src/configuration/sdk_builder.cc +++ b/sdk/src/configuration/sdk_builder.cc @@ -26,6 +26,7 @@ #include "opentelemetry/sdk/configuration/always_on_sampler_builder.h" #include "opentelemetry/sdk/configuration/always_on_sampler_configuration.h" #include "opentelemetry/sdk/configuration/attribute_limits_configuration.h" +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/sdk/configuration/attribute_value_configuration.h" #include "opentelemetry/sdk/configuration/attribute_value_configuration_visitor.h" #include "opentelemetry/sdk/configuration/attributes_configuration.h" @@ -268,31 +269,32 @@ static std::uint32_t ToUint32Limit(std::size_t value) return static_cast(value); } -/// Apply general attribute_limits when model-specific provider limits are not -/// configured. Model-specific limits take precedence; see +/// Resolve one limit per /// https://opentelemetry.io/docs/specs/otel/common/#attribute-limits -static void ApplyGeneralAttributeLimits( - opentelemetry::sdk::trace::SpanLimits &span_limits, - const opentelemetry::sdk::configuration::AttributeLimitsConfiguration *attribute_limits) +/// model-specific if set, else general if set, else the model-specific default. +template +static T ResolveLimit(const OptionalValue &model_specific, + const OptionalValue &general, + T model_default) { - if (attribute_limits == nullptr) + if (model_specific.HasValue()) { - return; + return model_specific.Value(); } - span_limits.attribute_value_length_limit = attribute_limits->attribute_value_length_limit; - span_limits.attribute_count_limit = ToUint32Limit(attribute_limits->attribute_count_limit); + if (general.HasValue()) + { + return general.Value(); + } + return model_default; } -static void ApplyGeneralAttributeLimits( - opentelemetry::sdk::logs::LogRecordLimits &log_record_limits, - const opentelemetry::sdk::configuration::AttributeLimitsConfiguration *attribute_limits) +static OptionalValue ToOptionalUint32(const OptionalValue &value) { - if (attribute_limits == nullptr) + if (!value.HasValue()) { - return; + return OptionalValue{}; } - log_record_limits.attribute_value_length_limit = attribute_limits->attribute_value_length_limit; - log_record_limits.attribute_count_limit = attribute_limits->attribute_count_limit; + return OptionalValue{ToUint32Limit(value.Value())}; } class ResourceAttributeValueSetter @@ -1491,19 +1493,49 @@ std::unique_ptr SdkBuilder::CreateTra } opentelemetry::sdk::trace::SpanLimits span_limits; + OptionalValue model_attribute_value_length_limit; + OptionalValue model_attribute_count_limit; + OptionalValue model_event_count_limit; + OptionalValue model_link_count_limit; + OptionalValue model_event_attribute_count_limit; + OptionalValue model_link_attribute_count_limit; if (model->limits) { - span_limits.attribute_value_length_limit = model->limits->attribute_value_length_limit; - span_limits.attribute_count_limit = model->limits->attribute_count_limit; - span_limits.event_count_limit = model->limits->event_count_limit; - span_limits.link_count_limit = model->limits->link_count_limit; - span_limits.event_attribute_count_limit = model->limits->event_attribute_count_limit; - span_limits.link_attribute_count_limit = model->limits->link_attribute_count_limit; - } - else - { - ApplyGeneralAttributeLimits(span_limits, attribute_limits); - } + model_attribute_value_length_limit = model->limits->attribute_value_length_limit; + model_attribute_count_limit = model->limits->attribute_count_limit; + model_event_count_limit = model->limits->event_count_limit; + model_link_count_limit = model->limits->link_count_limit; + model_event_attribute_count_limit = model->limits->event_attribute_count_limit; + model_link_attribute_count_limit = model->limits->link_attribute_count_limit; + } + + OptionalValue general_attribute_value_length_limit; + OptionalValue general_attribute_count_limit; + if (attribute_limits) + { + general_attribute_value_length_limit = attribute_limits->attribute_value_length_limit; + general_attribute_count_limit = attribute_limits->attribute_count_limit; + } + + using SpanLimitDefaults = SpanLimitsConfiguration; + span_limits.attribute_value_length_limit = ResolveLimit( + model_attribute_value_length_limit, general_attribute_value_length_limit, + SpanLimitDefaults::kDefaultAttributeValueLengthLimit); + span_limits.attribute_count_limit = + ResolveLimit(model_attribute_count_limit, ToOptionalUint32(general_attribute_count_limit), + SpanLimitDefaults::kDefaultAttributeCountLimit); + span_limits.event_count_limit = + ResolveLimit(model_event_count_limit, OptionalValue{}, + SpanLimitDefaults::kDefaultEventCountLimit); + span_limits.link_count_limit = + ResolveLimit(model_link_count_limit, OptionalValue{}, + SpanLimitDefaults::kDefaultLinkCountLimit); + span_limits.event_attribute_count_limit = + ResolveLimit(model_event_attribute_count_limit, OptionalValue{}, + SpanLimitDefaults::kDefaultEventAttributeCountLimit); + span_limits.link_attribute_count_limit = + ResolveLimit(model_link_attribute_count_limit, OptionalValue{}, + SpanLimitDefaults::kDefaultLinkAttributeCountLimit); if (model->tracer_configurator) { @@ -2406,16 +2438,30 @@ std::unique_ptr SdkBuilder::CreateLogg } opentelemetry::sdk::logs::LogRecordLimits log_record_limits; + OptionalValue model_attribute_value_length_limit; + OptionalValue model_attribute_count_limit; if (model->limits) { - log_record_limits.attribute_value_length_limit = model->limits->attribute_value_length_limit; - log_record_limits.attribute_count_limit = model->limits->attribute_count_limit; + model_attribute_value_length_limit = model->limits->attribute_value_length_limit; + model_attribute_count_limit = model->limits->attribute_count_limit; } - else + + OptionalValue general_attribute_value_length_limit; + OptionalValue general_attribute_count_limit; + if (attribute_limits) { - ApplyGeneralAttributeLimits(log_record_limits, attribute_limits); + general_attribute_value_length_limit = attribute_limits->attribute_value_length_limit; + general_attribute_count_limit = attribute_limits->attribute_count_limit; } + using LogLimitDefaults = LogRecordLimitsConfiguration; + log_record_limits.attribute_value_length_limit = ResolveLimit( + model_attribute_value_length_limit, general_attribute_value_length_limit, + LogLimitDefaults::kDefaultAttributeValueLengthLimit); + log_record_limits.attribute_count_limit = + ResolveLimit(model_attribute_count_limit, general_attribute_count_limit, + LogLimitDefaults::kDefaultAttributeCountLimit); + std::unique_ptr> logger_configurator; diff --git a/sdk/test/configuration/programmatic_configuration_test.cc b/sdk/test/configuration/programmatic_configuration_test.cc index 377ec37d2..bb6b5671b 100644 --- a/sdk/test/configuration/programmatic_configuration_test.cc +++ b/sdk/test/configuration/programmatic_configuration_test.cc @@ -329,10 +329,11 @@ TEST_F(ProgrammaticConfigTest, LoggerProviderWithLogRecordLimits) auto *record = log_buffer_->front().get(); EXPECT_EQ(nostd::get(record->GetBody()), "test-message"); const auto &attributes = record->GetAttributes(); - EXPECT_EQ(attributes.size(), limits.attribute_count_limit); + EXPECT_EQ(attributes.size(), limits.attribute_count_limit.Value()); for (const auto &attr : attributes) { - EXPECT_EQ(nostd::get(attr.second).size(), limits.attribute_value_length_limit); + EXPECT_EQ(nostd::get(attr.second).size(), + limits.attribute_value_length_limit.Value()); } } @@ -399,10 +400,49 @@ TEST_F(ProgrammaticConfigTest, LoggerProviderLimitsOverrideAttributeLimits) EXPECT_EQ(log_buffer_->size(), 1); auto *record = log_buffer_->front().get(); const auto &attributes = record->GetAttributes(); - EXPECT_EQ(attributes.size(), limits.attribute_count_limit); + EXPECT_EQ(attributes.size(), limits.attribute_count_limit.Value()); for (const auto &attr : attributes) { - EXPECT_EQ(nostd::get(attr.second).size(), limits.attribute_value_length_limit); + EXPECT_EQ(nostd::get(attr.second).size(), + limits.attribute_value_length_limit.Value()); + } +} + +TEST_F(ProgrammaticConfigTest, LoggerProviderLimitsPartialOverrideAttributeLimits) +{ + auto attribute_limits = std::make_unique(); + attribute_limits->attribute_count_limit = 1; + attribute_limits->attribute_value_length_limit = 3; + + config_sdk::LogRecordLimitsConfiguration limits; + limits.attribute_value_length_limit = 5; + + auto logger_provider_config = MakeLoggerProviderConfig(); + logger_provider_config->limits = + std::make_unique(limits); + + auto model = std::make_unique(); + model->attribute_limits = std::move(attribute_limits); + model->logger_provider = std::move(logger_provider_config); + + CreateAndInstallSdk(model); + ASSERT_NE(sdk_->logger_provider, nullptr); + + auto logger = logs::Provider::GetLoggerProvider()->GetLogger("test"); + logger->EmitLogRecord( + logs::Severity::kInfo, nostd::string_view("test-message"), + common::MakeAttributes({{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}})); + + ASSERT_TRUE(sdk_->logger_provider->ForceFlush(std::chrono::milliseconds(kProcessTimeout))); + ASSERT_TRUE(sdk_->logger_provider->Shutdown(std::chrono::milliseconds(kProcessTimeout))); + + EXPECT_EQ(log_buffer_->size(), 1); + auto *record = log_buffer_->front().get(); + const auto &attributes = record->GetAttributes(); + EXPECT_EQ(attributes.size(), 1); + for (const auto &attr : attributes) + { + EXPECT_EQ(nostd::get(attr.second).size(), 5); } } diff --git a/sdk/test/configuration/sdk_builder_test.cc b/sdk/test/configuration/sdk_builder_test.cc index 9368f8d34..18181962b 100644 --- a/sdk/test/configuration/sdk_builder_test.cc +++ b/sdk/test/configuration/sdk_builder_test.cc @@ -255,12 +255,14 @@ TEST(SdkBuilder, SpanLimitsConfiguration) ASSERT_NE(provider, nullptr); auto limits = provider->GetSpanLimits(); - EXPECT_EQ(limits.attribute_value_length_limit, model->limits->attribute_value_length_limit); - EXPECT_EQ(limits.attribute_count_limit, model->limits->attribute_count_limit); - EXPECT_EQ(limits.event_count_limit, model->limits->event_count_limit); - EXPECT_EQ(limits.link_count_limit, model->limits->link_count_limit); - EXPECT_EQ(limits.event_attribute_count_limit, model->limits->event_attribute_count_limit); - EXPECT_EQ(limits.link_attribute_count_limit, model->limits->link_attribute_count_limit); + EXPECT_EQ(limits.attribute_value_length_limit, + model->limits->attribute_value_length_limit.Value()); + EXPECT_EQ(limits.attribute_count_limit, model->limits->attribute_count_limit.Value()); + EXPECT_EQ(limits.event_count_limit, model->limits->event_count_limit.Value()); + EXPECT_EQ(limits.link_count_limit, model->limits->link_count_limit.Value()); + EXPECT_EQ(limits.event_attribute_count_limit, + model->limits->event_attribute_count_limit.Value()); + EXPECT_EQ(limits.link_attribute_count_limit, model->limits->link_attribute_count_limit.Value()); } TEST(SdkBuilder, SpanLimitsFromAttributeLimits) @@ -280,8 +282,9 @@ TEST(SdkBuilder, SpanLimitsFromAttributeLimits) const auto limits = provider->GetSpanLimits(); const auto default_limits = opentelemetry::sdk::trace::SpanLimits{}; - EXPECT_EQ(limits.attribute_count_limit, attribute_limits.attribute_count_limit); - EXPECT_EQ(limits.attribute_value_length_limit, attribute_limits.attribute_value_length_limit); + EXPECT_EQ(limits.attribute_count_limit, attribute_limits.attribute_count_limit.Value()); + EXPECT_EQ(limits.attribute_value_length_limit, + attribute_limits.attribute_value_length_limit.Value()); EXPECT_EQ(limits.event_count_limit, default_limits.event_count_limit); EXPECT_EQ(limits.link_count_limit, default_limits.link_count_limit); EXPECT_EQ(limits.event_attribute_count_limit, default_limits.event_attribute_count_limit); @@ -306,9 +309,56 @@ TEST(SdkBuilder, SpanLimitsOverrideAttributeLimits) ASSERT_NE(provider, nullptr); const auto limits = provider->GetSpanLimits(); - EXPECT_EQ(limits.attribute_value_length_limit, model->limits->attribute_value_length_limit); - EXPECT_EQ(limits.attribute_count_limit, model->limits->attribute_count_limit); - EXPECT_EQ(limits.event_count_limit, model->limits->event_count_limit); + EXPECT_EQ(limits.attribute_value_length_limit, + model->limits->attribute_value_length_limit.Value()); + EXPECT_EQ(limits.attribute_count_limit, model->limits->attribute_count_limit.Value()); + EXPECT_EQ(limits.event_count_limit, model->limits->event_count_limit.Value()); +} + +TEST(SdkBuilder, SpanLimitsPerFieldAttributeLimits) +{ + auto model = std::make_unique(); + model->limits = std::make_unique(); + model->limits->event_count_limit = 64; + model->limits->link_count_limit = 64; + model->limits->event_attribute_count_limit = 8; + model->limits->link_attribute_count_limit = 8; + + AttributeLimitsConfiguration attribute_limits; + attribute_limits.attribute_value_length_limit = 4096; + + SdkBuilder builder(RegistryFactory::Create()); + auto resource = opentelemetry::sdk::resource::Resource::Create({}); + auto provider = builder.CreateTracerProvider(model, resource, &attribute_limits); + ASSERT_NE(provider, nullptr); + + const auto limits = provider->GetSpanLimits(); + EXPECT_EQ(limits.attribute_value_length_limit, 4096); + EXPECT_EQ(limits.attribute_count_limit, SpanLimitsConfiguration::kDefaultAttributeCountLimit); + EXPECT_EQ(limits.event_count_limit, 64); + EXPECT_EQ(limits.link_count_limit, 64); + EXPECT_EQ(limits.event_attribute_count_limit, 8); + EXPECT_EQ(limits.link_attribute_count_limit, 8); +} + +TEST(SdkBuilder, SpanLimitsPartialOverrideAttributeLimits) +{ + auto model = std::make_unique(); + model->limits = std::make_unique(); + model->limits->attribute_count_limit = 22; + + AttributeLimitsConfiguration attribute_limits; + attribute_limits.attribute_count_limit = 7; + attribute_limits.attribute_value_length_limit = 9; + + SdkBuilder builder(RegistryFactory::Create()); + auto resource = opentelemetry::sdk::resource::Resource::Create({}); + auto provider = builder.CreateTracerProvider(model, resource, &attribute_limits); + ASSERT_NE(provider, nullptr); + + const auto limits = provider->GetSpanLimits(); + EXPECT_EQ(limits.attribute_count_limit, 22); + EXPECT_EQ(limits.attribute_value_length_limit, 9); } #if defined(ENABLE_METRICS_EXEMPLAR_PREVIEW) && !defined(NO_GETENV) diff --git a/sdk/test/configuration/yaml_logs_test.cc b/sdk/test/configuration/yaml_logs_test.cc index 78ca46f62..a7c7c5591 100644 --- a/sdk/test/configuration/yaml_logs_test.cc +++ b/sdk/test/configuration/yaml_logs_test.cc @@ -461,10 +461,8 @@ file_format: "1.0-logs" ASSERT_NE(config, nullptr); ASSERT_NE(config->logger_provider, nullptr); ASSERT_NE(config->logger_provider->limits, nullptr); - const auto defaults = opentelemetry::sdk::configuration::LogRecordLimitsConfiguration{}; - ASSERT_EQ(config->logger_provider->limits->attribute_value_length_limit, - defaults.attribute_value_length_limit); - ASSERT_EQ(config->logger_provider->limits->attribute_count_limit, 128); + ASSERT_FALSE(config->logger_provider->limits->attribute_value_length_limit.HasValue()); + ASSERT_FALSE(config->logger_provider->limits->attribute_count_limit.HasValue()); } TEST(YamlLogs, limits) @@ -485,8 +483,33 @@ file_format: "1.0-logs" ASSERT_NE(config, nullptr); ASSERT_NE(config->logger_provider, nullptr); ASSERT_NE(config->logger_provider->limits, nullptr); - ASSERT_EQ(config->logger_provider->limits->attribute_value_length_limit, 1111); - ASSERT_EQ(config->logger_provider->limits->attribute_count_limit, 2222); + ASSERT_TRUE(config->logger_provider->limits->attribute_value_length_limit.HasValue()); + ASSERT_EQ(config->logger_provider->limits->attribute_value_length_limit.Value(), 1111); + ASSERT_TRUE(config->logger_provider->limits->attribute_count_limit.HasValue()); + ASSERT_EQ(config->logger_provider->limits->attribute_count_limit.Value(), 2222); +} + +TEST(YamlLogs, limits_null_fields) +{ + std::string yaml = R"( +file_format: "1.0-logs" +logger_provider: + processors: + - simple: + exporter: + console: + limits: + attribute_value_length_limit: 1024 + attribute_count_limit: null +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->logger_provider, nullptr); + ASSERT_NE(config->logger_provider->limits, nullptr); + ASSERT_TRUE(config->logger_provider->limits->attribute_value_length_limit.HasValue()); + ASSERT_EQ(config->logger_provider->limits->attribute_value_length_limit.Value(), 1024); + ASSERT_FALSE(config->logger_provider->limits->attribute_count_limit.HasValue()); } TEST(YamlLogs, no_logger_configurator) diff --git a/sdk/test/configuration/yaml_test.cc b/sdk/test/configuration/yaml_test.cc index 8f9547842..a12331d2c 100644 --- a/sdk/test/configuration/yaml_test.cc +++ b/sdk/test/configuration/yaml_test.cc @@ -176,10 +176,8 @@ file_format: "1.0" ASSERT_NE(config, nullptr); ASSERT_EQ(config->file_format, "1.0"); ASSERT_NE(config->attribute_limits, nullptr); - const auto defaults = opentelemetry::sdk::configuration::AttributeLimitsConfiguration{}; - ASSERT_EQ(config->attribute_limits->attribute_value_length_limit, - defaults.attribute_value_length_limit); - ASSERT_EQ(config->attribute_limits->attribute_count_limit, 128); + ASSERT_FALSE(config->attribute_limits->attribute_value_length_limit.HasValue()); + ASSERT_FALSE(config->attribute_limits->attribute_count_limit.HasValue()); } TEST(Yaml, attribute_limits) @@ -195,8 +193,27 @@ file_format: "1.0" ASSERT_NE(config, nullptr); ASSERT_EQ(config->file_format, "1.0"); ASSERT_NE(config->attribute_limits, nullptr); - ASSERT_EQ(config->attribute_limits->attribute_value_length_limit, 1234); - ASSERT_EQ(config->attribute_limits->attribute_count_limit, 5678); + ASSERT_TRUE(config->attribute_limits->attribute_value_length_limit.HasValue()); + ASSERT_EQ(config->attribute_limits->attribute_value_length_limit.Value(), 1234); + ASSERT_TRUE(config->attribute_limits->attribute_count_limit.HasValue()); + ASSERT_EQ(config->attribute_limits->attribute_count_limit.Value(), 5678); +} + +TEST(Yaml, attribute_limits_null_fields) +{ + std::string yaml = R"( +file_format: "1.0" +attribute_limits: + attribute_value_length_limit: 4096 + attribute_count_limit: null +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->attribute_limits, nullptr); + ASSERT_TRUE(config->attribute_limits->attribute_value_length_limit.HasValue()); + ASSERT_EQ(config->attribute_limits->attribute_value_length_limit.Value(), 4096); + ASSERT_FALSE(config->attribute_limits->attribute_count_limit.HasValue()); } TEST(Yaml, no_optional_boolean) @@ -511,7 +528,7 @@ file_format: "1.0" auto config = DoParse(yaml); ASSERT_NE(config, nullptr); ASSERT_NE(config->attribute_limits, nullptr); - ASSERT_EQ(config->attribute_limits->attribute_count_limit, 128); + ASSERT_FALSE(config->attribute_limits->attribute_count_limit.HasValue()); } TEST(Yaml, illegal_integer) @@ -539,7 +556,7 @@ file_format: "1.0" auto config = DoParse(yaml); ASSERT_NE(config, nullptr); ASSERT_NE(config->attribute_limits, nullptr); - ASSERT_EQ(config->attribute_limits->attribute_count_limit, 128); + ASSERT_FALSE(config->attribute_limits->attribute_count_limit.HasValue()); } TEST(Yaml, empty_integer_substitution) @@ -555,7 +572,7 @@ file_format: "1.0" auto config = DoParse(yaml); ASSERT_NE(config, nullptr); ASSERT_NE(config->attribute_limits, nullptr); - ASSERT_EQ(config->attribute_limits->attribute_count_limit, 128); + ASSERT_FALSE(config->attribute_limits->attribute_count_limit.HasValue()); } TEST(Yaml, with_integer_substitution) @@ -571,7 +588,8 @@ file_format: "1.0" auto config = DoParse(yaml); ASSERT_NE(config, nullptr); ASSERT_NE(config->attribute_limits, nullptr); - ASSERT_EQ(config->attribute_limits->attribute_count_limit, 7777); + ASSERT_TRUE(config->attribute_limits->attribute_count_limit.HasValue()); + ASSERT_EQ(config->attribute_limits->attribute_count_limit.Value(), 7777); } TEST(Yaml, with_illegal_integer_substitution) diff --git a/sdk/test/configuration/yaml_trace_test.cc b/sdk/test/configuration/yaml_trace_test.cc index 1165f13ae..27ebe1937 100644 --- a/sdk/test/configuration/yaml_trace_test.cc +++ b/sdk/test/configuration/yaml_trace_test.cc @@ -605,14 +605,12 @@ file_format: "1.0-trace" ASSERT_NE(config, nullptr); ASSERT_NE(config->tracer_provider, nullptr); ASSERT_NE(config->tracer_provider->limits, nullptr); - const auto defaults = opentelemetry::sdk::configuration::SpanLimitsConfiguration{}; - ASSERT_EQ(config->tracer_provider->limits->attribute_value_length_limit, - defaults.attribute_value_length_limit); - ASSERT_EQ(config->tracer_provider->limits->attribute_count_limit, 128); - ASSERT_EQ(config->tracer_provider->limits->event_count_limit, 128); - ASSERT_EQ(config->tracer_provider->limits->link_count_limit, 128); - ASSERT_EQ(config->tracer_provider->limits->event_attribute_count_limit, 128); - ASSERT_EQ(config->tracer_provider->limits->link_attribute_count_limit, 128); + ASSERT_FALSE(config->tracer_provider->limits->attribute_value_length_limit.HasValue()); + ASSERT_FALSE(config->tracer_provider->limits->attribute_count_limit.HasValue()); + ASSERT_FALSE(config->tracer_provider->limits->event_count_limit.HasValue()); + ASSERT_FALSE(config->tracer_provider->limits->link_count_limit.HasValue()); + ASSERT_FALSE(config->tracer_provider->limits->event_attribute_count_limit.HasValue()); + ASSERT_FALSE(config->tracer_provider->limits->link_attribute_count_limit.HasValue()); } TEST(YamlTrace, limits) @@ -637,12 +635,43 @@ file_format: "1.0-trace" ASSERT_NE(config, nullptr); ASSERT_NE(config->tracer_provider, nullptr); ASSERT_NE(config->tracer_provider->limits, nullptr); - ASSERT_EQ(config->tracer_provider->limits->attribute_value_length_limit, 1111); - ASSERT_EQ(config->tracer_provider->limits->attribute_count_limit, 2222); - ASSERT_EQ(config->tracer_provider->limits->event_count_limit, 3333); - ASSERT_EQ(config->tracer_provider->limits->link_count_limit, 4444); - ASSERT_EQ(config->tracer_provider->limits->event_attribute_count_limit, 5555); - ASSERT_EQ(config->tracer_provider->limits->link_attribute_count_limit, 6666); + ASSERT_TRUE(config->tracer_provider->limits->attribute_value_length_limit.HasValue()); + ASSERT_EQ(config->tracer_provider->limits->attribute_value_length_limit.Value(), 1111); + ASSERT_TRUE(config->tracer_provider->limits->attribute_count_limit.HasValue()); + ASSERT_EQ(config->tracer_provider->limits->attribute_count_limit.Value(), 2222); + ASSERT_TRUE(config->tracer_provider->limits->event_count_limit.HasValue()); + ASSERT_EQ(config->tracer_provider->limits->event_count_limit.Value(), 3333); + ASSERT_TRUE(config->tracer_provider->limits->link_count_limit.HasValue()); + ASSERT_EQ(config->tracer_provider->limits->link_count_limit.Value(), 4444); + ASSERT_TRUE(config->tracer_provider->limits->event_attribute_count_limit.HasValue()); + ASSERT_EQ(config->tracer_provider->limits->event_attribute_count_limit.Value(), 5555); + ASSERT_TRUE(config->tracer_provider->limits->link_attribute_count_limit.HasValue()); + ASSERT_EQ(config->tracer_provider->limits->link_attribute_count_limit.Value(), 6666); +} + +TEST(YamlTrace, limits_null_fields) +{ + std::string yaml = R"( +file_format: "1.0-trace" +tracer_provider: + processors: + - simple: + exporter: + console: + limits: + attribute_value_length_limit: null + attribute_count_limit: null + event_count_limit: 64 +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_NE(config->tracer_provider->limits, nullptr); + ASSERT_FALSE(config->tracer_provider->limits->attribute_value_length_limit.HasValue()); + ASSERT_FALSE(config->tracer_provider->limits->attribute_count_limit.HasValue()); + ASSERT_TRUE(config->tracer_provider->limits->event_count_limit.HasValue()); + ASSERT_EQ(config->tracer_provider->limits->event_count_limit.Value(), 64); } TEST(YamlTrace, limits_with_invalid_values) From c995d4ee21647c56dcd6eccdd4c15916e8afae38 Mon Sep 17 00:00:00 2001 From: ayush-singh-0601 Date: Tue, 25 Aug 2026 21:11:02 +0530 Subject: [PATCH 5/6] [CONFIGURATION] Fix attribute limits CI failures --- sdk/src/configuration/configuration_parser.cc | 2 +- sdk/src/configuration/sdk_builder.cc | 14 +++++++------- .../programmatic_configuration_test.cc | 1 + sdk/test/configuration/sdk_builder_test.cc | 19 ++++++++++--------- sdk/test/configuration/yaml_logs_test.cc | 1 + sdk/test/configuration/yaml_test.cc | 1 + sdk/test/configuration/yaml_trace_test.cc | 1 + 7 files changed, 22 insertions(+), 17 deletions(-) diff --git a/sdk/src/configuration/configuration_parser.cc b/sdk/src/configuration/configuration_parser.cc index 2b8900479..0fc7762f1 100644 --- a/sdk/src/configuration/configuration_parser.cc +++ b/sdk/src/configuration/configuration_parser.cc @@ -17,7 +17,6 @@ #include "opentelemetry/sdk/configuration/always_off_sampler_configuration.h" #include "opentelemetry/sdk/configuration/always_on_sampler_configuration.h" #include "opentelemetry/sdk/configuration/attribute_limits_configuration.h" -#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/sdk/configuration/attribute_value_configuration.h" #include "opentelemetry/sdk/configuration/attributes_configuration.h" #include "opentelemetry/sdk/configuration/base2_exponential_bucket_histogram_aggregation_configuration.h" @@ -88,6 +87,7 @@ #include "opentelemetry/sdk/configuration/metric_producer_configuration.h" #include "opentelemetry/sdk/configuration/metric_reader_configuration.h" #include "opentelemetry/sdk/configuration/open_census_metric_producer_configuration.h" +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/sdk/configuration/otlp_file_log_record_exporter_configuration.h" #include "opentelemetry/sdk/configuration/otlp_file_push_metric_exporter_configuration.h" #include "opentelemetry/sdk/configuration/otlp_file_span_exporter_configuration.h" diff --git a/sdk/src/configuration/sdk_builder.cc b/sdk/src/configuration/sdk_builder.cc index 7b92e125b..ece90672e 100644 --- a/sdk/src/configuration/sdk_builder.cc +++ b/sdk/src/configuration/sdk_builder.cc @@ -26,7 +26,6 @@ #include "opentelemetry/sdk/configuration/always_on_sampler_builder.h" #include "opentelemetry/sdk/configuration/always_on_sampler_configuration.h" #include "opentelemetry/sdk/configuration/attribute_limits_configuration.h" -#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/sdk/configuration/attribute_value_configuration.h" #include "opentelemetry/sdk/configuration/attribute_value_configuration_visitor.h" #include "opentelemetry/sdk/configuration/attributes_configuration.h" @@ -104,6 +103,7 @@ #include "opentelemetry/sdk/configuration/meter_provider_configuration.h" #include "opentelemetry/sdk/configuration/metric_reader_configuration.h" #include "opentelemetry/sdk/configuration/metric_reader_configuration_visitor.h" +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/sdk/configuration/otlp_file_log_record_exporter_builder.h" #include "opentelemetry/sdk/configuration/otlp_file_log_record_exporter_configuration.h" #include "opentelemetry/sdk/configuration/otlp_file_push_metric_exporter_builder.h" @@ -1518,9 +1518,9 @@ std::unique_ptr SdkBuilder::CreateTra } using SpanLimitDefaults = SpanLimitsConfiguration; - span_limits.attribute_value_length_limit = ResolveLimit( - model_attribute_value_length_limit, general_attribute_value_length_limit, - SpanLimitDefaults::kDefaultAttributeValueLengthLimit); + span_limits.attribute_value_length_limit = + ResolveLimit(model_attribute_value_length_limit, general_attribute_value_length_limit, + SpanLimitDefaults::kDefaultAttributeValueLengthLimit); span_limits.attribute_count_limit = ResolveLimit(model_attribute_count_limit, ToOptionalUint32(general_attribute_count_limit), SpanLimitDefaults::kDefaultAttributeCountLimit); @@ -2455,9 +2455,9 @@ std::unique_ptr SdkBuilder::CreateLogg } using LogLimitDefaults = LogRecordLimitsConfiguration; - log_record_limits.attribute_value_length_limit = ResolveLimit( - model_attribute_value_length_limit, general_attribute_value_length_limit, - LogLimitDefaults::kDefaultAttributeValueLengthLimit); + log_record_limits.attribute_value_length_limit = + ResolveLimit(model_attribute_value_length_limit, general_attribute_value_length_limit, + LogLimitDefaults::kDefaultAttributeValueLengthLimit); log_record_limits.attribute_count_limit = ResolveLimit(model_attribute_count_limit, general_attribute_count_limit, LogLimitDefaults::kDefaultAttributeCountLimit); diff --git a/sdk/test/configuration/programmatic_configuration_test.cc b/sdk/test/configuration/programmatic_configuration_test.cc index bb6b5671b..5bce45cc0 100644 --- a/sdk/test/configuration/programmatic_configuration_test.cc +++ b/sdk/test/configuration/programmatic_configuration_test.cc @@ -70,6 +70,7 @@ #include "opentelemetry/sdk/configuration/meter_matcher_and_config_configuration.h" #include "opentelemetry/sdk/configuration/meter_provider_configuration.h" #include "opentelemetry/sdk/configuration/metric_reader_configuration.h" +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/sdk/configuration/parent_based_sampler_configuration.h" #include "opentelemetry/sdk/configuration/periodic_metric_reader_builder.h" #include "opentelemetry/sdk/configuration/periodic_metric_reader_configuration.h" diff --git a/sdk/test/configuration/sdk_builder_test.cc b/sdk/test/configuration/sdk_builder_test.cc index 3cc224956..44054a5e0 100644 --- a/sdk/test/configuration/sdk_builder_test.cc +++ b/sdk/test/configuration/sdk_builder_test.cc @@ -55,6 +55,7 @@ #include "opentelemetry/sdk/configuration/logger_config_configuration.h" #include "opentelemetry/sdk/configuration/logger_configurator_configuration.h" #include "opentelemetry/sdk/configuration/logger_matcher_and_config_configuration.h" +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/sdk/configuration/parent_based_sampler_configuration.h" #include "opentelemetry/sdk/configuration/periodic_metric_reader_builder.h" #include "opentelemetry/sdk/configuration/periodic_metric_reader_configuration.h" @@ -260,8 +261,7 @@ TEST(SdkBuilder, SpanLimitsConfiguration) EXPECT_EQ(limits.attribute_count_limit, model->limits->attribute_count_limit.Value()); EXPECT_EQ(limits.event_count_limit, model->limits->event_count_limit.Value()); EXPECT_EQ(limits.link_count_limit, model->limits->link_count_limit.Value()); - EXPECT_EQ(limits.event_attribute_count_limit, - model->limits->event_attribute_count_limit.Value()); + EXPECT_EQ(limits.event_attribute_count_limit, model->limits->event_attribute_count_limit.Value()); EXPECT_EQ(limits.link_attribute_count_limit, model->limits->link_attribute_count_limit.Value()); } @@ -317,8 +317,8 @@ TEST(SdkBuilder, SpanLimitsOverrideAttributeLimits) TEST(SdkBuilder, SpanLimitsPerFieldAttributeLimits) { - auto model = std::make_unique(); - model->limits = std::make_unique(); + auto model = std::make_unique(); + model->limits = std::make_unique(); model->limits->event_count_limit = 64; model->limits->link_count_limit = 64; model->limits->event_attribute_count_limit = 8; @@ -332,9 +332,10 @@ TEST(SdkBuilder, SpanLimitsPerFieldAttributeLimits) auto provider = builder.CreateTracerProvider(model, resource, &attribute_limits); ASSERT_NE(provider, nullptr); - const auto limits = provider->GetSpanLimits(); + const auto limits = provider->GetSpanLimits(); + const auto default_limits = opentelemetry::sdk::trace::SpanLimits{}; EXPECT_EQ(limits.attribute_value_length_limit, 4096); - EXPECT_EQ(limits.attribute_count_limit, SpanLimitsConfiguration::kDefaultAttributeCountLimit); + EXPECT_EQ(limits.attribute_count_limit, default_limits.attribute_count_limit); EXPECT_EQ(limits.event_count_limit, 64); EXPECT_EQ(limits.link_count_limit, 64); EXPECT_EQ(limits.event_attribute_count_limit, 8); @@ -343,9 +344,9 @@ TEST(SdkBuilder, SpanLimitsPerFieldAttributeLimits) TEST(SdkBuilder, SpanLimitsPartialOverrideAttributeLimits) { - auto model = std::make_unique(); - model->limits = std::make_unique(); - model->limits->attribute_count_limit = 22; + auto model = std::make_unique(); + model->limits = std::make_unique(); + model->limits->attribute_count_limit = 22; AttributeLimitsConfiguration attribute_limits; attribute_limits.attribute_count_limit = 7; diff --git a/sdk/test/configuration/yaml_logs_test.cc b/sdk/test/configuration/yaml_logs_test.cc index a7c7c5591..1bd933ba0 100644 --- a/sdk/test/configuration/yaml_logs_test.cc +++ b/sdk/test/configuration/yaml_logs_test.cc @@ -17,6 +17,7 @@ #include "opentelemetry/sdk/configuration/logger_configurator_configuration.h" #include "opentelemetry/sdk/configuration/logger_matcher_and_config_configuration.h" #include "opentelemetry/sdk/configuration/logger_provider_configuration.h" +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/sdk/configuration/otlp_file_log_record_exporter_configuration.h" #include "opentelemetry/sdk/configuration/otlp_grpc_log_record_exporter_configuration.h" #include "opentelemetry/sdk/configuration/otlp_http_encoding.h" diff --git a/sdk/test/configuration/yaml_test.cc b/sdk/test/configuration/yaml_test.cc index 1816390cc..823c7c142 100644 --- a/sdk/test/configuration/yaml_test.cc +++ b/sdk/test/configuration/yaml_test.cc @@ -8,6 +8,7 @@ #include "opentelemetry/sdk/configuration/attribute_limits_configuration.h" #include "opentelemetry/sdk/configuration/configuration.h" +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/sdk/configuration/severity_number.h" #include "opentelemetry/sdk/configuration/trace_id_ratio_based_sampler_configuration.h" #include "opentelemetry/sdk/configuration/tracer_provider_configuration.h" diff --git a/sdk/test/configuration/yaml_trace_test.cc b/sdk/test/configuration/yaml_trace_test.cc index 27ebe1937..2a6f95bf4 100644 --- a/sdk/test/configuration/yaml_trace_test.cc +++ b/sdk/test/configuration/yaml_trace_test.cc @@ -25,6 +25,7 @@ #include "opentelemetry/sdk/configuration/headers_configuration.h" #include "opentelemetry/sdk/configuration/http_tls_configuration.h" #include "opentelemetry/sdk/configuration/jaeger_remote_sampler_configuration.h" +#include "opentelemetry/sdk/configuration/optional_value.h" #include "opentelemetry/sdk/configuration/otlp_file_span_exporter_configuration.h" #include "opentelemetry/sdk/configuration/otlp_grpc_span_exporter_configuration.h" #include "opentelemetry/sdk/configuration/otlp_http_encoding.h" From 96432981964aa2533933367d9887c55634cc22d2 Mon Sep 17 00:00:00 2001 From: ayush-singh-0601 Date: Tue, 25 Aug 2026 22:39:12 +0530 Subject: [PATCH 6/6] [CONFIGURATION] Address optional value review feedback --- .../sdk/configuration/optional_value.h | 11 ++++++++++- sdk/src/configuration/ryml_document_node.cc | 11 ++++------- .../programmatic_configuration_test.cc | 8 ++++++++ sdk/test/configuration/yaml_test.cc | 14 ++++++++++++++ 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/sdk/include/opentelemetry/sdk/configuration/optional_value.h b/sdk/include/opentelemetry/sdk/configuration/optional_value.h index c9cf73d9f..42086f6f4 100644 --- a/sdk/include/opentelemetry/sdk/configuration/optional_value.h +++ b/sdk/include/opentelemetry/sdk/configuration/optional_value.h @@ -3,6 +3,8 @@ #pragma once +#include + #include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -25,7 +27,14 @@ class OptionalValue bool HasValue() const { return has_value_; } - const T &Value() const { return value_; } + const T &Value() const + { + if (!has_value_) + { + throw std::runtime_error("OptionalValue has no value"); + } + return value_; + } T ValueOr(T fallback) const { return has_value_ ? value_ : fallback; } diff --git a/sdk/src/configuration/ryml_document_node.cc b/sdk/src/configuration/ryml_document_node.cc index 2e7c9b028..634764280 100644 --- a/sdk/src/configuration/ryml_document_node.cc +++ b/sdk/src/configuration/ryml_document_node.cc @@ -302,19 +302,16 @@ OptionalValue RymlDocumentNode::GetOptionalInteger(const std::strin { OTEL_INTERNAL_LOG_DEBUG("RymlDocumentNode::GetOptionalInteger(" << name << ")"); - auto ryml_child = GetRymlChildNode(name); + auto child = GetChildNode(name); - if (ryml_child.invalid() || !ryml_child.has_val()) + if (!child || child->IsNull()) { return OptionalValue{}; } - ryml::csubstr view = ryml_child.val(); - std::string value(view.str, view.len); - - value = DoSubstitution(value); + std::string value = child->AsString(); - if (value.empty() || value == "~" || value == "null" || value == "Null" || value == "NULL") + if (value.empty()) { return OptionalValue{}; } diff --git a/sdk/test/configuration/programmatic_configuration_test.cc b/sdk/test/configuration/programmatic_configuration_test.cc index 5bce45cc0..10e2f2117 100644 --- a/sdk/test/configuration/programmatic_configuration_test.cc +++ b/sdk/test/configuration/programmatic_configuration_test.cc @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -221,6 +222,13 @@ class ProgrammaticConfigTest : public ::testing::Test } // namespace +TEST(OptionalValue, ValueThrowsWhenEmpty) +{ + config_sdk::OptionalValue value; + + EXPECT_THROW(value.Value(), std::runtime_error); +} + //--------------------------------------------------------------------------- // Resource configuration tests diff --git a/sdk/test/configuration/yaml_test.cc b/sdk/test/configuration/yaml_test.cc index 823c7c142..647312fb8 100644 --- a/sdk/test/configuration/yaml_test.cc +++ b/sdk/test/configuration/yaml_test.cc @@ -218,6 +218,20 @@ file_format: "1.0" ASSERT_FALSE(config->attribute_limits->attribute_count_limit.HasValue()); } +TEST(Yaml, attribute_limits_tilde_null_field) +{ + std::string yaml = R"( +file_format: "1.0" +attribute_limits: + attribute_count_limit: ~ +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->attribute_limits, nullptr); + ASSERT_FALSE(config->attribute_limits->attribute_count_limit.HasValue()); +} + TEST(Yaml, no_optional_boolean) { std::string yaml = R"(