diff --git a/sdk/include/opentelemetry/sdk/configuration/instrument_type.h b/sdk/include/opentelemetry/sdk/configuration/instrument_type.h index 49fd52f435..f4e5442f67 100644 --- a/sdk/include/opentelemetry/sdk/configuration/instrument_type.h +++ b/sdk/include/opentelemetry/sdk/configuration/instrument_type.h @@ -17,6 +17,7 @@ namespace configuration // YAML-NODE: InstrumentType enum class InstrumentType : std::uint8_t { + none, /* Represents a null entry */ counter, histogram, observable_counter, diff --git a/sdk/src/configuration/configuration_parser.cc b/sdk/src/configuration/configuration_parser.cc new file mode 100644 index 0000000000..000b935662 --- /dev/null +++ b/sdk/src/configuration/configuration_parser.cc @@ -0,0 +1,1775 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "opentelemetry/sdk/common/global_log_handler.h" +#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/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" +#include "opentelemetry/sdk/configuration/boolean_array_attribute_value_configuration.h" +#include "opentelemetry/sdk/configuration/boolean_attribute_value_configuration.h" +#include "opentelemetry/sdk/configuration/configuration.h" +#include "opentelemetry/sdk/configuration/configuration_parser.h" +#include "opentelemetry/sdk/configuration/console_log_record_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/console_push_metric_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/console_span_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/default_aggregation_configuration.h" +#include "opentelemetry/sdk/configuration/default_histogram_aggregation.h" +#include "opentelemetry/sdk/configuration/document.h" +#include "opentelemetry/sdk/configuration/document_node.h" +#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/explicit_bucket_histogram_aggregation_configuration.h" +#include "opentelemetry/sdk/configuration/extension_log_record_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/extension_log_record_processor_configuration.h" +#include "opentelemetry/sdk/configuration/extension_pull_metric_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/extension_push_metric_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/extension_sampler_configuration.h" +#include "opentelemetry/sdk/configuration/extension_span_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/extension_span_processor_configuration.h" +#include "opentelemetry/sdk/configuration/headers_configuration.h" +#include "opentelemetry/sdk/configuration/include_exclude_configuration.h" +#include "opentelemetry/sdk/configuration/instrument_type.h" +#include "opentelemetry/sdk/configuration/integer_array_attribute_value_configuration.h" +#include "opentelemetry/sdk/configuration/integer_attribute_value_configuration.h" +#include "opentelemetry/sdk/configuration/invalid_schema_exception.h" +#include "opentelemetry/sdk/configuration/jaeger_remote_sampler_configuration.h" +#include "opentelemetry/sdk/configuration/last_value_aggregation_configuration.h" +#include "opentelemetry/sdk/configuration/log_record_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/log_record_limits_configuration.h" +#include "opentelemetry/sdk/configuration/log_record_processor_configuration.h" +#include "opentelemetry/sdk/configuration/logger_provider_configuration.h" +#include "opentelemetry/sdk/configuration/meter_provider_configuration.h" +#include "opentelemetry/sdk/configuration/metric_reader_configuration.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" +#include "opentelemetry/sdk/configuration/otlp_grpc_log_record_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/otlp_grpc_push_metric_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/otlp_grpc_span_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/otlp_http_encoding.h" +#include "opentelemetry/sdk/configuration/otlp_http_log_record_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/otlp_http_push_metric_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/otlp_http_span_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/parent_based_sampler_configuration.h" +#include "opentelemetry/sdk/configuration/periodic_metric_reader_configuration.h" +#include "opentelemetry/sdk/configuration/prometheus_pull_metric_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/propagator_configuration.h" +#include "opentelemetry/sdk/configuration/pull_metric_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/pull_metric_reader_configuration.h" +#include "opentelemetry/sdk/configuration/push_metric_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/resource_configuration.h" +#include "opentelemetry/sdk/configuration/sampler_configuration.h" +#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/string_array_attribute_value_configuration.h" +#include "opentelemetry/sdk/configuration/string_array_configuration.h" +#include "opentelemetry/sdk/configuration/string_attribute_value_configuration.h" +#include "opentelemetry/sdk/configuration/sum_aggregation_configuration.h" +#include "opentelemetry/sdk/configuration/temporality_preference.h" +#include "opentelemetry/sdk/configuration/trace_id_ratio_based_sampler_configuration.h" +#include "opentelemetry/sdk/configuration/tracer_provider_configuration.h" +#include "opentelemetry/sdk/configuration/view_configuration.h" +#include "opentelemetry/sdk/configuration/view_selector_configuration.h" +#include "opentelemetry/sdk/configuration/view_stream_configuration.h" +#include "opentelemetry/sdk/configuration/zipkin_span_exporter_configuration.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace configuration +{ + +// FIXME: proper sizing +constexpr size_t MAX_SAMPLER_DEPTH = 10; + +static OtlpHttpEncoding ParseOtlpHttpEncoding(const std::string &name) +{ + if (name == "protobuf") + { + return OtlpHttpEncoding::protobuf; + } + + if (name == "json") + { + return OtlpHttpEncoding::json; + } + + std::string message("Illegal OtlpHttpEncoding: "); + message.append(name); + throw InvalidSchemaException(message); +} + +static std::unique_ptr ParseStringArrayConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + for (auto it = node->begin(); it != node->end(); ++it) + { + std::unique_ptr child(*it); + + std::string name = child->AsString(); + + model->string_array.push_back(name); + } + + return model; +} + +static std::unique_ptr ParseIncludeExcludeConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + child = node->GetChildNode("included"); + if (child) + { + model->included = ParseStringArrayConfiguration(child); + } + + child = node->GetChildNode("excluded"); + if (child) + { + model->excluded = ParseStringArrayConfiguration(child); + } + + return model; +} + +static std::unique_ptr ParseHeadersConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr kv_pair; + std::unique_ptr name_child; + std::unique_ptr value_child; + std::string name; + std::string value; + + for (auto it = node->begin(); it != node->end(); ++it) + { + kv_pair = *it; + + name_child = kv_pair->GetRequiredChildNode("name"); + value_child = kv_pair->GetRequiredChildNode("value"); + + name = name_child->AsString(); + value = value_child->AsString(); + + OTEL_INTERNAL_LOG_DEBUG("ParseHeadersConfiguration() name = " << name << ", value = " << value); + std::pair entry(name, value); + model->kv_map.insert(entry); + } + + return model; +} + +static std::unique_ptr ParseAttributeLimitsConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + model->attribute_value_length_limit = node->GetInteger("attribute_value_length_limit", 4096); + model->attribute_count_limit = node->GetInteger("attribute_count_limit", 128); + + return model; +} + +static std::unique_ptr +ParseOtlpHttpLogRecordExporterConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->endpoint = node->GetRequiredString("endpoint"); + model->certificate_file = node->GetString("certificate_file", ""); + model->client_key_file = node->GetString("client_key_file", ""); + model->client_certificate_file = node->GetString("client_certificate_file", ""); + + child = node->GetChildNode("headers"); + if (child) + { + model->headers = ParseHeadersConfiguration(child); + } + + model->headers_list = node->GetString("headers_list", ""); + model->compression = node->GetString("compression", ""); + model->timeout = node->GetInteger("timeout", 10000); + + std::string encoding = node->GetString("encoding", "protobuf"); + model->encoding = ParseOtlpHttpEncoding(encoding); + + return model; +} + +static std::unique_ptr +ParseOtlpGrpcLogRecordExporterConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->endpoint = node->GetRequiredString("endpoint"); + model->certificate_file = node->GetString("certificate_file", ""); + model->client_key_file = node->GetString("client_key_file", ""); + model->client_certificate_file = node->GetString("client_certificate_file", ""); + + child = node->GetChildNode("headers"); + if (child) + { + model->headers = ParseHeadersConfiguration(child); + } + + model->headers_list = node->GetString("headers_list", ""); + model->compression = node->GetString("compression", ""); + model->timeout = node->GetInteger("timeout", 10000); + model->insecure = node->GetBoolean("insecure", false); + + return model; +} + +static std::unique_ptr +ParseOtlpFileLogRecordExporterConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->output_stream = node->GetString("output_stream", ""); + + return model; +} + +static std::unique_ptr +ParseConsoleLogRecordExporterConfiguration(const std::unique_ptr & /* node */) +{ + auto model = std::make_unique(); + + return model; +} + +static std::unique_ptr +ParseExtensionLogRecordExporterConfiguration(const std::string &name, + std::unique_ptr node) +{ + auto model = std::make_unique(); + + model->name = name; + model->node = std::move(node); + + return model; +} + +static std::unique_ptr ParseLogRecordExporterConfiguration( + const std::unique_ptr &node) +{ + std::unique_ptr model; + + std::string name; + std::unique_ptr child; + size_t count = 0; + + for (auto it = node->begin_properties(); it != node->end_properties(); ++it) + { + name = it.Name(); + child = it.Value(); + count++; + } + + if (count != 1) + { + std::string message("Illegal log record exporter, count: "); + message.append(std::to_string(count)); + throw InvalidSchemaException(message); + } + + if (name == "otlp_http") + { + model = ParseOtlpHttpLogRecordExporterConfiguration(child); + } + else if (name == "otlp_grpc") + { + model = ParseOtlpGrpcLogRecordExporterConfiguration(child); + } + else if (name == "otlp_file/development") + { + model = ParseOtlpFileLogRecordExporterConfiguration(child); + } + else if (name == "console") + { + model = ParseConsoleLogRecordExporterConfiguration(child); + } + else + { + model = ParseExtensionLogRecordExporterConfiguration(name, std::move(child)); + } + + return model; +} + +static std::unique_ptr +ParseBatchLogRecordProcessorConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->schedule_delay = node->GetInteger("schedule_delay", 5000); + model->export_timeout = node->GetInteger("export_timeout", 30000); + model->max_queue_size = node->GetInteger("max_queue_size", 2048); + model->max_export_batch_size = node->GetInteger("max_export_batch_size", 512); + + child = node->GetRequiredChildNode("exporter"); + model->exporter = ParseLogRecordExporterConfiguration(child); + + return model; +} + +static std::unique_ptr +ParseSimpleLogRecordProcessorConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + child = node->GetRequiredChildNode("exporter"); + model->exporter = ParseLogRecordExporterConfiguration(child); + + return model; +} + +static std::unique_ptr +ParseExtensionLogRecordProcessorConfiguration(const std::string &name, + std::unique_ptr node) +{ + auto model = std::make_unique(); + + model->name = name; + model->node = std::move(node); + + return model; +} + +static std::unique_ptr ParseLogRecordProcessorConfiguration( + const std::unique_ptr &node) +{ + std::unique_ptr model; + + std::string name; + std::unique_ptr child; + size_t count = 0; + + for (auto it = node->begin_properties(); it != node->end_properties(); ++it) + { + name = it.Name(); + child = it.Value(); + count++; + } + + if (count != 1) + { + std::string message("Illegal log record processor, count: "); + message.append(std::to_string(count)); + throw InvalidSchemaException(message); + } + + if (name == "batch") + { + model = ParseBatchLogRecordProcessorConfiguration(child); + } + else if (name == "simple") + { + model = ParseSimpleLogRecordProcessorConfiguration(child); + } + else + { + model = ParseExtensionLogRecordProcessorConfiguration(name, std::move(child)); + } + + return model; +} + +static std::unique_ptr ParseLogRecordLimitsConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + model->attribute_value_length_limit = node->GetInteger("attribute_value_length_limit", 4096); + model->attribute_count_limit = node->GetInteger("attribute_count_limit", 128); + + return model; +} + +static std::unique_ptr ParseLoggerProviderConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + child = node->GetRequiredChildNode("processors"); + + for (auto it = child->begin(); it != child->end(); ++it) + { + model->processors.push_back(ParseLogRecordProcessorConfiguration(*it)); + } + + size_t count = model->processors.size(); + if (count == 0) + { + std::string message("Illegal logger provider, 0 processors"); + throw InvalidSchemaException(message); + } + + child = node->GetChildNode("limits"); + if (child) + { + model->limits = ParseLogRecordLimitsConfiguration(child); + } + + return model; +} + +static DefaultHistogramAggregation ParseDefaultHistogramAggregation(const std::string &name) +{ + if (name == "explicit_bucket_histogram") + { + return DefaultHistogramAggregation::explicit_bucket_histogram; + } + + if (name == "base2_exponential_bucket_histogram") + { + return DefaultHistogramAggregation::base2_exponential_bucket_histogram; + } + + std::string message("Illegal default_histogram_aggregation: "); + message.append(name); + throw InvalidSchemaException(message); +} + +static TemporalityPreference ParseTemporalityPreference(const std::string &name) +{ + if (name == "cumulative") + { + return TemporalityPreference::cumulative; + } + + if (name == "delta") + { + return TemporalityPreference::delta; + } + + if (name == "low_memory") + { + return TemporalityPreference::low_memory; + } + + std::string message("Illegal temporality preference: "); + message.append(name); + throw InvalidSchemaException(message); +} + +static std::unique_ptr +ParseOtlpHttpPushMetricExporterConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->endpoint = node->GetRequiredString("endpoint"); + model->certificate_file = node->GetString("certificate_file", ""); + model->client_key_file = node->GetString("client_key_file", ""); + model->client_certificate_file = node->GetString("client_certificate_file", ""); + + child = node->GetChildNode("headers"); + if (child) + { + model->headers = ParseHeadersConfiguration(child); + } + + model->headers_list = node->GetString("headers_list", ""); + model->compression = node->GetString("compression", ""); + model->timeout = node->GetInteger("timeout", 10000); + + std::string temporality_preference = node->GetString("temporality_preference", "cumulative"); + model->temporality_preference = ParseTemporalityPreference(temporality_preference); + + std::string default_histogram_aggregation = + node->GetString("default_histogram_aggregation", "explicit_bucket_histogram"); + model->default_histogram_aggregation = + ParseDefaultHistogramAggregation(default_histogram_aggregation); + + std::string encoding = node->GetString("encoding", "protobuf"); + model->encoding = ParseOtlpHttpEncoding(encoding); + + return model; +} + +static std::unique_ptr +ParseOtlpGrpcPushMetricExporterConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->endpoint = node->GetRequiredString("endpoint"); + model->certificate_file = node->GetString("certificate_file", ""); + model->client_key_file = node->GetString("client_key_file", ""); + model->client_certificate_file = node->GetString("client_certificate_file", ""); + + child = node->GetChildNode("headers"); + if (child) + { + model->headers = ParseHeadersConfiguration(child); + } + + model->headers_list = node->GetString("headers_list", ""); + model->compression = node->GetString("compression", ""); + model->timeout = node->GetInteger("timeout", 10000); + + std::string temporality_preference = node->GetString("temporality_preference", "cumulative"); + model->temporality_preference = ParseTemporalityPreference(temporality_preference); + + std::string default_histogram_aggregation = + node->GetString("default_histogram_aggregation", "explicit_bucket_histogram"); + model->default_histogram_aggregation = + ParseDefaultHistogramAggregation(default_histogram_aggregation); + + model->insecure = node->GetBoolean("insecure", false); + + return model; +} + +static std::unique_ptr +ParseOtlpFilePushMetricExporterConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->output_stream = node->GetString("output_stream", ""); + + std::string temporality_preference = node->GetString("temporality_preference", "cumulative"); + model->temporality_preference = ParseTemporalityPreference(temporality_preference); + + std::string default_histogram_aggregation = + node->GetString("default_histogram_aggregation", "explicit_bucket_histogram"); + model->default_histogram_aggregation = + ParseDefaultHistogramAggregation(default_histogram_aggregation); + + return model; +} + +static std::unique_ptr +ParseConsolePushMetricExporterConfiguration(const std::unique_ptr & /* node */) +{ + auto model = std::make_unique(); + + // FIXME-CONFIG: https://github.com/open-telemetry/opentelemetry-configuration/issues/242 + + return model; +} + +static std::unique_ptr +ParsePrometheusPullMetricExporterConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + model->host = node->GetString("host", "localhost"); + model->port = node->GetInteger("port", 9464); + model->without_units = node->GetBoolean("without_units", false); + model->without_type_suffix = node->GetBoolean("without_type_suffix", false); + model->without_scope_info = node->GetBoolean("without_scope_info", false); + + return model; +} + +static std::unique_ptr +ParsePushMetricExporterExtensionConfiguration(const std::string &name, + std::unique_ptr node) +{ + auto model = std::make_unique(); + + model->name = name; + model->node = std::move(node); + + return model; +} + +static std::unique_ptr +ParsePullMetricExporterExtensionConfiguration(const std::string &name, + std::unique_ptr node) +{ + auto model = std::make_unique(); + + model->name = name; + model->node = std::move(node); + + return model; +} + +static std::unique_ptr ParsePushMetricExporterConfiguration( + const std::unique_ptr &node) +{ + std::unique_ptr model; + + std::string name; + std::unique_ptr child; + size_t count = 0; + + for (auto it = node->begin_properties(); it != node->end_properties(); ++it) + { + name = it.Name(); + child = it.Value(); + count++; + } + + if (count != 1) + { + std::string message("Illegal push metric exporter, count: "); + message.append(std::to_string(count)); + throw InvalidSchemaException(message); + } + + if (name == "otlp_http") + { + model = ParseOtlpHttpPushMetricExporterConfiguration(child); + } + else if (name == "otlp_grpc") + { + model = ParseOtlpGrpcPushMetricExporterConfiguration(child); + } + else if (name == "otlp_file/development") + { + model = ParseOtlpFilePushMetricExporterConfiguration(child); + } + else if (name == "console") + { + model = ParseConsolePushMetricExporterConfiguration(child); + } + else + { + model = ParsePushMetricExporterExtensionConfiguration(name, std::move(child)); + } + + return model; +} + +static std::unique_ptr ParsePullMetricExporterConfiguration( + const std::unique_ptr &node) +{ + std::unique_ptr model; + + std::string name; + std::unique_ptr child; + size_t count = 0; + + for (auto it = node->begin_properties(); it != node->end_properties(); ++it) + { + name = it.Name(); + child = it.Value(); + count++; + } + + if (count != 1) + { + std::string message("Illegal pull metric exporter, count: "); + message.append(std::to_string(count)); + throw InvalidSchemaException(message); + } + + if (name == "prometheus") + { + model = ParsePrometheusPullMetricExporterConfiguration(child); + } + else + { + model = ParsePullMetricExporterExtensionConfiguration(name, std::move(child)); + } + + return model; +} + +static std::unique_ptr ParsePeriodicMetricReaderConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->interval = node->GetInteger("interval", 5000); + model->timeout = node->GetInteger("timeout", 30000); + + child = node->GetRequiredChildNode("exporter"); + model->exporter = ParsePushMetricExporterConfiguration(child); + + return model; +} + +static std::unique_ptr ParsePullMetricReaderConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + child = node->GetRequiredChildNode("exporter"); + model->exporter = ParsePullMetricExporterConfiguration(child); + + return model; +} + +static std::unique_ptr ParseMetricReaderConfiguration( + const std::unique_ptr &node) +{ + std::unique_ptr model; + + std::string name; + std::unique_ptr child; + size_t count = 0; + + for (auto it = node->begin_properties(); it != node->end_properties(); ++it) + { + name = it.Name(); + child = it.Value(); + count++; + } + + if (count != 1) + { + std::string message("Illegal metric reader, count: "); + message.append(std::to_string(count)); + throw InvalidSchemaException(message); + } + + if (name == "periodic") + { + model = ParsePeriodicMetricReaderConfiguration(child); + } + else if (name == "pull") + { + model = ParsePullMetricReaderConfiguration(child); + } + else + { + std::string message("Illegal metric reader: "); + message.append(name); + throw InvalidSchemaException(message); + } + + return model; +} + +static InstrumentType ParseInstrumentType(const std::string &name) +{ + if (name == "") + { + return InstrumentType::none; + } + + if (name == "counter") + { + return InstrumentType::counter; + } + + if (name == "histogram") + { + return InstrumentType::histogram; + } + + if (name == "observable_counter") + { + return InstrumentType::observable_counter; + } + + if (name == "observable_gauge") + { + return InstrumentType::observable_gauge; + } + + if (name == "observable_up_down_counter") + { + return InstrumentType::observable_up_down_counter; + } + + if (name == "up_down_counter") + { + return InstrumentType::up_down_counter; + } + + std::string message("Illegal instrument type: "); + message.append(name); + throw InvalidSchemaException(message); +} + +static std::unique_ptr ParseViewSelectorConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + model->instrument_name = node->GetString("instrument_name", ""); + + std::string instrument_type = node->GetString("instrument_type", ""); + model->instrument_type = ParseInstrumentType(instrument_type); + + model->unit = node->GetString("unit", ""); + model->meter_name = node->GetString("meter_name", ""); + model->meter_version = node->GetString("meter_version", ""); + model->meter_schema_url = node->GetString("meter_schema_url", ""); + + return model; +} + +static std::unique_ptr ParseDefaultAggregationConfiguration( + const std::unique_ptr & /* node */) +{ + auto model = std::make_unique(); + + return model; +} + +static std::unique_ptr ParseDropAggregationConfiguration( + const std::unique_ptr & /* node */) +{ + auto model = std::make_unique(); + + return model; +} + +static std::unique_ptr +ParseExplicitBucketHistogramAggregationConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + child = node->GetChildNode("boundaries"); + + if (child) + { + for (auto it = child->begin(); it != child->end(); ++it) + { + std::unique_ptr attribute_key(*it); + + double boundary = attribute_key->AsDouble(); + + model->boundaries.push_back(boundary); + } + } + + model->record_min_max = node->GetBoolean("record_min_max", true); + + return model; +} + +static std::unique_ptr +ParseBase2ExponentialBucketHistogramAggregationConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + model->max_scale = node->GetInteger("max_scale", 20); + model->max_size = node->GetInteger("max_size", 160); + model->record_min_max = node->GetBoolean("record_min_max", true); + + return model; +} + +static std::unique_ptr ParseLastValueAggregationConfiguration( + const std::unique_ptr & /* node */) +{ + auto model = std::make_unique(); + + return model; +} + +static std::unique_ptr ParseSumAggregationConfiguration( + const std::unique_ptr & /* node */) +{ + auto model = std::make_unique(); + + return model; +} + +static std::unique_ptr ParseAggregationConfiguration( + const std::unique_ptr &node) +{ + std::unique_ptr model; + std::unique_ptr child; + + size_t count = node->num_children(); + + if (count != 1) + { + std::string message("Illegal aggregation, children: "); + message.append(std::to_string(count)); + throw InvalidSchemaException(message); + } + + child = node->GetChild(0); + std::string name = child->Key(); + + if (name == "default") + { + model = ParseDefaultAggregationConfiguration(child); + } + else if (name == "drop") + { + model = ParseDropAggregationConfiguration(child); + } + else if (name == "explicit_bucket_histogram") + { + model = ParseExplicitBucketHistogramAggregationConfiguration(child); + } + else if (name == "base2_exponential_bucket_histogram") + { + model = ParseBase2ExponentialBucketHistogramAggregationConfiguration(child); + } + else if (name == "last_value") + { + model = ParseLastValueAggregationConfiguration(child); + } + else if (name == "sum") + { + model = ParseSumAggregationConfiguration(child); + } + else + { + std::string message("Illegal aggregation: "); + message.append(name); + throw InvalidSchemaException(message); + } + + return model; +} + +static std::unique_ptr ParseViewStreamConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->name = node->GetString("name", ""); + model->description = node->GetString("description", ""); + model->aggregation_cardinality_limit = node->GetInteger("aggregation_cardinality_limit", 0); + + child = node->GetChildNode("aggregation"); + if (child) + { + model->aggregation = ParseAggregationConfiguration(child); + } + + child = node->GetChildNode("attribute_keys"); + if (child) + { + model->attribute_keys = ParseIncludeExcludeConfiguration(child); + } + + return model; +} + +static std::unique_ptr ParseViewConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + child = node->GetRequiredChildNode("selector"); + model->selector = ParseViewSelectorConfiguration(child); + + child = node->GetRequiredChildNode("stream"); + model->stream = ParseViewStreamConfiguration(child); + + return model; +} + +static std::unique_ptr ParseMeterProviderConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + child = node->GetRequiredChildNode("readers"); + + for (auto it = child->begin(); it != child->end(); ++it) + { + model->readers.push_back(ParseMetricReaderConfiguration(*it)); + } + + if (model->readers.size() == 0) + { + std::string message("Illegal meter provider, 0 readers"); + throw InvalidSchemaException(message); + } + + child = node->GetChildNode("views"); + + if (child != nullptr) + { + for (auto it = child->begin(); it != child->end(); ++it) + { + model->views.push_back(ParseViewConfiguration(*it)); + } + } + + return model; +} + +static std::unique_ptr ParsePropagatorConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + std::unique_ptr child; + child = node->GetRequiredChildNode("composite"); + + for (auto it = child->begin(); it != child->end(); ++it) + { + std::unique_ptr element(*it); + + std::string name = element->AsString(); + + model->composite.push_back(name); + } + + return model; +} + +static std::unique_ptr ParseSpanLimitsConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + model->attribute_value_length_limit = node->GetInteger("attribute_value_length_limit", 4096); + model->attribute_count_limit = node->GetInteger("attribute_count_limit", 128); + model->event_count_limit = node->GetInteger("event_count_limit", 128); + model->link_count_limit = node->GetInteger("link_count_limit", 128); + model->event_attribute_count_limit = node->GetInteger("event_attribute_count_limit", 128); + model->link_attribute_count_limit = node->GetInteger("link_attribute_count_limit", 128); + + return model; +} + +static std::unique_ptr ParseSamplerConfiguration( + const std::unique_ptr &node, + size_t depth); + +static std::unique_ptr ParseAlwaysOffSamplerConfiguration( + const std::unique_ptr & /* node */, + size_t /* depth */) +{ + auto model = std::make_unique(); + + return model; +} + +static std::unique_ptr ParseAlwaysOnSamplerConfiguration( + const std::unique_ptr & /* node */, + size_t /* depth */) +{ + auto model = std::make_unique(); + + return model; +} + +// NOLINTBEGIN(misc-no-recursion) +static std::unique_ptr ParseJaegerRemoteSamplerConfiguration( + const std::unique_ptr &node, + size_t depth) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + // Unclear if endpoint and interval are required/optional + // FIXME-CONFIG: https://github.com/open-telemetry/opentelemetry-configuration/issues/238 + OTEL_INTERNAL_LOG_ERROR("JaegerRemoteSamplerConfiguration: FIXME"); + + model->endpoint = node->GetString("endpoint", "FIXME"); + model->interval = node->GetInteger("interval", 0); + + child = node->GetChildNode("initial_sampler"); + if (child) + { + model->initial_sampler = ParseSamplerConfiguration(child, depth + 1); + } + + return model; +} +// NOLINTEND(misc-no-recursion) + +// NOLINTBEGIN(misc-no-recursion) +static std::unique_ptr ParseParentBasedSamplerConfiguration( + const std::unique_ptr &node, + size_t depth) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + child = node->GetChildNode("root"); + if (child) + { + model->root = ParseSamplerConfiguration(child, depth + 1); + } + + child = node->GetChildNode("remote_parent_sampled"); + if (child) + { + model->remote_parent_sampled = ParseSamplerConfiguration(child, depth + 1); + } + + child = node->GetChildNode("remote_parent_not_sampled"); + if (child) + { + model->remote_parent_not_sampled = ParseSamplerConfiguration(child, depth + 1); + } + + child = node->GetChildNode("local_parent_sampled"); + if (child) + { + model->local_parent_sampled = ParseSamplerConfiguration(child, depth + 1); + } + + child = node->GetChildNode("local_parent_not_sampled"); + if (child) + { + model->local_parent_not_sampled = ParseSamplerConfiguration(child, depth + 1); + } + + return model; +} +// NOLINTEND(misc-no-recursion) + +static std::unique_ptr +ParseTraceIdRatioBasedSamplerConfiguration(const std::unique_ptr &node, + size_t /* depth */) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->ratio = node->GetDouble("ratio", 0); + + return model; +} + +static std::unique_ptr ParseSamplerExtensionConfiguration( + const std::string &name, + std::unique_ptr node, + size_t depth) +{ + auto model = std::make_unique(); + + model->name = name; + model->node = std::move(node); + model->depth = depth; + + return model; +} + +// NOLINTBEGIN(misc-no-recursion) +static std::unique_ptr ParseSamplerConfiguration( + const std::unique_ptr &node, + size_t depth) +{ + /* + * ParseSamplerConfiguration() is recursive, + * enforce a limit to prevent attacks from yaml. + */ + if (depth >= MAX_SAMPLER_DEPTH) + { + std::string message("Samplers nested too deeply: "); + message.append(std::to_string(depth)); + throw InvalidSchemaException(message); + } + + std::unique_ptr model; + + std::string name; + std::unique_ptr child; + size_t count = 0; + + for (auto it = node->begin_properties(); it != node->end_properties(); ++it) + { + name = it.Name(); + child = it.Value(); + count++; + } + + if (count != 1) + { + std::string message("Illegal sampler, properties count: "); + message.append(std::to_string(count)); + throw InvalidSchemaException(message); + } + + if (name == "always_off") + { + model = ParseAlwaysOffSamplerConfiguration(child, depth); + } + else if (name == "always_on") + { + model = ParseAlwaysOnSamplerConfiguration(child, depth); + } + else if (name == "jaeger_remote") + { + model = ParseJaegerRemoteSamplerConfiguration(child, depth); + } + else if (name == "parent_based") + { + model = ParseParentBasedSamplerConfiguration(child, depth); + } + else if (name == "trace_id_ratio_based") + { + model = ParseTraceIdRatioBasedSamplerConfiguration(child, depth); + } + else + { + model = ParseSamplerExtensionConfiguration(name, std::move(child), depth); + } + + return model; +} +// NOLINTEND(misc-no-recursion) + +static std::unique_ptr ParseOtlpHttpSpanExporterConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->endpoint = node->GetRequiredString("endpoint"); + model->certificate_file = node->GetString("certificate_file", ""); + model->client_key_file = node->GetString("client_key_file", ""); + model->client_certificate_file = node->GetString("client_certificate_file", ""); + + child = node->GetChildNode("headers"); + if (child) + { + model->headers = ParseHeadersConfiguration(child); + } + + model->headers_list = node->GetString("headers_list", ""); + model->compression = node->GetString("compression", ""); + model->timeout = node->GetInteger("timeout", 10000); + + std::string encoding = node->GetString("encoding", "protobuf"); + model->encoding = ParseOtlpHttpEncoding(encoding); + + return model; +} + +static std::unique_ptr ParseOtlpGrpcSpanExporterConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->endpoint = node->GetRequiredString("endpoint"); + model->certificate_file = node->GetString("certificate_file", ""); + model->client_key_file = node->GetString("client_key_file", ""); + model->client_certificate_file = node->GetString("client_certificate_file", ""); + + child = node->GetChildNode("headers"); + if (child) + { + model->headers = ParseHeadersConfiguration(child); + } + + model->headers_list = node->GetString("headers_list", ""); + model->compression = node->GetString("compression", ""); + model->timeout = node->GetInteger("timeout", 10000); + model->insecure = node->GetBoolean("insecure", false); + + return model; +} + +static std::unique_ptr ParseOtlpFileSpanExporterConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->output_stream = node->GetString("output_stream", ""); + + return model; +} + +static std::unique_ptr ParseConsoleSpanExporterConfiguration( + const std::unique_ptr & /* node */) +{ + auto model = std::make_unique(); + + return model; +} + +static std::unique_ptr ParseZipkinSpanExporterConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + model->endpoint = node->GetRequiredString("endpoint"); + model->timeout = node->GetInteger("timeout", 10000); + + return model; +} + +static std::unique_ptr ParseExtensionSpanExporterConfiguration( + const std::string &name, + std::unique_ptr node) +{ + auto model = std::make_unique(); + + model->name = name; + model->node = std::move(node); + + return model; +} + +static std::unique_ptr ParseSpanExporterConfiguration( + const std::unique_ptr &node) +{ + std::unique_ptr model; + + std::string name; + std::unique_ptr child; + size_t count = 0; + + for (auto it = node->begin_properties(); it != node->end_properties(); ++it) + { + name = it.Name(); + child = it.Value(); + count++; + } + + if (count != 1) + { + std::string message("Illegal span exporter, properties count: "); + message.append(std::to_string(count)); + throw InvalidSchemaException(message); + } + + if (name == "otlp_http") + { + model = ParseOtlpHttpSpanExporterConfiguration(child); + } + else if (name == "otlp_grpc") + { + model = ParseOtlpGrpcSpanExporterConfiguration(child); + } + else if (name == "otlp_file/development") + { + model = ParseOtlpFileSpanExporterConfiguration(child); + } + else if (name == "console") + { + model = ParseConsoleSpanExporterConfiguration(child); + } + else if (name == "zipkin") + { + model = ParseZipkinSpanExporterConfiguration(child); + } + else + { + model = ParseExtensionSpanExporterConfiguration(name, std::move(child)); + } + + return model; +} + +static std::unique_ptr ParseBatchSpanProcessorConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->schedule_delay = node->GetInteger("schedule_delay", 5000); + model->export_timeout = node->GetInteger("export_timeout", 30000); + model->max_queue_size = node->GetInteger("max_queue_size", 2048); + model->max_export_batch_size = node->GetInteger("max_export_batch_size", 512); + + child = node->GetRequiredChildNode("exporter"); + model->exporter = ParseSpanExporterConfiguration(child); + + return model; +} + +static std::unique_ptr ParseSimpleSpanProcessorConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + child = node->GetRequiredChildNode("exporter"); + model->exporter = ParseSpanExporterConfiguration(child); + + return model; +} + +static std::unique_ptr +ParseExtensionSpanProcessorConfiguration(const std::string &name, + std::unique_ptr node) +{ + auto model = std::make_unique(); + + model->name = name; + model->node = std::move(node); + + return model; +} + +static std::unique_ptr ParseSpanProcessorConfiguration( + const std::unique_ptr &node) +{ + std::unique_ptr model; + + std::string name; + std::unique_ptr child; + size_t count = 0; + + for (auto it = node->begin_properties(); it != node->end_properties(); ++it) + { + name = it.Name(); + child = it.Value(); + count++; + } + + if (count != 1) + { + std::string message("Illegal span processor, properties count: "); + message.append(std::to_string(count)); + throw InvalidSchemaException(message); + } + + if (name == "batch") + { + model = ParseBatchSpanProcessorConfiguration(child); + } + else if (name == "simple") + { + model = ParseSimpleSpanProcessorConfiguration(child); + } + else + { + model = ParseExtensionSpanProcessorConfiguration(name, std::move(child)); + } + + return model; +} + +static std::unique_ptr ParseTracerProviderConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + child = node->GetRequiredChildNode("processors"); + + for (auto it = child->begin(); it != child->end(); ++it) + { + model->processors.push_back(ParseSpanProcessorConfiguration(*it)); + } + + size_t count = model->processors.size(); + if (count == 0) + { + std::string message("Illegal tracer provider, 0 processors"); + throw InvalidSchemaException(message); + } + + child = node->GetChildNode("limits"); + if (child) + { + model->limits = ParseSpanLimitsConfiguration(child); + } + + child = node->GetChildNode("sampler"); + if (child) + { + model->sampler = ParseSamplerConfiguration(child, 0); + } + + return model; +} + +static std::unique_ptr ParseStringAttributeValueConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + model->value = node->AsString(); + + return model; +} + +static std::unique_ptr ParseIntegerAttributeValueConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + model->value = node->AsInteger(); + + return model; +} + +static std::unique_ptr ParseDoubleAttributeValueConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + model->value = node->AsDouble(); + + return model; +} + +static std::unique_ptr ParseBooleanAttributeValueConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + model->value = node->AsBoolean(); + + return model; +} + +static std::unique_ptr +ParseStringArrayAttributeValueConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + for (auto it = node->begin(); it != node->end(); ++it) + { + std::unique_ptr child(*it); + + std::string value = child->AsString(); + + model->value.push_back(value); + } + + return model; +} + +static std::unique_ptr +ParseIntegerArrayAttributeValueConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + for (auto it = node->begin(); it != node->end(); ++it) + { + std::unique_ptr child(*it); + + std::size_t value = child->AsInteger(); + + model->value.push_back(value); + } + + return model; +} + +static std::unique_ptr +ParseDoubleArrayAttributeValueConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + for (auto it = node->begin(); it != node->end(); ++it) + { + std::unique_ptr child(*it); + + double value = child->AsDouble(); + + model->value.push_back(value); + } + + return model; +} + +static std::unique_ptr +ParseBooleanArrayAttributeValueConfiguration(const std::unique_ptr &node) +{ + auto model = std::make_unique(); + + for (auto it = node->begin(); it != node->end(); ++it) + { + std::unique_ptr child(*it); + + bool value = child->AsBoolean(); + + model->value.push_back(value); + } + + return model; +} + +static std::unique_ptr ParseAttributesConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + std::unique_ptr attribute_name_value; + std::unique_ptr name_child; + std::unique_ptr value_child; + std::unique_ptr type_child; + std::string name; + std::string type; + + for (auto it = node->begin(); it != node->end(); ++it) + { + attribute_name_value = *it; + + name_child = attribute_name_value->GetRequiredChildNode("name"); + value_child = attribute_name_value->GetRequiredChildNode("value"); + type_child = attribute_name_value->GetChildNode("type"); + + std::unique_ptr value_model; + + name = name_child->AsString(); + if (type_child) + { + type = type_child->AsString(); + } + else + { + type = "string"; + } + + if (type == "string") + { + auto model_detail = ParseStringAttributeValueConfiguration(value_child); + value_model = std::move(model_detail); + } + else if (type == "bool") + { + auto model_detail = ParseBooleanAttributeValueConfiguration(value_child); + value_model = std::move(model_detail); + } + else if (type == "int") + { + auto model_detail = ParseIntegerAttributeValueConfiguration(value_child); + value_model = std::move(model_detail); + } + else if (type == "double") + { + auto model_detail = ParseDoubleAttributeValueConfiguration(value_child); + value_model = std::move(model_detail); + } + else if (type == "string_array") + { + auto model_detail = ParseStringArrayAttributeValueConfiguration(value_child); + value_model = std::move(model_detail); + } + else if (type == "bool_array") + { + auto model_detail = ParseBooleanArrayAttributeValueConfiguration(value_child); + value_model = std::move(model_detail); + } + else if (type == "int_array") + { + auto model_detail = ParseIntegerArrayAttributeValueConfiguration(value_child); + value_model = std::move(model_detail); + } + else if (type == "double_array") + { + auto model_detail = ParseDoubleArrayAttributeValueConfiguration(value_child); + value_model = std::move(model_detail); + } + else + { + std::string message("Illegal attribute type: "); + message.append(type); + throw InvalidSchemaException(message); + } + + std::pair> entry( + name, std::move(value_model)); + model->kv_map.insert(std::move(entry)); + } + + return model; +} + +static std::unique_ptr ParseResourceConfiguration( + const std::unique_ptr &node) +{ + auto model = std::make_unique(); + std::unique_ptr child; + + model->schema_url = node->GetString("schema_url", ""); + model->attributes_list = node->GetString("attributes_list", ""); + + child = node->GetChildNode("attributes"); + if (child) + { + model->attributes = ParseAttributesConfiguration(child); + } + + child = node->GetChildNode("detectors"); + if (child) + { + model->detectors = ParseIncludeExcludeConfiguration(child); + } + + return model; +} + +std::unique_ptr ConfigurationParser::Parse(std::unique_ptr doc) +{ + std::unique_ptr node = doc->GetRootNode(); + + auto model = std::make_unique(std::move(doc)); + + model->file_format = node->GetRequiredString("file_format"); + model->disabled = node->GetBoolean("disabled", false); + + std::unique_ptr child; + + child = node->GetChildNode("attribute_limits"); + if (child) + { + model->attribute_limits = ParseAttributeLimitsConfiguration(child); + } + + child = node->GetChildNode("logger_provider"); + if (child) + { + model->logger_provider = ParseLoggerProviderConfiguration(child); + } + + child = node->GetChildNode("meter_provider"); + if (child) + { + model->meter_provider = ParseMeterProviderConfiguration(child); + } + + child = node->GetChildNode("propagator"); + if (child) + { + model->propagator = ParsePropagatorConfiguration(child); + } + + child = node->GetChildNode("tracer_provider"); + if (child) + { + model->tracer_provider = ParseTracerProviderConfiguration(child); + } + + child = node->GetChildNode("resource"); + if (child) + { + model->resource = ParseResourceConfiguration(child); + } + + return model; +} + +} // namespace configuration +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/test/configuration/yaml_logs_test.cc b/sdk/test/configuration/yaml_logs_test.cc new file mode 100644 index 0000000000..b38c7c58ed --- /dev/null +++ b/sdk/test/configuration/yaml_logs_test.cc @@ -0,0 +1,483 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include +#include + +#include "opentelemetry/sdk/configuration/batch_log_record_processor_configuration.h" +#include "opentelemetry/sdk/configuration/configuration.h" +#include "opentelemetry/sdk/configuration/headers_configuration.h" +#include "opentelemetry/sdk/configuration/log_record_limits_configuration.h" +#include "opentelemetry/sdk/configuration/log_record_processor_configuration.h" +#include "opentelemetry/sdk/configuration/logger_provider_configuration.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" +#include "opentelemetry/sdk/configuration/otlp_http_log_record_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/simple_log_record_processor_configuration.h" +#include "opentelemetry/sdk/configuration/yaml_configuration_parser.h" + +static std::unique_ptr DoParse( + const std::string &yaml) +{ + static const std::string source("test"); + return opentelemetry::sdk::configuration::YamlConfigurationParser::ParseString(source, yaml); +} + +TEST(YamlLogs, no_processors) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(YamlLogs, empty_processors) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(YamlLogs, many_processors) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - simple: + exporter: + console: + - simple: + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->logger_provider, nullptr); + ASSERT_EQ(config->logger_provider->processors.size(), 2); +} + +TEST(YamlLogs, simple_processor) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - simple: + exporter: + console: +)"; + + 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); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); +} + +TEST(YamlLogs, default_batch_processor) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - batch: + exporter: + console: +)"; + + 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); + auto *batch = + reinterpret_cast( + processor); + ASSERT_EQ(batch->schedule_delay, 5000); + ASSERT_EQ(batch->export_timeout, 30000); + ASSERT_EQ(batch->max_queue_size, 2048); + ASSERT_EQ(batch->max_export_batch_size, 512); + ASSERT_NE(batch->exporter, nullptr); + auto *exporter = batch->exporter.get(); + ASSERT_NE(exporter, nullptr); +} + +TEST(YamlLogs, batch_processor) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - batch: + schedule_delay: 5555 + export_timeout: 33333 + max_queue_size: 1234 + max_export_batch_size: 256 + exporter: + console: +)"; + + 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); + auto *batch = + reinterpret_cast( + processor); + ASSERT_EQ(batch->schedule_delay, 5555); + ASSERT_EQ(batch->export_timeout, 33333); + ASSERT_EQ(batch->max_queue_size, 1234); + ASSERT_EQ(batch->max_export_batch_size, 256); + ASSERT_NE(batch->exporter, nullptr); + auto *exporter = batch->exporter.get(); + ASSERT_NE(exporter, nullptr); +} + +TEST(YamlLogs, default_otlp_http) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - simple: + exporter: + otlp_http: + endpoint: "somewhere" +)"; + + 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); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_http = + reinterpret_cast( + exporter); + ASSERT_EQ(otlp_http->endpoint, "somewhere"); + ASSERT_EQ(otlp_http->certificate_file, ""); + ASSERT_EQ(otlp_http->client_key_file, ""); + ASSERT_EQ(otlp_http->client_certificate_file, ""); + ASSERT_EQ(otlp_http->headers, nullptr); + ASSERT_EQ(otlp_http->headers_list, ""); + ASSERT_EQ(otlp_http->compression, ""); + ASSERT_EQ(otlp_http->timeout, 10000); + ASSERT_EQ(otlp_http->encoding, opentelemetry::sdk::configuration::OtlpHttpEncoding::protobuf); +} + +TEST(YamlLogs, otlp_http) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - simple: + exporter: + otlp_http: + endpoint: "somewhere" + certificate_file: "certificate_file" + client_key_file: "client_key_file" + client_certificate_file: "client_certificate_file" + headers: + - name: foo + value: "123" + - name: bar + value: "456" + headers_list: "baz=789" + compression: "compression" + timeout: 5000 + encoding: json +)"; + + 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); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_http = + reinterpret_cast( + exporter); + ASSERT_EQ(otlp_http->endpoint, "somewhere"); + ASSERT_EQ(otlp_http->certificate_file, "certificate_file"); + ASSERT_EQ(otlp_http->client_key_file, "client_key_file"); + ASSERT_EQ(otlp_http->client_certificate_file, "client_certificate_file"); + ASSERT_NE(otlp_http->headers, nullptr); + ASSERT_EQ(otlp_http->headers->kv_map.size(), 2); + ASSERT_EQ(otlp_http->headers->kv_map["foo"], "123"); + ASSERT_EQ(otlp_http->headers->kv_map["bar"], "456"); + ASSERT_EQ(otlp_http->headers_list, "baz=789"); + ASSERT_EQ(otlp_http->compression, "compression"); + ASSERT_EQ(otlp_http->timeout, 5000); + ASSERT_EQ(otlp_http->encoding, opentelemetry::sdk::configuration::OtlpHttpEncoding::json); +} + +TEST(YamlLogs, default_otlp_grpc) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - simple: + exporter: + otlp_grpc: + endpoint: "somewhere" +)"; + + 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); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_grpc = + reinterpret_cast( + exporter); + ASSERT_EQ(otlp_grpc->endpoint, "somewhere"); + ASSERT_EQ(otlp_grpc->certificate_file, ""); + ASSERT_EQ(otlp_grpc->client_key_file, ""); + ASSERT_EQ(otlp_grpc->client_certificate_file, ""); + ASSERT_EQ(otlp_grpc->headers, nullptr); + ASSERT_EQ(otlp_grpc->headers_list, ""); + ASSERT_EQ(otlp_grpc->compression, ""); + ASSERT_EQ(otlp_grpc->timeout, 10000); + ASSERT_EQ(otlp_grpc->insecure, false); +} + +TEST(YamlLogs, otlp_grpc) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - simple: + exporter: + otlp_grpc: + endpoint: "somewhere" + certificate_file: "certificate_file" + client_key_file: "client_key_file" + client_certificate_file: "client_certificate_file" + headers: + - name: foo + value: "123" + - name: bar + value: "456" + headers_list: "baz=789" + compression: "compression" + timeout: 5000 + insecure: true +)"; + + 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); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_grpc = + reinterpret_cast( + exporter); + ASSERT_EQ(otlp_grpc->endpoint, "somewhere"); + ASSERT_EQ(otlp_grpc->certificate_file, "certificate_file"); + ASSERT_EQ(otlp_grpc->client_key_file, "client_key_file"); + ASSERT_EQ(otlp_grpc->client_certificate_file, "client_certificate_file"); + ASSERT_NE(otlp_grpc->headers, nullptr); + ASSERT_EQ(otlp_grpc->headers->kv_map.size(), 2); + ASSERT_EQ(otlp_grpc->headers->kv_map["foo"], "123"); + ASSERT_EQ(otlp_grpc->headers->kv_map["bar"], "456"); + ASSERT_EQ(otlp_grpc->headers_list, "baz=789"); + ASSERT_EQ(otlp_grpc->compression, "compression"); + ASSERT_EQ(otlp_grpc->timeout, 5000); + ASSERT_EQ(otlp_grpc->insecure, true); +} + +TEST(YamlLogs, default_otlp_file) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - simple: + exporter: + otlp_file/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); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_file = + reinterpret_cast( + exporter); + ASSERT_EQ(otlp_file->output_stream, ""); +} + +TEST(YamlLogs, otlp_file) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - simple: + exporter: + otlp_file/development: + output_stream: "somewhere" +)"; + + 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); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_file = + reinterpret_cast( + exporter); + ASSERT_EQ(otlp_file->output_stream, "somewhere"); +} + +TEST(YamlLogs, otlp_console) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - simple: + exporter: + console: +)"; + + 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); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); +} + +TEST(YamlLogs, no_limits) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - simple: + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->logger_provider, nullptr); + ASSERT_EQ(config->logger_provider->limits, nullptr); +} + +TEST(YamlLogs, default_limits) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - simple: + exporter: + console: + limits: +)"; + + auto config = DoParse(yaml); + 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, 4096); + ASSERT_EQ(config->logger_provider->limits->attribute_count_limit, 128); +} + +TEST(YamlLogs, limits) +{ + std::string yaml = R"( +file_format: xx.yy +logger_provider: + processors: + - simple: + exporter: + console: + limits: + attribute_value_length_limit: 1111 + attribute_count_limit: 2222 +)"; + + auto config = DoParse(yaml); + 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); +} diff --git a/sdk/test/configuration/yaml_metrics_test.cc b/sdk/test/configuration/yaml_metrics_test.cc new file mode 100644 index 0000000000..8f963f293e --- /dev/null +++ b/sdk/test/configuration/yaml_metrics_test.cc @@ -0,0 +1,946 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include +#include + +#include "opentelemetry/sdk/configuration/base2_exponential_bucket_histogram_aggregation_configuration.h" +#include "opentelemetry/sdk/configuration/configuration.h" +#include "opentelemetry/sdk/configuration/default_histogram_aggregation.h" +#include "opentelemetry/sdk/configuration/explicit_bucket_histogram_aggregation_configuration.h" +#include "opentelemetry/sdk/configuration/headers_configuration.h" +#include "opentelemetry/sdk/configuration/include_exclude_configuration.h" +#include "opentelemetry/sdk/configuration/instrument_type.h" +#include "opentelemetry/sdk/configuration/meter_provider_configuration.h" +#include "opentelemetry/sdk/configuration/metric_reader_configuration.h" +#include "opentelemetry/sdk/configuration/otlp_file_push_metric_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/otlp_grpc_push_metric_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/otlp_http_encoding.h" +#include "opentelemetry/sdk/configuration/otlp_http_push_metric_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/periodic_metric_reader_configuration.h" +#include "opentelemetry/sdk/configuration/prometheus_pull_metric_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/pull_metric_reader_configuration.h" +#include "opentelemetry/sdk/configuration/string_array_configuration.h" +#include "opentelemetry/sdk/configuration/temporality_preference.h" +#include "opentelemetry/sdk/configuration/view_configuration.h" +#include "opentelemetry/sdk/configuration/view_selector_configuration.h" +#include "opentelemetry/sdk/configuration/view_stream_configuration.h" +#include "opentelemetry/sdk/configuration/yaml_configuration_parser.h" + +static std::unique_ptr DoParse( + const std::string &yaml) +{ + static const std::string source("test"); + return opentelemetry::sdk::configuration::YamlConfigurationParser::ParseString(source, yaml); +} + +TEST(YamlMetrics, no_readers) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(YamlMetrics, empty_readers) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(YamlMetrics, many_readers) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + - periodic: + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 2); +} + +TEST(YamlMetrics, default_periodic_reader) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *periodic = + reinterpret_cast( + reader); + ASSERT_EQ(periodic->interval, 5000); + ASSERT_EQ(periodic->timeout, 30000); + ASSERT_NE(periodic->exporter, nullptr); + auto *exporter = periodic->exporter.get(); + ASSERT_NE(exporter, nullptr); +} + +TEST(YamlMetrics, periodic_reader) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + interval: 2500 + timeout: 15000 + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *periodic = + reinterpret_cast( + reader); + ASSERT_EQ(periodic->interval, 2500); + ASSERT_EQ(periodic->timeout, 15000); + ASSERT_NE(periodic->exporter, nullptr); + auto *exporter = periodic->exporter.get(); + ASSERT_NE(exporter, nullptr); +} + +TEST(YamlMetrics, pull_reader) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - pull: + exporter: + prometheus: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *pull = + reinterpret_cast(reader); + ASSERT_NE(pull->exporter, nullptr); + auto *exporter = pull->exporter.get(); + ASSERT_NE(exporter, nullptr); +} + +TEST(YamlMetrics, default_otlp_http) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + otlp_http: + endpoint: "somewhere" +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *periodic = + reinterpret_cast( + reader); + ASSERT_NE(periodic->exporter, nullptr); + auto *exporter = periodic->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_http = reinterpret_cast< + opentelemetry::sdk::configuration::OtlpHttpPushMetricExporterConfiguration *>(exporter); + ASSERT_EQ(otlp_http->endpoint, "somewhere"); + ASSERT_EQ(otlp_http->certificate_file, ""); + ASSERT_EQ(otlp_http->client_key_file, ""); + ASSERT_EQ(otlp_http->client_certificate_file, ""); + ASSERT_EQ(otlp_http->headers, nullptr); + ASSERT_EQ(otlp_http->headers_list, ""); + ASSERT_EQ(otlp_http->compression, ""); + ASSERT_EQ(otlp_http->timeout, 10000); + ASSERT_EQ(otlp_http->temporality_preference, + opentelemetry::sdk::configuration::TemporalityPreference::cumulative); + ASSERT_EQ( + otlp_http->default_histogram_aggregation, + opentelemetry::sdk::configuration::DefaultHistogramAggregation::explicit_bucket_histogram); + ASSERT_EQ(otlp_http->encoding, opentelemetry::sdk::configuration::OtlpHttpEncoding::protobuf); +} + +TEST(YamlMetrics, otlp_http) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + otlp_http: + endpoint: "somewhere" + certificate_file: "certificate_file" + client_key_file: "client_key_file" + client_certificate_file: "client_certificate_file" + headers: + - name: foo + value: "123" + - name: bar + value: "456" + headers_list: "baz=789" + compression: "compression" + timeout: 5000 + temporality_preference: delta + default_histogram_aggregation: base2_exponential_bucket_histogram + encoding: json +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *periodic = + reinterpret_cast( + reader); + ASSERT_NE(periodic->exporter, nullptr); + auto *exporter = periodic->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_http = reinterpret_cast< + opentelemetry::sdk::configuration::OtlpHttpPushMetricExporterConfiguration *>(exporter); + ASSERT_EQ(otlp_http->endpoint, "somewhere"); + ASSERT_EQ(otlp_http->certificate_file, "certificate_file"); + ASSERT_EQ(otlp_http->client_key_file, "client_key_file"); + ASSERT_EQ(otlp_http->client_certificate_file, "client_certificate_file"); + ASSERT_NE(otlp_http->headers, nullptr); + ASSERT_EQ(otlp_http->headers->kv_map.size(), 2); + ASSERT_EQ(otlp_http->headers->kv_map["foo"], "123"); + ASSERT_EQ(otlp_http->headers->kv_map["bar"], "456"); + ASSERT_EQ(otlp_http->headers_list, "baz=789"); + ASSERT_EQ(otlp_http->compression, "compression"); + ASSERT_EQ(otlp_http->timeout, 5000); + ASSERT_EQ(otlp_http->temporality_preference, + opentelemetry::sdk::configuration::TemporalityPreference::delta); + ASSERT_EQ(otlp_http->default_histogram_aggregation, + opentelemetry::sdk::configuration::DefaultHistogramAggregation:: + base2_exponential_bucket_histogram); + ASSERT_EQ(otlp_http->encoding, opentelemetry::sdk::configuration::OtlpHttpEncoding::json); +} + +TEST(YamlMetrics, default_otlp_grpc) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + otlp_grpc: + endpoint: "somewhere" +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *periodic = + reinterpret_cast( + reader); + ASSERT_NE(periodic->exporter, nullptr); + auto *exporter = periodic->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_grpc = reinterpret_cast< + opentelemetry::sdk::configuration::OtlpGrpcPushMetricExporterConfiguration *>(exporter); + ASSERT_EQ(otlp_grpc->endpoint, "somewhere"); + ASSERT_EQ(otlp_grpc->certificate_file, ""); + ASSERT_EQ(otlp_grpc->client_key_file, ""); + ASSERT_EQ(otlp_grpc->client_certificate_file, ""); + ASSERT_EQ(otlp_grpc->headers, nullptr); + ASSERT_EQ(otlp_grpc->headers_list, ""); + ASSERT_EQ(otlp_grpc->compression, ""); + ASSERT_EQ(otlp_grpc->timeout, 10000); + ASSERT_EQ(otlp_grpc->temporality_preference, + opentelemetry::sdk::configuration::TemporalityPreference::cumulative); + ASSERT_EQ( + otlp_grpc->default_histogram_aggregation, + opentelemetry::sdk::configuration::DefaultHistogramAggregation::explicit_bucket_histogram); + ASSERT_EQ(otlp_grpc->insecure, false); +} + +TEST(YamlMetrics, otlp_grpc) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + otlp_grpc: + endpoint: "somewhere" + certificate_file: "certificate_file" + client_key_file: "client_key_file" + client_certificate_file: "client_certificate_file" + headers: + - name: foo + value: "123" + - name: bar + value: "456" + headers_list: "baz=789" + compression: "compression" + timeout: 5000 + temporality_preference: delta + default_histogram_aggregation: base2_exponential_bucket_histogram + insecure: true +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *periodic = + reinterpret_cast( + reader); + ASSERT_NE(periodic->exporter, nullptr); + auto *exporter = periodic->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_grpc = reinterpret_cast< + opentelemetry::sdk::configuration::OtlpGrpcPushMetricExporterConfiguration *>(exporter); + ASSERT_EQ(otlp_grpc->endpoint, "somewhere"); + ASSERT_EQ(otlp_grpc->certificate_file, "certificate_file"); + ASSERT_EQ(otlp_grpc->client_key_file, "client_key_file"); + ASSERT_EQ(otlp_grpc->client_certificate_file, "client_certificate_file"); + ASSERT_NE(otlp_grpc->headers, nullptr); + ASSERT_EQ(otlp_grpc->headers->kv_map.size(), 2); + ASSERT_EQ(otlp_grpc->headers->kv_map["foo"], "123"); + ASSERT_EQ(otlp_grpc->headers->kv_map["bar"], "456"); + ASSERT_EQ(otlp_grpc->headers_list, "baz=789"); + ASSERT_EQ(otlp_grpc->compression, "compression"); + ASSERT_EQ(otlp_grpc->timeout, 5000); + ASSERT_EQ(otlp_grpc->temporality_preference, + opentelemetry::sdk::configuration::TemporalityPreference::delta); + ASSERT_EQ(otlp_grpc->default_histogram_aggregation, + opentelemetry::sdk::configuration::DefaultHistogramAggregation:: + base2_exponential_bucket_histogram); + ASSERT_EQ(otlp_grpc->insecure, true); +} + +TEST(YamlMetrics, default_otlp_file) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + otlp_file/development: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *periodic = + reinterpret_cast( + reader); + ASSERT_NE(periodic->exporter, nullptr); + auto *exporter = periodic->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_file = reinterpret_cast< + opentelemetry::sdk::configuration::OtlpFilePushMetricExporterConfiguration *>(exporter); + ASSERT_EQ(otlp_file->output_stream, ""); + ASSERT_EQ(otlp_file->temporality_preference, + opentelemetry::sdk::configuration::TemporalityPreference::cumulative); + ASSERT_EQ( + otlp_file->default_histogram_aggregation, + opentelemetry::sdk::configuration::DefaultHistogramAggregation::explicit_bucket_histogram); +} + +TEST(YamlMetrics, otlp_file) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + otlp_file/development: + output_stream: "somewhere" + temporality_preference: delta + default_histogram_aggregation: base2_exponential_bucket_histogram +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *periodic = + reinterpret_cast( + reader); + ASSERT_NE(periodic->exporter, nullptr); + auto *exporter = periodic->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_file = reinterpret_cast< + opentelemetry::sdk::configuration::OtlpFilePushMetricExporterConfiguration *>(exporter); + ASSERT_EQ(otlp_file->output_stream, "somewhere"); + ASSERT_EQ(otlp_file->temporality_preference, + opentelemetry::sdk::configuration::TemporalityPreference::delta); + ASSERT_EQ(otlp_file->default_histogram_aggregation, + opentelemetry::sdk::configuration::DefaultHistogramAggregation:: + base2_exponential_bucket_histogram); +} + +TEST(YamlMetrics, default_console) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *periodic = + reinterpret_cast( + reader); + ASSERT_NE(periodic->exporter, nullptr); + auto *exporter = periodic->exporter.get(); + ASSERT_NE(exporter, nullptr); + +#if 0 + auto *console = + reinterpret_cast( + exporter); + + // FIXME-CONFIG: https://github.com/open-telemetry/opentelemetry-configuration/issues/242 + + ASSERT_EQ(console->temporality_preference, + opentelemetry::sdk::configuration::TemporalityPreference::cumulative); + ASSERT_EQ( + console->default_histogram_aggregation, + opentelemetry::sdk::configuration::DefaultHistogramAggregation::explicit_bucket_histogram); +#endif +} + +TEST(YamlMetrics, console) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + temporality_preference: delta + default_histogram_aggregation: base2_exponential_bucket_histogram +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *periodic = + reinterpret_cast( + reader); + ASSERT_NE(periodic->exporter, nullptr); + auto *exporter = periodic->exporter.get(); + ASSERT_NE(exporter, nullptr); + +#if 0 + auto *console = + reinterpret_cast( + exporter); + + // FIXME-CONFIG: https://github.com/open-telemetry/opentelemetry-configuration/issues/242 + + ASSERT_EQ(console->temporality_preference, + opentelemetry::sdk::configuration::TemporalityPreference::cumulative); + ASSERT_EQ( + console->default_histogram_aggregation, + opentelemetry::sdk::configuration::DefaultHistogramAggregation::explicit_bucket_histogram); +#endif +} + +TEST(YamlMetrics, default_prometheus) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - pull: + exporter: + prometheus: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *pull = + reinterpret_cast(reader); + ASSERT_NE(pull->exporter, nullptr); + auto *exporter = pull->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *prometheus = reinterpret_cast< + opentelemetry::sdk::configuration::PrometheusPullMetricExporterConfiguration *>(exporter); + ASSERT_EQ(prometheus->host, "localhost"); + ASSERT_EQ(prometheus->port, 9464); + ASSERT_EQ(prometheus->without_units, false); + ASSERT_EQ(prometheus->without_type_suffix, false); + ASSERT_EQ(prometheus->without_scope_info, false); +} + +TEST(YamlMetrics, prometheus) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - pull: + exporter: + prometheus: + host: "prometheus" + port: 1234 + without_units: true + without_type_suffix: true + without_scope_info: true +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->readers.size(), 1); + auto *reader = config->meter_provider->readers[0].get(); + ASSERT_NE(reader, nullptr); + auto *pull = + reinterpret_cast(reader); + ASSERT_NE(pull->exporter, nullptr); + auto *exporter = pull->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *prometheus = reinterpret_cast< + opentelemetry::sdk::configuration::PrometheusPullMetricExporterConfiguration *>(exporter); + ASSERT_EQ(prometheus->host, "prometheus"); + ASSERT_EQ(prometheus->port, 1234); + ASSERT_EQ(prometheus->without_units, true); + ASSERT_EQ(prometheus->without_type_suffix, true); + ASSERT_EQ(prometheus->without_scope_info, true); +} + +TEST(YamlMetrics, empty_views) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + views: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->views.size(), 0); +} + +TEST(YamlMetrics, default_views) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + views: + - selector: + stream: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->views.size(), 1); + auto *view = config->meter_provider->views[0].get(); + ASSERT_NE(view, nullptr); + ASSERT_NE(view->selector, nullptr); + ASSERT_EQ(view->selector->instrument_name, ""); + ASSERT_EQ(view->selector->instrument_type, + opentelemetry::sdk::configuration::InstrumentType::none); + ASSERT_EQ(view->selector->unit, ""); + ASSERT_EQ(view->selector->meter_name, ""); + ASSERT_EQ(view->selector->meter_version, ""); + ASSERT_EQ(view->selector->meter_schema_url, ""); + ASSERT_NE(view->stream, nullptr); + ASSERT_EQ(view->stream->name, ""); + ASSERT_EQ(view->stream->description, ""); + ASSERT_EQ(view->stream->aggregation_cardinality_limit, 0); + ASSERT_EQ(view->stream->aggregation, nullptr); + ASSERT_EQ(view->stream->attribute_keys, nullptr); +} + +TEST(YamlMetrics, selector) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + views: + - selector: + instrument_name: "instrument_name" + instrument_type: "counter" + unit: "unit" + meter_name: "meter_name" + meter_version: "meter_version" + meter_schema_url: "meter_schema_url" + stream: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->views.size(), 1); + auto *view = config->meter_provider->views[0].get(); + ASSERT_NE(view, nullptr); + ASSERT_NE(view->selector, nullptr); + ASSERT_EQ(view->selector->instrument_name, "instrument_name"); + ASSERT_EQ(view->selector->instrument_type, + opentelemetry::sdk::configuration::InstrumentType::counter); + ASSERT_EQ(view->selector->unit, "unit"); + ASSERT_EQ(view->selector->meter_name, "meter_name"); + ASSERT_EQ(view->selector->meter_version, "meter_version"); + ASSERT_EQ(view->selector->meter_schema_url, "meter_schema_url"); + ASSERT_NE(view->stream, nullptr); + ASSERT_EQ(view->stream->name, ""); + ASSERT_EQ(view->stream->description, ""); + ASSERT_EQ(view->stream->aggregation_cardinality_limit, 0); + ASSERT_EQ(view->stream->aggregation, nullptr); + ASSERT_EQ(view->stream->attribute_keys, nullptr); +} + +TEST(YamlMetrics, stream) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + views: + - selector: + stream: + name: "name" + description: "description" + aggregation_cardinality_limit: 1234 +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->views.size(), 1); + auto *view = config->meter_provider->views[0].get(); + ASSERT_NE(view, nullptr); + ASSERT_NE(view->selector, nullptr); + ASSERT_EQ(view->selector->instrument_name, ""); + ASSERT_EQ(view->selector->instrument_type, + opentelemetry::sdk::configuration::InstrumentType::none); + ASSERT_EQ(view->selector->unit, ""); + ASSERT_EQ(view->selector->meter_name, ""); + ASSERT_EQ(view->selector->meter_version, ""); + ASSERT_EQ(view->selector->meter_schema_url, ""); + ASSERT_NE(view->stream, nullptr); + ASSERT_EQ(view->stream->name, "name"); + ASSERT_EQ(view->stream->description, "description"); + ASSERT_EQ(view->stream->aggregation_cardinality_limit, 1234); + ASSERT_EQ(view->stream->aggregation, nullptr); + ASSERT_EQ(view->stream->attribute_keys, nullptr); +} + +TEST(YamlMetrics, stream_aggregation_default) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + views: + - selector: + stream: + aggregation: + default: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->views.size(), 1); + auto *view = config->meter_provider->views[0].get(); + ASSERT_NE(view, nullptr); + ASSERT_NE(view->selector, nullptr); + ASSERT_NE(view->stream, nullptr); + ASSERT_NE(view->stream->aggregation, nullptr); + ASSERT_EQ(view->stream->attribute_keys, nullptr); +} + +TEST(YamlMetrics, stream_aggregation_drop) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + views: + - selector: + stream: + aggregation: + drop: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->views.size(), 1); + auto *view = config->meter_provider->views[0].get(); + ASSERT_NE(view, nullptr); + ASSERT_NE(view->selector, nullptr); + ASSERT_NE(view->stream, nullptr); + ASSERT_NE(view->stream->aggregation, nullptr); + ASSERT_EQ(view->stream->attribute_keys, nullptr); +} + +TEST(YamlMetrics, stream_aggregation_explicit_bucket_histogram) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + views: + - selector: + stream: + aggregation: + explicit_bucket_histogram: + boundaries: + - 10 + - 20 + - 30 + record_min_max: false +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->views.size(), 1); + auto *view = config->meter_provider->views[0].get(); + ASSERT_NE(view, nullptr); + ASSERT_NE(view->selector, nullptr); + ASSERT_NE(view->stream, nullptr); + ASSERT_NE(view->stream->aggregation, nullptr); + auto *aggregation = view->stream->aggregation.get(); + auto *explicit_bucket_histogram = reinterpret_cast< + opentelemetry::sdk::configuration::ExplicitBucketHistogramAggregationConfiguration *>( + aggregation); + ASSERT_EQ(explicit_bucket_histogram->boundaries.size(), 3); + ASSERT_EQ(explicit_bucket_histogram->boundaries[0], 10); + ASSERT_EQ(explicit_bucket_histogram->boundaries[1], 20); + ASSERT_EQ(explicit_bucket_histogram->boundaries[2], 30); + ASSERT_EQ(explicit_bucket_histogram->record_min_max, false); + ASSERT_EQ(view->stream->attribute_keys, nullptr); +} + +TEST(YamlMetrics, stream_aggregation_base2_exponential_bucket_histogram) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + views: + - selector: + stream: + aggregation: + base2_exponential_bucket_histogram: + max_scale: 40 + max_size: 320 + record_min_max: false +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->views.size(), 1); + auto *view = config->meter_provider->views[0].get(); + ASSERT_NE(view, nullptr); + ASSERT_NE(view->selector, nullptr); + ASSERT_NE(view->stream, nullptr); + ASSERT_NE(view->stream->aggregation, nullptr); + auto *aggregation = view->stream->aggregation.get(); + auto *base2_exponential_bucket_histogram = reinterpret_cast< + opentelemetry::sdk::configuration::Base2ExponentialBucketHistogramAggregationConfiguration *>( + aggregation); + ASSERT_EQ(base2_exponential_bucket_histogram->max_scale, 40); + ASSERT_EQ(base2_exponential_bucket_histogram->max_size, 320); + ASSERT_EQ(base2_exponential_bucket_histogram->record_min_max, false); + ASSERT_EQ(view->stream->attribute_keys, nullptr); +} + +TEST(YamlMetrics, stream_aggregation_last_value) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + views: + - selector: + stream: + aggregation: + last_value: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->views.size(), 1); + auto *view = config->meter_provider->views[0].get(); + ASSERT_NE(view, nullptr); + ASSERT_NE(view->selector, nullptr); + ASSERT_NE(view->stream, nullptr); + ASSERT_NE(view->stream->aggregation, nullptr); + ASSERT_EQ(view->stream->attribute_keys, nullptr); +} + +TEST(YamlMetrics, stream_aggregation_sum) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + views: + - selector: + stream: + aggregation: + sum: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->views.size(), 1); + auto *view = config->meter_provider->views[0].get(); + ASSERT_NE(view, nullptr); + ASSERT_NE(view->selector, nullptr); + ASSERT_NE(view->stream, nullptr); + ASSERT_NE(view->stream->aggregation, nullptr); + ASSERT_EQ(view->stream->attribute_keys, nullptr); +} + +TEST(YamlMetrics, stream_attribute_keys) +{ + std::string yaml = R"( +file_format: xx.yy +meter_provider: + readers: + - periodic: + exporter: + console: + views: + - selector: + stream: + attribute_keys: + included: + - foo.in + - bar.in + excluded: + - foo.ex + - bar.ex +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->meter_provider, nullptr); + ASSERT_EQ(config->meter_provider->views.size(), 1); + auto *view = config->meter_provider->views[0].get(); + ASSERT_NE(view, nullptr); + ASSERT_NE(view->selector, nullptr); + ASSERT_NE(view->stream, nullptr); + ASSERT_EQ(view->stream->aggregation, nullptr); + ASSERT_NE(view->stream->attribute_keys, nullptr); + ASSERT_EQ(view->stream->attribute_keys->included->string_array.size(), 2); + ASSERT_EQ(view->stream->attribute_keys->included->string_array[0], "foo.in"); + ASSERT_EQ(view->stream->attribute_keys->included->string_array[1], "bar.in"); + ASSERT_NE(view->stream->attribute_keys->excluded, nullptr); + ASSERT_EQ(view->stream->attribute_keys->excluded->string_array.size(), 2); + ASSERT_EQ(view->stream->attribute_keys->excluded->string_array[0], "foo.ex"); + ASSERT_EQ(view->stream->attribute_keys->excluded->string_array[1], "bar.ex"); +} diff --git a/sdk/test/configuration/yaml_resource_test.cc b/sdk/test/configuration/yaml_resource_test.cc new file mode 100644 index 0000000000..69386928e3 --- /dev/null +++ b/sdk/test/configuration/yaml_resource_test.cc @@ -0,0 +1,302 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include +#include + +#include "opentelemetry/sdk/configuration/attribute_value_configuration.h" +#include "opentelemetry/sdk/configuration/attributes_configuration.h" +#include "opentelemetry/sdk/configuration/configuration.h" +#include "opentelemetry/sdk/configuration/include_exclude_configuration.h" +#include "opentelemetry/sdk/configuration/resource_configuration.h" +#include "opentelemetry/sdk/configuration/string_array_configuration.h" +#include "opentelemetry/sdk/configuration/string_attribute_value_configuration.h" +#include "opentelemetry/sdk/configuration/yaml_configuration_parser.h" + +static std::unique_ptr DoParse( + const std::string &yaml) +{ + static const std::string source("test"); + return opentelemetry::sdk::configuration::YamlConfigurationParser::ParseString(source, yaml); +} + +TEST(YamlResource, empty_resource) +{ + std::string yaml = R"( +file_format: xx.yy +resource: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->resource, nullptr); + ASSERT_EQ(config->resource->attributes, nullptr); + ASSERT_EQ(config->resource->attributes_list, ""); + ASSERT_EQ(config->resource->detectors, nullptr); +} + +TEST(YamlResource, empty_attributes) +{ + std::string yaml = R"( +file_format: xx.yy +resource: + attributes: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->resource, nullptr); + ASSERT_NE(config->resource->attributes, nullptr); + ASSERT_EQ(config->resource->attributes->kv_map.size(), 0); +} + +TEST(YamlResource, some_attributes_0_10) +{ + // This is the old 0.10 format, must fail + std::string yaml = R"( +file_format: xx.yy +resource: + attributes: + foo: "1234" + bar: "5678" +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(YamlResource, some_attributes_0_30) +{ + // This is the new 0.30 format, must pass + std::string yaml = R"( +file_format: xx.yy +resource: + attributes: + - name: foo + value: "1234" + - name: bar + value: "5678" +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->resource, nullptr); + ASSERT_NE(config->resource->attributes, nullptr); + ASSERT_EQ(config->resource->attributes->kv_map.size(), 2); + + { + const auto &value = config->resource->attributes->kv_map["foo"]; + ASSERT_NE(value, nullptr); + auto *value_ptr = value.get(); + auto *string_value = + reinterpret_cast( + value_ptr); + ASSERT_EQ(string_value->value, "1234"); + } + + { + const auto &value = config->resource->attributes->kv_map["bar"]; + ASSERT_NE(value, nullptr); + auto *value_ptr = value.get(); + auto *string_value = + reinterpret_cast( + value_ptr); + ASSERT_EQ(string_value->value, "5678"); + } +} + +TEST(YamlResource, empty_attributes_list) +{ + std::string yaml = R"( +file_format: xx.yy +resource: + attributes_list: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->resource, nullptr); + ASSERT_EQ(config->resource->attributes_list, ""); +} + +TEST(YamlResource, some_attributes_list) +{ + std::string yaml = R"( +file_format: xx.yy +resource: + attributes_list: "foo=1234,bar=5678" +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->resource, nullptr); + ASSERT_EQ(config->resource->attributes_list, "foo=1234,bar=5678"); +} + +TEST(YamlResource, both_0_10) +{ + // This is the old 0.10 format, must fail + std::string yaml = R"( +file_format: xx.yy +resource: + attributes: + foo: "1234" + bar: "5678" + attributes_list: "foo=aaaa,bar=bbbb" +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(YamlResource, both_0_30) +{ + // This is the new 0.30 format, must pass + std::string yaml = R"( +file_format: xx.yy +resource: + attributes: + - name: foo + value: "1234" + - name: bar + value: "5678" + attributes_list: "foo=aaaa,bar=bbbb" +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->resource, nullptr); + ASSERT_NE(config->resource->attributes, nullptr); + ASSERT_EQ(config->resource->attributes->kv_map.size(), 2); + + { + const auto &value = config->resource->attributes->kv_map["foo"]; + ASSERT_NE(value, nullptr); + auto *value_ptr = value.get(); + auto *string_value = + reinterpret_cast( + value_ptr); + ASSERT_EQ(string_value->value, "1234"); + } + + { + const auto &value = config->resource->attributes->kv_map["bar"]; + ASSERT_NE(value, nullptr); + auto *value_ptr = value.get(); + auto *string_value = + reinterpret_cast( + value_ptr); + ASSERT_EQ(string_value->value, "5678"); + } + + ASSERT_EQ(config->resource->attributes_list, "foo=aaaa,bar=bbbb"); +} + +TEST(YamlResource, empty_detectors) +{ + std::string yaml = R"( +file_format: xx.yy +resource: + detectors: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->resource, nullptr); + ASSERT_NE(config->resource->detectors, nullptr); + ASSERT_EQ(config->resource->detectors->included, nullptr); + ASSERT_EQ(config->resource->detectors->excluded, nullptr); +} + +TEST(YamlResource, empty_included_detectors) +{ + std::string yaml = R"( +file_format: xx.yy +resource: + detectors: + included: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->resource, nullptr); + ASSERT_NE(config->resource->detectors, nullptr); + ASSERT_NE(config->resource->detectors->included, nullptr); + ASSERT_EQ(config->resource->detectors->included->string_array.size(), 0); + ASSERT_EQ(config->resource->detectors->excluded, nullptr); +} + +TEST(YamlResource, some_included_detectors) +{ + std::string yaml = R"( +file_format: xx.yy +resource: + detectors: + included: + - foo + - bar +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->resource, nullptr); + ASSERT_NE(config->resource->detectors, nullptr); + ASSERT_NE(config->resource->detectors->included, nullptr); + ASSERT_EQ(config->resource->detectors->included->string_array.size(), 2); + ASSERT_EQ(config->resource->detectors->included->string_array[0], "foo"); + ASSERT_EQ(config->resource->detectors->included->string_array[1], "bar"); + ASSERT_EQ(config->resource->detectors->excluded, nullptr); +} + +TEST(YamlResource, some_excluded_detectors) +{ + std::string yaml = R"( +file_format: xx.yy +resource: + detectors: + excluded: + - foo + - bar +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->resource, nullptr); + ASSERT_NE(config->resource->detectors, nullptr); + ASSERT_EQ(config->resource->detectors->included, nullptr); + ASSERT_NE(config->resource->detectors->excluded, nullptr); + ASSERT_EQ(config->resource->detectors->excluded->string_array.size(), 2); + ASSERT_EQ(config->resource->detectors->excluded->string_array[0], "foo"); + ASSERT_EQ(config->resource->detectors->excluded->string_array[1], "bar"); +} + +TEST(YamlResource, some_detectors) +{ + std::string yaml = R"( +file_format: xx.yy +resource: + detectors: + included: + - foo.in + - bar.in + excluded: + - foo.ex + - bar.ex +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->resource, nullptr); + ASSERT_NE(config->resource->detectors, nullptr); + ASSERT_NE(config->resource->detectors->included, nullptr); + ASSERT_EQ(config->resource->detectors->included->string_array.size(), 2); + ASSERT_EQ(config->resource->detectors->included->string_array[0], "foo.in"); + ASSERT_EQ(config->resource->detectors->included->string_array[1], "bar.in"); + ASSERT_NE(config->resource->detectors->excluded, nullptr); + ASSERT_EQ(config->resource->detectors->excluded->string_array.size(), 2); + ASSERT_EQ(config->resource->detectors->excluded->string_array[0], "foo.ex"); + ASSERT_EQ(config->resource->detectors->excluded->string_array[1], "bar.ex"); +} diff --git a/sdk/test/configuration/yaml_test.cc b/sdk/test/configuration/yaml_test.cc new file mode 100644 index 0000000000..6a62f65429 --- /dev/null +++ b/sdk/test/configuration/yaml_test.cc @@ -0,0 +1,663 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include + +#include "opentelemetry/sdk/configuration/attribute_limits_configuration.h" +#include "opentelemetry/sdk/configuration/configuration.h" +#include "opentelemetry/sdk/configuration/trace_id_ratio_based_sampler_configuration.h" +#include "opentelemetry/sdk/configuration/tracer_provider_configuration.h" +#include "opentelemetry/sdk/configuration/yaml_configuration_parser.h" + +static std::unique_ptr DoParse( + const std::string &yaml) +{ + static const std::string source("test"); + return opentelemetry::sdk::configuration::YamlConfigurationParser::ParseString(source, yaml); +} + +TEST(Yaml, empty) +{ + std::string yaml = ""; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, no_format) +{ + std::string yaml = R"( +file_format: +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, just_format) +{ + std::string yaml = R"( +file_format: xx.yy +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, "xx.yy"); +} + +TEST(Yaml, disabled) +{ + std::string yaml = R"( +file_format: xx.yy +disabled: true +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, "xx.yy"); + ASSERT_EQ(config->disabled, true); +} + +TEST(Yaml, enabled) +{ + std::string yaml = R"( +file_format: xx.yy +disabled: false +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, "xx.yy"); + ASSERT_EQ(config->disabled, false); +} + +TEST(Yaml, enabled_by_default) +{ + std::string yaml = R"( +file_format: xx.yy +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, "xx.yy"); + ASSERT_EQ(config->disabled, false); +} + +TEST(Yaml, no_attribute_limits) +{ + std::string yaml = R"( +file_format: xx.yy +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->attribute_limits, nullptr); +} + +TEST(Yaml, empty_attribute_limits) +{ + std::string yaml = R"( +file_format: xx.yy +attribute_limits: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, "xx.yy"); + ASSERT_NE(config->attribute_limits, nullptr); + ASSERT_EQ(config->attribute_limits->attribute_value_length_limit, 4096); + ASSERT_EQ(config->attribute_limits->attribute_count_limit, 128); +} + +TEST(Yaml, attribute_limits) +{ + std::string yaml = R"( +file_format: xx.yy +attribute_limits: + attribute_value_length_limit: 1234 + attribute_count_limit: 5678 +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, "xx.yy"); + 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); +} + +TEST(Yaml, no_optional_boolean) +{ + std::string yaml = R"( +file_format: 0.0 +disabled: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->disabled, false); +} + +TEST(Yaml, illegal_boolean) +{ + std::string yaml = R"( +file_format: 0.0 +disabled: illegal +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, no_boolean_substitution) +{ + unsetenv("ENV_NAME"); + + std::string yaml = R"( +file_format: 0.0 +disabled: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->disabled, false); +} + +TEST(Yaml, no_boolean_substitution_env) +{ + unsetenv("ENV_NAME"); + + std::string yaml = R"( +file_format: 0.0 +disabled: ${env:ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->disabled, false); +} + +TEST(Yaml, empty_boolean_substitution) +{ + setenv("ENV_NAME", "", 1); + + std::string yaml = R"( +file_format: 0.0 +disabled: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->disabled, false); +} + +TEST(Yaml, empty_boolean_substitution_env) +{ + setenv("ENV_NAME", "", 1); + + std::string yaml = R"( +file_format: 0.0 +disabled: ${env:ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->disabled, false); +} + +TEST(Yaml, true_boolean_substitution) +{ + setenv("ENV_NAME", "true", 1); + + std::string yaml = R"( +file_format: 0.0 +disabled: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->disabled, true); +} + +TEST(Yaml, false_boolean_substitution) +{ + setenv("ENV_NAME", "false", 1); + + std::string yaml = R"( +file_format: 0.0 +disabled: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->disabled, false); +} + +TEST(Yaml, illegal_boolean_substitution) +{ + setenv("ENV_NAME", "illegal", 1); + + std::string yaml = R"( +file_format: 0.0 +disabled: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, empty_boolean_substitution_fallback) +{ + unsetenv("ENV_NAME"); + + std::string yaml = R"( +file_format: 0.0 +disabled: ${ENV_NAME:-} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->disabled, false); +} + +TEST(Yaml, true_boolean_substitution_fallback) +{ + unsetenv("ENV_NAME"); + + std::string yaml = R"( +file_format: 0.0 +disabled: ${ENV_NAME:-true} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->disabled, true); +} + +TEST(Yaml, false_boolean_substitution_fallback) +{ + unsetenv("ENV_NAME"); + + std::string yaml = R"( +file_format: 0.0 +disabled: ${ENV_NAME:-false} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->disabled, false); +} + +TEST(Yaml, illegal_boolean_substitution_fallback) +{ + unsetenv("ENV_NAME"); + + std::string yaml = R"( +file_format: 0.0 +disabled: ${ENV_NAME:-illegal} +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, torture_boolean_substitution_fallback) +{ + setenv("env", "true", 1); + + std::string yaml = R"( +file_format: 0.0 +disabled: ${env:-false} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->disabled, true); +} + +TEST(Yaml, no_required_string) +{ + std::string yaml = R"( +file_format: +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, no_string_substitution) +{ + unsetenv("ENV_NAME"); + + std::string yaml = R"( +file_format: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, no_string_substitution_env) +{ + unsetenv("ENV_NAME"); + + std::string yaml = R"( +file_format: ${env:ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, empty_string_substitution) +{ + setenv("ENV_NAME", "", 1); + + std::string yaml = R"( +file_format: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, empty_string_substitution_env) +{ + setenv("ENV_NAME", "", 1); + + std::string yaml = R"( +file_format: ${env:ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, with_string_substitution) +{ + setenv("ENV_NAME", "foo.bar", 1); + + std::string yaml = R"( +file_format: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, "foo.bar"); +} + +TEST(Yaml, with_string_substitution_env) +{ + setenv("ENV_NAME", "foo.bar", 1); + + std::string yaml = R"( +file_format: ${env:ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, "foo.bar"); +} + +TEST(Yaml, with_string_substitution_fallback) +{ + unsetenv("ENV_NAME"); + + std::string yaml = R"( +file_format: ${env:ENV_NAME:-foo.bar} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, "foo.bar"); +} + +TEST(Yaml, multiple_string_substitution) +{ + setenv("PREFIX", "foo", 1); + unsetenv("DOT"); + setenv("SUFFIX", "bar", 1); + + std::string yaml = R"( +file_format: ${env:PREFIX:-failed}${DOT:-.}${SUFFIX:-failed} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, "foo.bar"); +} + +TEST(Yaml, no_optional_integer) +{ + std::string yaml = R"( +file_format: 0.0 +attribute_limits: + attribute_count_limit: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->attribute_limits, nullptr); + ASSERT_EQ(config->attribute_limits->attribute_count_limit, 128); +} + +TEST(Yaml, illegal_integer) +{ + std::string yaml = R"( +file_format: 0.0 +attribute_limits: + attribute_count_limit: "just enough" +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, no_integer_substitution) +{ + unsetenv("ENV_NAME"); + + std::string yaml = R"( +file_format: 0.0 +attribute_limits: + attribute_count_limit: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->attribute_limits, nullptr); + ASSERT_EQ(config->attribute_limits->attribute_count_limit, 128); +} + +TEST(Yaml, empty_integer_substitution) +{ + setenv("ENV_NAME", "", 1); + + std::string yaml = R"( +file_format: 0.0 +attribute_limits: + attribute_count_limit: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->attribute_limits, nullptr); + ASSERT_EQ(config->attribute_limits->attribute_count_limit, 128); +} + +TEST(Yaml, with_integer_substitution) +{ + setenv("ENV_NAME", "7777", 1); + + std::string yaml = R"( +file_format: 0.0 +attribute_limits: + attribute_count_limit: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->attribute_limits, nullptr); + ASSERT_EQ(config->attribute_limits->attribute_count_limit, 7777); +} + +TEST(Yaml, with_illegal_integer_substitution) +{ + setenv("ENV_NAME", "still not enough", 1); + + std::string yaml = R"( +file_format: 0.0 +attribute_limits: + attribute_count_limit: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, no_optional_double) +{ + std::string yaml = R"( +file_format: 0.0 +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + trace_id_ratio_based: + ratio: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_NE(config->tracer_provider->sampler, nullptr); + auto sampler = config->tracer_provider->sampler.get(); + auto ratio_sampler = + static_cast( + sampler); + ASSERT_EQ(ratio_sampler->ratio, 0.0); +} + +TEST(Yaml, illegal_double) +{ + std::string yaml = R"( +file_format: 0.0 +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + trace_id_ratio_based: + ratio: something +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(Yaml, no_double_substitution) +{ + unsetenv("ENV_NAME"); + + std::string yaml = R"( +file_format: 0.0 +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + trace_id_ratio_based: + ratio: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_NE(config->tracer_provider->sampler, nullptr); + auto sampler = config->tracer_provider->sampler.get(); + auto ratio_sampler = + static_cast( + sampler); + ASSERT_EQ(ratio_sampler->ratio, 0.0); +} + +TEST(Yaml, empty_double_substitution) +{ + setenv("ENV_NAME", "", 1); + + std::string yaml = R"( +file_format: 0.0 +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + trace_id_ratio_based: + ratio: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_NE(config->tracer_provider->sampler, nullptr); + auto sampler = config->tracer_provider->sampler.get(); + auto ratio_sampler = + static_cast( + sampler); + ASSERT_EQ(ratio_sampler->ratio, 0.0); +} + +TEST(Yaml, with_double_substitution) +{ + setenv("ENV_NAME", "3.14", 1); + + std::string yaml = R"( +file_format: 0.0 +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + trace_id_ratio_based: + ratio: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_NE(config->tracer_provider->sampler, nullptr); + auto sampler = config->tracer_provider->sampler.get(); + auto ratio_sampler = + static_cast( + sampler); + ASSERT_EQ(ratio_sampler->ratio, 3.14); +} + +TEST(Yaml, with_illegal_double_substitution) +{ + setenv("ENV_NAME", "something else", 1); + + std::string yaml = R"( +file_format: 0.0 +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + trace_id_ratio_based: + ratio: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} diff --git a/sdk/test/configuration/yaml_trace_test.cc b/sdk/test/configuration/yaml_trace_test.cc new file mode 100644 index 0000000000..f5f53c7419 --- /dev/null +++ b/sdk/test/configuration/yaml_trace_test.cc @@ -0,0 +1,796 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include +#include + +#include "opentelemetry/sdk/configuration/batch_span_processor_configuration.h" +#include "opentelemetry/sdk/configuration/configuration.h" +#include "opentelemetry/sdk/configuration/headers_configuration.h" +#include "opentelemetry/sdk/configuration/jaeger_remote_sampler_configuration.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" +#include "opentelemetry/sdk/configuration/otlp_http_span_exporter_configuration.h" +#include "opentelemetry/sdk/configuration/parent_based_sampler_configuration.h" +#include "opentelemetry/sdk/configuration/simple_span_processor_configuration.h" +#include "opentelemetry/sdk/configuration/span_limits_configuration.h" +#include "opentelemetry/sdk/configuration/span_processor_configuration.h" +#include "opentelemetry/sdk/configuration/trace_id_ratio_based_sampler_configuration.h" +#include "opentelemetry/sdk/configuration/tracer_provider_configuration.h" +#include "opentelemetry/sdk/configuration/yaml_configuration_parser.h" +#include "opentelemetry/sdk/configuration/zipkin_span_exporter_configuration.h" + +static std::unique_ptr DoParse( + const std::string &yaml) +{ + static const std::string source("test"); + return opentelemetry::sdk::configuration::YamlConfigurationParser::ParseString(source, yaml); +} + +TEST(YamlTrace, no_processors) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(YamlTrace, empty_processors) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(YamlTrace, many_processors) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: + - simple: + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 2); +} + +TEST(YamlTrace, simple_processor) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 1); + auto *processor = config->tracer_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); +} + +TEST(YamlTrace, default_batch_processor) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - batch: + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 1); + auto *processor = config->tracer_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + auto *batch = + reinterpret_cast( + processor); + ASSERT_EQ(batch->schedule_delay, 5000); + ASSERT_EQ(batch->export_timeout, 30000); + ASSERT_EQ(batch->max_queue_size, 2048); + ASSERT_EQ(batch->max_export_batch_size, 512); + ASSERT_NE(batch->exporter, nullptr); + auto *exporter = batch->exporter.get(); + ASSERT_NE(exporter, nullptr); +} + +TEST(YamlTrace, batch_processor) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - batch: + schedule_delay: 5555 + export_timeout: 33333 + max_queue_size: 1234 + max_export_batch_size: 256 + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 1); + auto *processor = config->tracer_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + auto *batch = + reinterpret_cast( + processor); + ASSERT_EQ(batch->schedule_delay, 5555); + ASSERT_EQ(batch->export_timeout, 33333); + ASSERT_EQ(batch->max_queue_size, 1234); + ASSERT_EQ(batch->max_export_batch_size, 256); + ASSERT_NE(batch->exporter, nullptr); + auto *exporter = batch->exporter.get(); + ASSERT_NE(exporter, nullptr); +} + +TEST(YamlTrace, default_otlp_http) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + otlp_http: + endpoint: "somewhere" +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 1); + auto *processor = config->tracer_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_http = + reinterpret_cast( + exporter); + ASSERT_EQ(otlp_http->endpoint, "somewhere"); + ASSERT_EQ(otlp_http->certificate_file, ""); + ASSERT_EQ(otlp_http->client_key_file, ""); + ASSERT_EQ(otlp_http->client_certificate_file, ""); + ASSERT_EQ(otlp_http->headers, nullptr); + ASSERT_EQ(otlp_http->headers_list, ""); + ASSERT_EQ(otlp_http->compression, ""); + ASSERT_EQ(otlp_http->timeout, 10000); + ASSERT_EQ(otlp_http->encoding, opentelemetry::sdk::configuration::OtlpHttpEncoding::protobuf); +} + +TEST(YamlTrace, otlp_http) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + otlp_http: + endpoint: "somewhere" + certificate_file: "certificate_file" + client_key_file: "client_key_file" + client_certificate_file: "client_certificate_file" + headers: + - name: foo + value: "123" + - name: bar + value: "456" + headers_list: "baz=789" + compression: "compression" + timeout: 5000 + encoding: json +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 1); + auto *processor = config->tracer_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_http = + reinterpret_cast( + exporter); + ASSERT_EQ(otlp_http->endpoint, "somewhere"); + ASSERT_EQ(otlp_http->certificate_file, "certificate_file"); + ASSERT_EQ(otlp_http->client_key_file, "client_key_file"); + ASSERT_EQ(otlp_http->client_certificate_file, "client_certificate_file"); + ASSERT_NE(otlp_http->headers, nullptr); + ASSERT_EQ(otlp_http->headers->kv_map.size(), 2); + ASSERT_EQ(otlp_http->headers->kv_map["foo"], "123"); + ASSERT_EQ(otlp_http->headers->kv_map["bar"], "456"); + ASSERT_EQ(otlp_http->headers_list, "baz=789"); + ASSERT_EQ(otlp_http->compression, "compression"); + ASSERT_EQ(otlp_http->timeout, 5000); + ASSERT_EQ(otlp_http->encoding, opentelemetry::sdk::configuration::OtlpHttpEncoding::json); +} + +TEST(YamlTrace, default_otlp_grpc) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + otlp_grpc: + endpoint: "somewhere" +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 1); + auto *processor = config->tracer_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_grpc = + reinterpret_cast( + exporter); + ASSERT_EQ(otlp_grpc->endpoint, "somewhere"); + ASSERT_EQ(otlp_grpc->certificate_file, ""); + ASSERT_EQ(otlp_grpc->client_key_file, ""); + ASSERT_EQ(otlp_grpc->client_certificate_file, ""); + ASSERT_EQ(otlp_grpc->headers, nullptr); + ASSERT_EQ(otlp_grpc->headers_list, ""); + ASSERT_EQ(otlp_grpc->compression, ""); + ASSERT_EQ(otlp_grpc->timeout, 10000); + ASSERT_EQ(otlp_grpc->insecure, false); +} + +TEST(YamlTrace, otlp_grpc) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + otlp_grpc: + endpoint: "somewhere" + certificate_file: "certificate_file" + client_key_file: "client_key_file" + client_certificate_file: "client_certificate_file" + headers: + - name: foo + value: "123" + - name: bar + value: "456" + headers_list: "baz=789" + compression: "compression" + timeout: 5000 + insecure: true +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 1); + auto *processor = config->tracer_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_grpc = + reinterpret_cast( + exporter); + ASSERT_EQ(otlp_grpc->endpoint, "somewhere"); + ASSERT_EQ(otlp_grpc->certificate_file, "certificate_file"); + ASSERT_EQ(otlp_grpc->client_key_file, "client_key_file"); + ASSERT_EQ(otlp_grpc->client_certificate_file, "client_certificate_file"); + ASSERT_NE(otlp_grpc->headers, nullptr); + ASSERT_EQ(otlp_grpc->headers->kv_map.size(), 2); + ASSERT_EQ(otlp_grpc->headers->kv_map["foo"], "123"); + ASSERT_EQ(otlp_grpc->headers->kv_map["bar"], "456"); + ASSERT_EQ(otlp_grpc->headers_list, "baz=789"); + ASSERT_EQ(otlp_grpc->compression, "compression"); + ASSERT_EQ(otlp_grpc->timeout, 5000); + ASSERT_EQ(otlp_grpc->insecure, true); +} + +TEST(YamlTrace, default_otlp_file) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + otlp_file/development: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 1); + auto *processor = config->tracer_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_file = + reinterpret_cast( + exporter); + ASSERT_EQ(otlp_file->output_stream, ""); +} + +TEST(YamlTrace, otlp_file) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + otlp_file/development: + output_stream: "somewhere" +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 1); + auto *processor = config->tracer_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *otlp_file = + reinterpret_cast( + exporter); + ASSERT_EQ(otlp_file->output_stream, "somewhere"); +} + +TEST(YamlTrace, otlp_console) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 1); + auto *processor = config->tracer_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); +} + +TEST(YamlTrace, default_otlp_zipkin) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + zipkin: + endpoint: "zipkin" +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 1); + auto *processor = config->tracer_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *zipkin = + reinterpret_cast( + exporter); + ASSERT_EQ(zipkin->endpoint, "zipkin"); + ASSERT_EQ(zipkin->timeout, 10000); +} + +TEST(YamlTrace, otlp_zipkin) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + zipkin: + endpoint: "zipkin" + timeout: 5000 +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->processors.size(), 1); + auto *processor = config->tracer_provider->processors[0].get(); + ASSERT_NE(processor, nullptr); + auto *simple = + reinterpret_cast( + processor); + ASSERT_NE(simple->exporter, nullptr); + auto *exporter = simple->exporter.get(); + ASSERT_NE(exporter, nullptr); + auto *zipkin = + reinterpret_cast( + exporter); + ASSERT_EQ(zipkin->endpoint, "zipkin"); + ASSERT_EQ(zipkin->timeout, 5000); +} + +TEST(YamlTrace, no_limits) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->limits, nullptr); +} + +TEST(YamlTrace, default_limits) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: + limits: +)"; + + auto config = DoParse(yaml); + 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, 4096); + 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); +} + +TEST(YamlTrace, limits) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: + limits: + attribute_value_length_limit: 1111 + attribute_count_limit: 2222 + event_count_limit: 3333 + link_count_limit: 4444 + event_attribute_count_limit: 5555 + link_attribute_count_limit: 6666 +)"; + + auto config = DoParse(yaml); + 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); +} + +TEST(YamlTrace, no_sampler) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_EQ(config->tracer_provider->sampler, nullptr); +} + +TEST(YamlTrace, empty_sampler) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(YamlTrace, many_sampler) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + foo: + bar: +)"; + + auto config = DoParse(yaml); + ASSERT_EQ(config, nullptr); +} + +TEST(YamlTrace, always_off_sampler) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + always_off: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_NE(config->tracer_provider->sampler, nullptr); +} + +TEST(YamlTrace, always_on_sampler) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + always_on: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_NE(config->tracer_provider->sampler, nullptr); +} + +TEST(YamlTrace, jaeger_remote_sampler) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + jaeger_remote: + endpoint: jaeger + interval: 1234 + initial_sampler: + always_off: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_NE(config->tracer_provider->sampler, nullptr); + auto *sampler = config->tracer_provider->sampler.get(); + auto *jaeger = + reinterpret_cast( + sampler); + ASSERT_EQ(jaeger->endpoint, "jaeger"); + ASSERT_EQ(jaeger->interval, 1234); + ASSERT_NE(jaeger->initial_sampler, nullptr); +} + +TEST(YamlTrace, default_parent_based_sampler) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + parent_based: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_NE(config->tracer_provider->sampler, nullptr); + auto *sampler = config->tracer_provider->sampler.get(); + auto *parent = + reinterpret_cast( + sampler); + ASSERT_EQ(parent->root, nullptr); + ASSERT_EQ(parent->remote_parent_sampled, nullptr); + ASSERT_EQ(parent->remote_parent_not_sampled, nullptr); + ASSERT_EQ(parent->local_parent_sampled, nullptr); + ASSERT_EQ(parent->local_parent_not_sampled, nullptr); +} + +TEST(YamlTrace, parent_based_sampler) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + parent_based: + root: + always_off: + remote_parent_sampled: + always_off: + remote_parent_not_sampled: + always_off: + local_parent_sampled: + always_off: + local_parent_not_sampled: + always_off: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_NE(config->tracer_provider->sampler, nullptr); + auto *sampler = config->tracer_provider->sampler.get(); + auto *parent = + reinterpret_cast( + sampler); + ASSERT_NE(parent->root, nullptr); + ASSERT_NE(parent->remote_parent_sampled, nullptr); + ASSERT_NE(parent->remote_parent_not_sampled, nullptr); + ASSERT_NE(parent->local_parent_sampled, nullptr); + ASSERT_NE(parent->local_parent_not_sampled, nullptr); +} + +TEST(YamlTrace, default_trace_id_ratio_based_sampler) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + trace_id_ratio_based: +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_NE(config->tracer_provider->sampler, nullptr); + auto *sampler = config->tracer_provider->sampler.get(); + auto *ratio = + reinterpret_cast( + sampler); + ASSERT_EQ(ratio->ratio, 0.0); +} + +TEST(YamlTrace, trace_id_ratio_based_sampler) +{ + std::string yaml = R"( +file_format: xx.yy +tracer_provider: + processors: + - simple: + exporter: + console: + sampler: + trace_id_ratio_based: + ratio: 3.14 +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_NE(config->tracer_provider, nullptr); + ASSERT_NE(config->tracer_provider->sampler, nullptr); + auto *sampler = config->tracer_provider->sampler.get(); + auto *ratio = + reinterpret_cast( + sampler); + ASSERT_EQ(ratio->ratio, 3.14); +}