diff --git a/CHANGELOG.md b/CHANGELOG.md index 765eb43998..27aa4d7805 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,12 @@ Increment the: ## [Unreleased] +* [CONFIGURATION] Parse the `event_to_span_event_bridge/development` log + record processor configuration in declarative configuration. The SDK + implementation of this processor is not yet available; `SdkBuilder` logs a + warning and skips it when configured. + [#4309](https://github.com/open-telemetry/opentelemetry-cpp/pull/4309) + * [SDK] Clamp `BatchSpanProcessor` max_export_batch_size to max_queue_size, so a larger value no longer stops spans from being exported until the schedule delay expires. diff --git a/sdk/include/opentelemetry/sdk/configuration/configuration_parser.h b/sdk/include/opentelemetry/sdk/configuration/configuration_parser.h index 15e1748280..be162cd2ec 100644 --- a/sdk/include/opentelemetry/sdk/configuration/configuration_parser.h +++ b/sdk/include/opentelemetry/sdk/configuration/configuration_parser.h @@ -37,6 +37,7 @@ #include "opentelemetry/sdk/configuration/double_array_attribute_value_configuration.h" #include "opentelemetry/sdk/configuration/double_attribute_value_configuration.h" #include "opentelemetry/sdk/configuration/drop_aggregation_configuration.h" +#include "opentelemetry/sdk/configuration/event_to_span_event_bridge_log_record_processor_configuration.h" #include "opentelemetry/sdk/configuration/exemplar_filter.h" #include "opentelemetry/sdk/configuration/explicit_bucket_histogram_aggregation_configuration.h" #include "opentelemetry/sdk/configuration/extension_composable_sampler_configuration.h" @@ -171,6 +172,10 @@ class ConfigurationParser std::unique_ptr ParseSimpleLogRecordProcessorConfiguration( const std::unique_ptr &node) const; + std::unique_ptr + ParseEventToSpanEventBridgeLogRecordProcessorConfiguration( + const std::unique_ptr &node) const; + std::unique_ptr ParseExtensionLogRecordProcessorConfiguration(const std::string &name, std::unique_ptr node) const; diff --git a/sdk/include/opentelemetry/sdk/configuration/event_to_span_event_bridge_log_record_processor_configuration.h b/sdk/include/opentelemetry/sdk/configuration/event_to_span_event_bridge_log_record_processor_configuration.h new file mode 100644 index 0000000000..687b416e30 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/configuration/event_to_span_event_bridge_log_record_processor_configuration.h @@ -0,0 +1,29 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/sdk/configuration/log_record_processor_configuration.h" +#include "opentelemetry/sdk/configuration/log_record_processor_configuration_visitor.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace configuration +{ + +// YAML-SCHEMA: schema/logger_provider.json +// YAML-NODE: ExperimentalEventToSpanEventBridgeLogRecordProcessor +class EventToSpanEventBridgeLogRecordProcessorConfiguration : public LogRecordProcessorConfiguration +{ +public: + void Accept(LogRecordProcessorConfigurationVisitor *visitor) const override + { + visitor->VisitEventToSpanEventBridge(this); + } +}; + +} // namespace configuration +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/configuration/log_record_processor_configuration_visitor.h b/sdk/include/opentelemetry/sdk/configuration/log_record_processor_configuration_visitor.h index ac4dd52d23..320a8fe4b1 100644 --- a/sdk/include/opentelemetry/sdk/configuration/log_record_processor_configuration_visitor.h +++ b/sdk/include/opentelemetry/sdk/configuration/log_record_processor_configuration_visitor.h @@ -13,6 +13,7 @@ namespace configuration class BatchLogRecordProcessorConfiguration; class SimpleLogRecordProcessorConfiguration; +class EventToSpanEventBridgeLogRecordProcessorConfiguration; class ExtensionLogRecordProcessorConfiguration; class LogRecordProcessorConfigurationVisitor @@ -27,8 +28,10 @@ class LogRecordProcessorConfigurationVisitor const LogRecordProcessorConfigurationVisitor &other) = default; virtual ~LogRecordProcessorConfigurationVisitor() = default; - virtual void VisitBatch(const BatchLogRecordProcessorConfiguration *model) = 0; - virtual void VisitSimple(const SimpleLogRecordProcessorConfiguration *model) = 0; + virtual void VisitBatch(const BatchLogRecordProcessorConfiguration *model) = 0; + virtual void VisitSimple(const SimpleLogRecordProcessorConfiguration *model) = 0; + virtual void VisitEventToSpanEventBridge( + const EventToSpanEventBridgeLogRecordProcessorConfiguration *model) = 0; virtual void VisitExtension(const ExtensionLogRecordProcessorConfiguration *model) = 0; }; diff --git a/sdk/src/configuration/configuration_parser.cc b/sdk/src/configuration/configuration_parser.cc index 26613b26e5..fc9e4fb545 100644 --- a/sdk/src/configuration/configuration_parser.cc +++ b/sdk/src/configuration/configuration_parser.cc @@ -51,6 +51,7 @@ #include "opentelemetry/sdk/configuration/double_array_attribute_value_configuration.h" #include "opentelemetry/sdk/configuration/double_attribute_value_configuration.h" #include "opentelemetry/sdk/configuration/drop_aggregation_configuration.h" +#include "opentelemetry/sdk/configuration/event_to_span_event_bridge_log_record_processor_configuration.h" #include "opentelemetry/sdk/configuration/exemplar_filter.h" #include "opentelemetry/sdk/configuration/explicit_bucket_histogram_aggregation_configuration.h" #include "opentelemetry/sdk/configuration/extension_composable_sampler_configuration.h" @@ -612,6 +613,13 @@ ConfigurationParser::ParseSimpleLogRecordProcessorConfiguration( return model; } +std::unique_ptr +ConfigurationParser::ParseEventToSpanEventBridgeLogRecordProcessorConfiguration( + const std::unique_ptr & /* node */) const +{ + return std::make_unique(); +} + std::unique_ptr ConfigurationParser::ParseExtensionLogRecordProcessorConfiguration( const std::string &name, @@ -657,6 +665,10 @@ ConfigurationParser::ParseLogRecordProcessorConfiguration( { model = ParseSimpleLogRecordProcessorConfiguration(child); } + else if (name == "event_to_span_event_bridge/development") + { + model = ParseEventToSpanEventBridgeLogRecordProcessorConfiguration(child); + } else { model = ParseExtensionLogRecordProcessorConfiguration(name, std::move(child)); diff --git a/sdk/src/configuration/logs_builder_utils.cc b/sdk/src/configuration/logs_builder_utils.cc index 22a4d94d42..31d9f0bc27 100644 --- a/sdk/src/configuration/logs_builder_utils.cc +++ b/sdk/src/configuration/logs_builder_utils.cc @@ -14,6 +14,7 @@ #include "opentelemetry/sdk/configuration/batch_log_record_processor_configuration.h" #include "opentelemetry/sdk/configuration/console_log_record_exporter_builder.h" #include "opentelemetry/sdk/configuration/console_log_record_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/event_to_span_event_bridge_log_record_processor_configuration.h" #include "opentelemetry/sdk/configuration/extension_log_record_exporter_builder.h" #include "opentelemetry/sdk/configuration/extension_log_record_exporter_configuration.h" #include "opentelemetry/sdk/configuration/extension_log_record_processor_builder.h" @@ -172,6 +173,18 @@ class LogRecordExporterDispatcher const Registry *registry_; }; +static std::unique_ptr +CreateEventToSpanEventBridgeLogRecordProcessor( + const opentelemetry::sdk::configuration::EventToSpanEventBridgeLogRecordProcessorConfiguration + * /* model */) +{ + // FIXME-SDK: not yet implemented. + // https://github.com/open-telemetry/opentelemetry-cpp/issues/4454 + OTEL_INTERNAL_LOG_WARN( + "event_to_span_event_bridge/development processor is not yet supported, ignoring"); + return nullptr; +} + static std::unique_ptr CreateExtensionLogRecordProcessor( const Registry *registry, @@ -233,6 +246,13 @@ class LogRecordProcessorDispatcher throw UnsupportedException(message); } + void VisitEventToSpanEventBridge( + const opentelemetry::sdk::configuration::EventToSpanEventBridgeLogRecordProcessorConfiguration + *model) override + { + processor = CreateEventToSpanEventBridgeLogRecordProcessor(model); + } + void VisitExtension( const opentelemetry::sdk::configuration::ExtensionLogRecordProcessorConfiguration *model) override diff --git a/sdk/test/configuration/BUILD b/sdk/test/configuration/BUILD index 8b102946f7..89baf13796 100644 --- a/sdk/test/configuration/BUILD +++ b/sdk/test/configuration/BUILD @@ -117,6 +117,7 @@ cc_test( "//sdk:headers", "//sdk/src/configuration:configuration_logs_builders", "//sdk/src/logs", + "//test_common:headers", "@com_google_googletest//:gtest_main", ], ) diff --git a/sdk/test/configuration/CMakeLists.txt b/sdk/test/configuration/CMakeLists.txt index 71f85e264b..7d627b9663 100644 --- a/sdk/test/configuration/CMakeLists.txt +++ b/sdk/test/configuration/CMakeLists.txt @@ -35,7 +35,7 @@ target_link_libraries( logs_builders_test PRIVATE ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_configuration_logs_builders - opentelemetry_configuration_core) + opentelemetry_configuration_core opentelemetry_test_common) gtest_add_tests( TARGET logs_builders_test TEST_PREFIX config. diff --git a/sdk/test/configuration/logs_builders_test.cc b/sdk/test/configuration/logs_builders_test.cc index aa34e11547..bb16f23da5 100644 --- a/sdk/test/configuration/logs_builders_test.cc +++ b/sdk/test/configuration/logs_builders_test.cc @@ -14,12 +14,14 @@ #include "opentelemetry/logs/provider.h" #include "opentelemetry/logs/severity.h" +#include "opentelemetry/sdk/common/global_log_handler.h" #include "opentelemetry/sdk/configuration/batch_log_record_processor_builder.h" #include "opentelemetry/sdk/configuration/batch_log_record_processor_configuration.h" #include "opentelemetry/sdk/configuration/configuration.h" #include "opentelemetry/sdk/configuration/configured_sdk.h" #include "opentelemetry/sdk/configuration/console_log_record_exporter_builder.h" #include "opentelemetry/sdk/configuration/console_log_record_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/event_to_span_event_bridge_log_record_processor_configuration.h" #include "opentelemetry/sdk/configuration/extension_log_record_exporter_builder.h" #include "opentelemetry/sdk/configuration/extension_log_record_exporter_configuration.h" #include "opentelemetry/sdk/configuration/extension_log_record_processor_builder.h" @@ -50,6 +52,7 @@ #include "opentelemetry/sdk/logs/logger_config.h" #include "opentelemetry/sdk/logs/logger_provider.h" #include "opentelemetry/sdk/logs/processor.h" +#include "opentelemetry/test_common/sdk/common/scoped_test_log_handler.h" #include "config_test_logs.h" @@ -236,6 +239,28 @@ TEST_F(LogsBuildersTest, CreateSimpleLogRecordProcessor) EXPECT_NE(result, nullptr); } +// The event_to_span_event_bridge/development processor has no SDK implementation yet (see +// https://github.com/open-telemetry/opentelemetry-cpp/issues/4454): SdkBuilder should log a +// warning and skip it rather than build a processor, so a pipeline like +// [event_to_span_event_bridge, batch] just runs batch instead of failing or crashing. +TEST_F(LogsBuildersTest, CreateEventToSpanEventBridgeLogRecordProcessorWarnsAndSkips) +{ + opentelemetry::test_common::ScopedTestLogHandler log_handler{ + opentelemetry::sdk::common::internal_log::LogLevel::Warning}; + + std::unique_ptr model = + std::make_unique(); + + auto result = MakeLogRecordProcessor(std::move(model)); + + EXPECT_EQ(result, nullptr); + + auto entries = log_handler.Drain(); + ASSERT_EQ(entries.size(), 1U); + EXPECT_EQ(entries[0].level, opentelemetry::sdk::common::internal_log::LogLevel::Warning); + EXPECT_NE(entries[0].msg.find("event_to_span_event_bridge"), std::string::npos); +} + TEST_F(LogsBuildersTest, UnregisteredLoggerConfigurator) { registry_->SetLoggerConfiguratorBuilder(nullptr); diff --git a/sdk/test/configuration/yaml_logs_test.cc b/sdk/test/configuration/yaml_logs_test.cc index 462c89b39a..ca305f3901 100644 --- a/sdk/test/configuration/yaml_logs_test.cc +++ b/sdk/test/configuration/yaml_logs_test.cc @@ -15,6 +15,8 @@ #include "opentelemetry/sdk/configuration/headers_configuration.h" #include "opentelemetry/sdk/configuration/http_tls_configuration.h" #include "opentelemetry/sdk/configuration/log_record_limits_configuration.h" +#include "opentelemetry/sdk/configuration/log_record_processor_configuration.h" +#include "opentelemetry/sdk/configuration/log_record_processor_configuration_visitor.h" #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" @@ -109,6 +111,101 @@ file_format: "1.0-logs" ASSERT_NE(exporter, nullptr); } +namespace +{ + +// Records which LogRecordProcessorConfigurationVisitor callback a parsed model dispatches to. +// The bridge configuration carries no properties of its own, so there is no parsed field to +// assert on; dispatching through Accept() is what actually proves the YAML key selected the +// bridge configuration rather than falling through to the extension configuration. This also +// avoids needing RTTI. +class RecordingLogRecordProcessorVisitor final + : public opentelemetry::sdk::configuration::LogRecordProcessorConfigurationVisitor +{ +public: + void VisitBatch( + const opentelemetry::sdk::configuration::BatchLogRecordProcessorConfiguration *) override + { + ++batch_count; + } + + void VisitSimple( + const opentelemetry::sdk::configuration::SimpleLogRecordProcessorConfiguration *) override + { + ++simple_count; + } + + void VisitEventToSpanEventBridge( + const opentelemetry::sdk::configuration::EventToSpanEventBridgeLogRecordProcessorConfiguration + *) override + { + ++bridge_count; + } + + void VisitExtension( + const opentelemetry::sdk::configuration::ExtensionLogRecordProcessorConfiguration *) override + { + ++extension_count; + } + + int batch_count{0}; + int simple_count{0}; + int bridge_count{0}; + int extension_count{0}; +}; + +} // namespace + +TEST(YamlLogs, event_to_span_event_bridge_processor) +{ + std::string yaml = R"( +file_format: "1.0-logs" +logger_provider: + processors: + - event_to_span_event_bridge/development: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->logger_provider, nullptr); + ASSERT_EQ(config->logger_provider->processors.size(), 1); + auto *processor = config->logger_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + + RecordingLogRecordProcessorVisitor visitor; + processor->Accept(&visitor); + + EXPECT_EQ(visitor.bridge_count, 1); + EXPECT_EQ(visitor.extension_count, 0); + EXPECT_EQ(visitor.batch_count, 0); + EXPECT_EQ(visitor.simple_count, 0); +} + +TEST(YamlLogs, event_to_span_event_bridge_processor_misspelled_key_is_not_the_bridge) +{ + // A misspelled key falls through to the extension processor configuration. Guards against the + // bridge assertion above passing for a model that is not actually the bridge. + std::string yaml = R"( +file_format: "1.0-logs" +logger_provider: + processors: + - event_to_span_event_brige/development: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->logger_provider, nullptr); + ASSERT_EQ(config->logger_provider->processors.size(), 1); + auto *processor = config->logger_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + + RecordingLogRecordProcessorVisitor visitor; + processor->Accept(&visitor); + + EXPECT_EQ(visitor.bridge_count, 0); + EXPECT_EQ(visitor.extension_count, 1); +} + TEST(YamlLogs, default_batch_processor) { std::string yaml = R"(