From bcedd1c5872ac065cb10d37430439a5b20d31bfc Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Tue, 23 Sep 2025 12:41:19 +0200 Subject: [PATCH 01/18] [File-Based] Add traces exporter configuration --- .../BatchProcessorConfig.cs | 90 +++++++++++++++++++ .../FileBasedConfiguration/ExporterConfig.cs | 39 ++++++++ .../FileBasedConfiguration/Header.cs | 21 +++++ .../OtlpGrpcExporterConfig.cs | 42 +++++++++ .../OtlpHttpExporterConfig.cs | 43 +++++++++ .../TracerProviderConfiguration.cs | 12 +++ .../YamlConfiguration.cs | 9 ++ .../ZipkinExporterConfig.cs | 28 ++++++ .../Configurations/Otlp/OtlpSettings.cs | 63 +++++++++++++ .../Configurations/TracerSettings.cs | 55 ++++++++++-- 10 files changed, 397 insertions(+), 5 deletions(-) create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Header.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs new file mode 100644 index 0000000000..0a0095e8db --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs @@ -0,0 +1,90 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.Diagnostics; +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class BatchProcessorConfig +{ + public BatchProcessorConfig() + { + } + + public BatchProcessorConfig( + int? scheduleDelay = null, + int? exportTimeout = null, + int? maxQueueSize = null, + int? maxExportBatchSize = null) + { + if (scheduleDelay is not null) + { + ScheduleDelay = scheduleDelay.Value; + } + + if (exportTimeout is not null) + { + ExportTimeout = exportTimeout.Value; + } + + if (maxQueueSize is not null) + { + MaxQueueSize = maxQueueSize.Value; + } + + if (maxExportBatchSize is not null) + { + MaxExportBatchSize = maxExportBatchSize.Value; + } + } + + /// + /// Gets or sets the delay interval (in milliseconds) between two consecutive exports. + /// Value must be non-negative. + /// If omitted or null, 5000 is used. + /// + [YamlMember(Alias = "schedule_delay")] + public int ScheduleDelay { get; set; } = 5000; + + /// + /// Gets or sets the maximum allowed time (in milliseconds) to export data. + /// Value must be non-negative. A value of 0 indicates no limit (infinity). + /// If omitted or null, 30000 is used. + /// + [YamlMember(Alias = "export_timeout")] + public int ExportTimeout { get; set; } = 30000; + + /// + /// Gets or sets the maximum queue size. + /// Value must be positive. + /// If omitted or null, 2048 is used. + /// + [YamlMember(Alias = "max_queue_size")] + public int MaxQueueSize { get; set; } = 2048; + + /// + /// Gets or sets the maximum batch size. + /// Value must be positive. + /// If omitted or null, 512 is used. + /// + [YamlMember(Alias = "max_export_batch_size")] + public int MaxExportBatchSize { get; set; } = 512; + + /// + /// Gets or sets the exporters. + /// + [YamlMember(Alias = "exporter")] + public ExporterConfig? Exporter { get; set; } + + public BatchExportProcessorOptions ToBatchExportProcessorOptions() + { + return new BatchExportProcessorOptions + { + ScheduledDelayMilliseconds = this.ScheduleDelay, + ExporterTimeoutMilliseconds = this.ExportTimeout, + MaxQueueSize = this.MaxQueueSize, + MaxExportBatchSize = this.MaxExportBatchSize + }; + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs new file mode 100644 index 0000000000..8954eea496 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs @@ -0,0 +1,39 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class ExporterConfig +{ + /// + /// Gets or sets the OTLP HTTP exporter configuration. + /// + [YamlMember(Alias = "otlp_http")] + public OtlpHttpExporterConfig? OtlpHttp { get; set; } + + /// + /// Gets or sets the OTLP gRPC exporter configuration. + /// + [YamlMember(Alias = "otlp_grpc")] + public OtlpGrpcExporterConfig? OtlpGrpc { get; set; } + + /// + /// Gets or sets the Zipkin exporter configuration. + /// + [YamlMember(Alias = "zipkin")] + public ZipkinExporterConfig? Zipkin { get; set; } + + /// + /// Gets or sets the Prometheus exporter configuration. + /// + [YamlMember(Alias = "prometheus")] + public object? Prometheus { get; set; } + + /// + /// Gets or sets the console exporter configuration. + /// + [YamlMember(Alias = "console")] + public object? Console { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Header.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Header.cs new file mode 100644 index 0000000000..fcb10a6686 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Header.cs @@ -0,0 +1,21 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class Header +{ + /// + /// Gets or sets the name of the header. + /// + [YamlMember(Alias = "name")] + public string? Name { get; set; } + + /// + /// Gets or sets the value of the header. + /// + [YamlMember(Alias = "value")] + public string? Value { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs new file mode 100644 index 0000000000..c625f53bd6 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs @@ -0,0 +1,42 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class OtlpGrpcExporterConfig +{ + /// + /// Gets or sets the endpoint for the OTLP gRPC exporter. + /// Configure endpoint. + /// If omitted or null, http://localhost:4317 is used. + /// + [YamlMember(Alias = "endpoint")] + public string? Endpoint { get; set; } + + /// + /// Gets or sets the headers for the exporter. + /// Configure headers. Entries have higher priority than entries from headers_list. + /// If an entry's value is null, the entry is ignored. + /// + [YamlMember(Alias = "headers")] + public List
? Headers { get; set; } + + /// + /// Gets or sets the headers list for the exporter. + /// Configure headers. Entries have lower priority than entries from headers. + /// The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. + /// If omitted or null, no headers are added. + /// + [YamlMember(Alias = "headers_list")] + public string? HeadersList { get; set; } + + /// + /// Gets or sets the maximum time (in milliseconds) to wait for each export. + /// Value must be non-negative. A value of 0 indicates no limit (infinity). + /// If omitted or null, 10000 is used. + /// + [YamlMember(Alias = "timeout")] + public int? Timeout { get; set; } = 10000; +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs new file mode 100644 index 0000000000..74a624882e --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs @@ -0,0 +1,43 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.Diagnostics; +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class OtlpHttpExporterConfig +{ + /// + /// Gets or sets the endpoint for the OTLP HTTP exporter. + /// Configure endpoint. + /// If omitted or null, http://localhost:4318 is used. + /// + [YamlMember(Alias = "endpoint")] + public string? Endpoint { get; set; } + + /// + /// Gets or sets the headers for the exporter. + /// Configure headers. Entries have higher priority than entries from headers_list. + /// If an entry's value is null, the entry is ignored. + /// + [YamlMember(Alias = "headers")] + public List
? Headers { get; set; } + + /// + /// Gets or sets the headers list for the exporter. + /// Configure headers. Entries have lower priority than entries from headers. + /// The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. + /// If omitted or null, no headers are added. + /// + [YamlMember(Alias = "headers_list")] + public string? HeadersList { get; set; } + + /// + /// Gets or sets the maximum time (in milliseconds) to wait for each export. + /// Value must be non-negative. A value of 0 indicates no limit (infinity). + /// If omitted or null, 10000 is used. + /// + [YamlMember(Alias = "timeout")] + public int? Timeout { get; set; } = 10000; +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs new file mode 100644 index 0000000000..21be9eaef9 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs @@ -0,0 +1,12 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class TracerProviderConfiguration +{ + [YamlMember(Alias = "processors")] + public Dictionary Processors { get; set; } = new(); +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs index 8e0fbf259e..ae56728198 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using System.Diagnostics; using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; @@ -22,4 +23,12 @@ internal class YamlConfiguration /// [YamlMember(Alias = "resource")] public ResourceConfiguration? Resource { get; set; } + + /// + /// Gets or sets the tracer provider configuration. + /// Configure tracer provider. + /// If omitted, a noop tracer provider is used. + /// + [YamlMember(Alias = "tracer_provider")] + public TracerProviderConfiguration? TracerProvider { get; set; } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs new file mode 100644 index 0000000000..45fafd8429 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs @@ -0,0 +1,28 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class ZipkinExporterConfig +{ + public ZipkinExporterConfig() + { + } + + public ZipkinExporterConfig(string? endpoint) + { + if (endpoint is not null) + { + Endpoint = endpoint; + } + } + + /// + /// Gets or sets the Zipkin endpoint URL to which spans are exported. + /// If omitted or null, the default value "http://localhost:9411/api/v2/spans" is used. + /// + [YamlMember(Alias = "endpoint")] + public string Endpoint { get; set; } = "http://localhost:9411/api/v2/spans"; +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs index 366ad01c8d..62af59ec9d 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using OpenTelemetry.Exporter; namespace OpenTelemetry.AutoInstrumentation.Configurations.Otlp; @@ -25,6 +26,30 @@ public OtlpSettings(OtlpSignalType signalType, Configuration configuration) Endpoint = configuration.GetUri(priorityVar); } + public OtlpSettings(OtlpSignalType signalType, OtlpHttpExporterConfig configuration) + { + Protocol = OtlpExportProtocol.HttpProtobuf; + + Headers = CombineHeaders(configuration.Headers, configuration.HeadersList); + + TimeoutMilliseconds = configuration.Timeout; + + Endpoint = !string.IsNullOrEmpty(configuration.Endpoint) ? new Uri(configuration.Endpoint) : null; + } + + public OtlpSettings(OtlpSignalType signalType, OtlpGrpcExporterConfig configuration) + { +#pragma warning disable CS0618 // OtlpExportProtocol.Grpc is obsolete + Protocol = OtlpExportProtocol.Grpc; +#pragma warning restore CS0618 // OtlpExportProtocol.Grpc is obsolete + + Headers = CombineHeaders(configuration.Headers, configuration.HeadersList); + + TimeoutMilliseconds = configuration.Timeout; + + Endpoint = !string.IsNullOrEmpty(configuration.Endpoint) ? new Uri(configuration.Endpoint) : null; + } + /// /// Gets the OTLP transport protocol. Supported values: Grpc and HttpProtobuf. /// @@ -70,6 +95,44 @@ public void CopyTo(OtlpExporterOptions options) } } + private static string? CombineHeaders(List
? headers, string? headersList) + { + var headerDict = new Dictionary(StringComparer.OrdinalIgnoreCase); + + if (!string.IsNullOrWhiteSpace(headersList)) + { + var pairs = headersList!.Split([','], StringSplitOptions.RemoveEmptyEntries); + foreach (var pair in pairs) + { + var parts = pair.Split('='); + if (parts.Length == 2) + { + var key = parts[0]; + var value = parts[1]; + if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value)) + { + headerDict[key] = value; + } + } + } + } + + if (headers != null) + { + foreach (var header in headers) + { + if (!string.IsNullOrWhiteSpace(header?.Name) && !string.IsNullOrWhiteSpace(header?.Value)) + { + headerDict[header!.Name!] = header!.Value!; + } + } + } + + return headerDict.Count == 0 + ? null + : string.Join(",", headerDict.Select(kvp => $"{kvp.Key}={kvp.Value}")); + } + private static OtlpExportProtocol? GetExporterOtlpProtocol(OtlpSignalType signalType, Configuration configuration) { // the default in SDK is grpc. http/protobuf should be default for our purposes diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs index 78732e0da8..d7d72239a8 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using OpenTelemetry.AutoInstrumentation.Configurations.Otlp; using OpenTelemetry.AutoInstrumentation.Logging; @@ -26,22 +27,22 @@ internal class TracerSettings : Settings /// /// Gets the list of enabled traces exporters. /// - public IReadOnlyList TracesExporters { get; private set; } = new List(); + public IReadOnlyList TracesExporters { get; private set; } = []; /// /// Gets the list of enabled instrumentations. /// - public IReadOnlyList EnabledInstrumentations { get; private set; } = new List(); + public IReadOnlyList EnabledInstrumentations { get; private set; } = []; /// /// Gets the list of activity configurations to be added to the tracer at the startup. /// - public IList ActivitySources { get; } = new List { "OpenTelemetry.AutoInstrumentation.*" }; + public IList ActivitySources { get; } = ["OpenTelemetry.AutoInstrumentation.*"]; /// /// Gets the list of legacy configurations to be added to the tracer at the startup. /// - public IList AdditionalLegacySources { get; } = new List(); + public IList AdditionalLegacySources { get; } = []; /// /// Gets the instrumentation options. @@ -93,7 +94,51 @@ protected override void OnLoadEnvVar(Configuration configuration) InstrumentationOptions = new InstrumentationOptions(configuration); } - private static IReadOnlyList ParseTracesExporter(Configuration configuration) + protected override void OnLoadFile(YamlConfiguration configuration) + { + if (configuration.TracerProvider != null && + configuration.TracerProvider.Processors != null && + configuration.TracerProvider.Processors.TryGetValue("batch", out var batchProcessorConfig)) + { + TracesEnabled = true; + // BatchProcessorConfig = batchProcessorConfig; + var exporters = batchProcessorConfig.Exporter; + var tracesExporters = new List(); + if (exporters != null) + { + if (exporters.OtlpGrpc != null) + { + tracesExporters.Add(TracesExporter.Otlp); + OtlpSettings = new OtlpSettings(OtlpSignalType.Traces, exporters.OtlpGrpc); + } + + if (exporters.OtlpHttp != null) + { + tracesExporters.Add(TracesExporter.Otlp); + OtlpSettings = new OtlpSettings(OtlpSignalType.Traces, exporters.OtlpHttp); + } + + if (exporters.Zipkin != null) + { + tracesExporters.Add(TracesExporter.Zipkin); + // ZipkinSettings = exporters.Zipkin; + } + + if (exporters.Console != null) + { + tracesExporters.Add(TracesExporter.Console); + } + + TracesExporters = tracesExporters; + } + } + else + { + TracesEnabled = false; + } + } + + private static List ParseTracesExporter(Configuration configuration) { var tracesExporterEnvVar = configuration.GetString(ConfigurationKeys.Traces.Exporter); var exporters = new List(); From 00dda04e37ea87183b3decc9dab06893d08f27c0 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Tue, 23 Sep 2025 15:28:53 +0200 Subject: [PATCH 02/18] [FileBased] Add traces Tests --- .../FileBased/FilebasedTracesSettingsTests.cs | 226 ++++++++++++++++++ .../FileBased/Files/TestTracesFile.yaml | 15 ++ .../Files/TestTracesFileEnvVars.yaml | 12 + .../FileBased/Parser/ParserTracesTests.cs | 80 +++++++ ...Telemetry.AutoInstrumentation.Tests.csproj | 6 + 5 files changed, 339 insertions(+) create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFile.yaml create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFileEnvVars.yaml create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserTracesTests.cs diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs new file mode 100644 index 0000000000..adf9aed492 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs @@ -0,0 +1,226 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +using Xunit; + +namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; + +public class FilebasedTracesSettingsTests +{ + [Fact] + public void LoadFile_SetsBatchProcessorAndExportersCorrectly() + { + var exporter = new ExporterConfig + { + OtlpGrpc = new OtlpGrpcExporterConfig + { + Endpoint = "http://localhost:4317/" + }, + Zipkin = new ZipkinExporterConfig("http://localhost:9411/") + }; + + var batchProcessorConfig = new BatchProcessorConfig + { + ScheduleDelay = 1000, + ExportTimeout = 30000, + MaxQueueSize = 2048, + MaxExportBatchSize = 512, + Exporter = exporter + }; + + var conf = new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = new Dictionary + { + { "batch", batchProcessorConfig } + } + } + }; + + var settings = new TracerSettings(); + + settings.LoadFile(conf); + + Assert.True(settings.TracesEnabled); + Assert.Equal(2, settings.TracesExporters.Count); + Assert.Contains(TracesExporter.Otlp, settings.TracesExporters); + Assert.Contains(TracesExporter.Zipkin, settings.TracesExporters); + + Assert.NotNull(settings.OtlpSettings); + // Assert.NotNull(settings.ZipkinSettings); + + Assert.NotNull(settings.OtlpSettings.Endpoint); + Assert.Equal("http://localhost:4317/", settings.OtlpSettings.Endpoint.ToString()); + // Assert.Equal("http://localhost:9411/", settings.ZipkinSettings.Endpoint); + + // Assert.Equal(1000, settings.BatchProcessorConfig.ScheduleDelay); + // Assert.Equal(30000, settings.BatchProcessorConfig.ExportTimeout); + // Assert.Equal(2048, settings.BatchProcessorConfig.MaxQueueSize); + // Assert.Equal(512, settings.BatchProcessorConfig.MaxExportBatchSize); + } + + [Fact] + public void LoadFile_DisablesTraces_WhenNoBatchProcessorConfigured() + { + var conf = new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = [] + } + }; + + var settings = new TracerSettings(); + + settings.LoadFile(conf); + + Assert.False(settings.TracesEnabled); + Assert.Empty(settings.TracesExporters); + Assert.Null(settings.OtlpSettings); + // Assert.Null(settings.ZipkinSettings); + } + + [Fact] + public void LoadFile_SetsOtlpHttpExporterCorrectly() + { + var exporter = new ExporterConfig + { + OtlpHttp = new OtlpHttpExporterConfig + { + Endpoint = "http://localhost:4318/" + } + }; + + var batchProcessorConfig = new BatchProcessorConfig + { + Exporter = exporter + }; + + var conf = new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = new Dictionary + { + { "batch", batchProcessorConfig } + } + } + }; + + var settings = new TracerSettings(); + + settings.LoadFile(conf); + + Assert.True(settings.TracesEnabled); + Assert.Single(settings.TracesExporters); + Assert.Contains(TracesExporter.Otlp, settings.TracesExporters); + Assert.NotNull(settings.OtlpSettings); + Assert.NotNull(settings.OtlpSettings.Endpoint); + Assert.Equal("http://localhost:4318/", settings.OtlpSettings.Endpoint.ToString()); + } + + [Fact] + public void LoadFile_SetsConsoleExporterCorrectly() + { + var exporter = new ExporterConfig + { + Console = new object() + }; + + var batchProcessorConfig = new BatchProcessorConfig + { + Exporter = exporter + }; + + var conf = new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = new Dictionary + { + { "batch", batchProcessorConfig } + } + } + }; + + var settings = new TracerSettings(); + + settings.LoadFile(conf); + + Assert.True(settings.TracesEnabled); + Assert.Single(settings.TracesExporters); + Assert.Contains(TracesExporter.Console, settings.TracesExporters); + Assert.Null(settings.OtlpSettings); + // Assert.Null(settings.ZipkinSettings); + } + + [Fact] + public void LoadFile_SetsMultipleExportersCorrectly() + { + var exporter = new ExporterConfig + { + OtlpGrpc = new OtlpGrpcExporterConfig { Endpoint = "http://localhost:4317/" }, + Console = new object(), + Zipkin = new ZipkinExporterConfig("http://localhost:9411/") + }; + + var batchProcessorConfig = new BatchProcessorConfig + { + Exporter = exporter + }; + + var conf = new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = new Dictionary + { + { "batch", batchProcessorConfig } + } + } + }; + + var settings = new TracerSettings(); + + settings.LoadFile(conf); + + Assert.True(settings.TracesEnabled); + Assert.Equal(3, settings.TracesExporters.Count); + Assert.Contains(TracesExporter.Otlp, settings.TracesExporters); + Assert.Contains(TracesExporter.Console, settings.TracesExporters); + Assert.Contains(TracesExporter.Zipkin, settings.TracesExporters); + } + + [Fact] + public void LoadFile_HandlesNullExporterGracefully() + { + var batchProcessorConfig = new BatchProcessorConfig + { + Exporter = null + }; + + var conf = new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = new Dictionary + { + { "batch", batchProcessorConfig } + } + } + }; + + var settings = new TracerSettings(); + + settings.LoadFile(conf); + + Assert.True(settings.TracesEnabled); + Assert.Empty(settings.TracesExporters); + Assert.Null(settings.OtlpSettings); + // Assert.Null(settings.ZipkinSettings); + } +} diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFile.yaml new file mode 100644 index 0000000000..8b50ba567e --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFile.yaml @@ -0,0 +1,15 @@ +tracer_provider: + processors: + batch: + schedule_delay: 5000 + export_timeout: 30000 + max_queue_size: 2048 + max_export_batch_size: 512 + exporter: + otlp_http: + endpoint: http://localhost:4318/v1/traces + timeout: 10000 + headers: + - name: header1234 + value: "1234" + \ No newline at end of file diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFileEnvVars.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFileEnvVars.yaml new file mode 100644 index 0000000000..33ab57bbc3 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFileEnvVars.yaml @@ -0,0 +1,12 @@ +tracer_provider: + processors: + batch: + schedule_delay: ${OTEL_BSP_SCHEDULE_DELAY} + export_timeout: ${OTEL_BSP_EXPORT_TIMEOUT} + max_queue_size: ${OTEL_BSP_MAX_QUEUE_SIZE} + max_export_batch_size: ${OTEL_BSP_MAX_EXPORT_BATCH_SIZE} + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT} + timeout: ${OTEL_EXPORTER_OTLP_TRACES_TIMEOUT} + headers_list: ${OTEL_EXPORTER_OTLP_TRACES_HEADERS} \ No newline at end of file diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserTracesTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserTracesTests.cs new file mode 100644 index 0000000000..d61ca54fc9 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserTracesTests.cs @@ -0,0 +1,80 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Xunit; +using YamlParser = OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser.Parser; + +namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased.Parser; + +[Collection("Non-Parallel Collection")] +public class ParserTracesTests +{ + [Fact] + public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() + { + var config = YamlParser.ParseYaml("Configurations/FileBased/Files/TestTracesFile.yaml"); + Assert.NotNull(config); + + Assert.NotNull(config.TracerProvider); + Assert.NotNull(config.TracerProvider.Processors); + Assert.True(config.TracerProvider.Processors.ContainsKey("batch")); + var traceBatch = config.TracerProvider.Processors["batch"]; + Assert.NotNull(traceBatch); + + Assert.Equal(5000, traceBatch.ScheduleDelay); + Assert.Equal(30000, traceBatch.ExportTimeout); + Assert.Equal(2048, traceBatch.MaxQueueSize); + Assert.Equal(512, traceBatch.MaxExportBatchSize); + + Assert.NotNull(traceBatch.Exporter); + Assert.NotNull(traceBatch.Exporter.OtlpHttp); + var traceExporter = traceBatch.Exporter.OtlpHttp; + Assert.NotNull(traceExporter); + + Assert.Equal("http://localhost:4318/v1/traces", traceExporter.Endpoint); + Assert.Equal(10000, traceExporter.Timeout); + Assert.Null(traceExporter.HeadersList); + Assert.NotNull(traceExporter.Headers); + Assert.Single(traceExporter.Headers); + Assert.Equal("header1234", traceExporter.Headers[0].Name); + Assert.Equal("1234", traceExporter.Headers[0].Value); + } + + [Fact] + public void Parse_EnvVarYaml_ShouldPopulateModelCompletely() + { + Environment.SetEnvironmentVariable("OTEL_SDK_DISABLED", "true"); + Environment.SetEnvironmentVariable("OTEL_BSP_SCHEDULE_DELAY", "7000"); + Environment.SetEnvironmentVariable("OTEL_BSP_EXPORT_TIMEOUT", "35000"); + Environment.SetEnvironmentVariable("OTEL_BSP_MAX_QUEUE_SIZE", "4096"); + Environment.SetEnvironmentVariable("OTEL_BSP_MAX_EXPORT_BATCH_SIZE", "1024"); + Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", "http://collector:4318/v1/traces"); + Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_TRACES_TIMEOUT", "15000"); + Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_TRACES_HEADERS", "header1=value1,header2=value2"); + + var config = YamlParser.ParseYaml("Configurations/FileBased/Files/TestTracesFileEnvVars.yaml"); + Assert.NotNull(config); + + Assert.NotNull(config.TracerProvider); + Assert.NotNull(config.TracerProvider.Processors); + Assert.True(config.TracerProvider.Processors.ContainsKey("batch")); + var traceBatch = config.TracerProvider.Processors["batch"]; + Assert.NotNull(traceBatch); + + Assert.NotNull(traceBatch.Exporter); + Assert.NotNull(traceBatch.Exporter.OtlpHttp); + var traceExporter = traceBatch.Exporter.OtlpHttp; + Assert.NotNull(traceExporter); + + Assert.Equal(7000, traceBatch.ScheduleDelay); + Assert.Equal(35000, traceBatch.ExportTimeout); + Assert.Equal(4096, traceBatch.MaxQueueSize); + Assert.Equal(1024, traceBatch.MaxExportBatchSize); + + Assert.Equal("http://collector:4318/v1/traces", traceExporter.Endpoint); + Assert.Equal(15000, traceBatch.Exporter.OtlpHttp.Timeout); + Assert.Null(traceExporter.Headers); + Assert.NotNull(traceExporter.HeadersList); + Assert.Equal("header1=value1,header2=value2", traceExporter.HeadersList); + } +} diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj b/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj index 50c9bfa3f0..feabb7981a 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj @@ -12,9 +12,15 @@ + + PreserveNewest + PreserveNewest + + PreserveNewest + PreserveNewest From d6ec27ab2705e5c775e847aeb6184fe9d6221093 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Mon, 29 Sep 2025 09:41:40 +0200 Subject: [PATCH 03/18] [File-Based] Add Batch options --- .../EnvironmentConfigurationTracerHelper.cs | 15 +++++-- .../BatchProcessorConfig.cs | 45 +++---------------- .../ZipkinExporterConfig.cs | 18 +++----- .../Configurations/TracerSettings.cs | 8 +++- .../FileBased/FilebasedTracesSettingsTests.cs | 29 +++++++----- 5 files changed, 48 insertions(+), 67 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs index a57cce88df..553c3f5c29 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs @@ -4,6 +4,7 @@ using System.Runtime.CompilerServices; using OpenTelemetry.AutoInstrumentation.Loading; using OpenTelemetry.AutoInstrumentation.Plugins; +using OpenTelemetry.Exporter; using OpenTelemetry.Trace; namespace OpenTelemetry.AutoInstrumentation.Configurations; @@ -92,7 +93,7 @@ private static TracerProviderBuilder SetExporter(this TracerProviderBuilder buil { builder = traceExporter switch { - TracesExporter.Zipkin => Wrappers.AddZipkinExporter(builder, pluginManager), + TracesExporter.Zipkin => Wrappers.AddZipkinExporter(builder, settings, pluginManager), TracesExporter.Otlp => Wrappers.AddOtlpExporter(builder, settings, pluginManager), TracesExporter.Console => Wrappers.AddConsoleExporter(builder, pluginManager), _ => throw new ArgumentOutOfRangeException($"Traces exporter '{traceExporter}' is incorrect") @@ -218,9 +219,16 @@ public static TracerProviderBuilder AddConsoleExporter(TracerProviderBuilder bui } [MethodImpl(MethodImplOptions.NoInlining)] - public static TracerProviderBuilder AddZipkinExporter(TracerProviderBuilder builder, PluginManager pluginManager) + public static TracerProviderBuilder AddZipkinExporter(TracerProviderBuilder builder, TracerSettings settings, PluginManager pluginManager) { - return builder.AddZipkinExporter(pluginManager.ConfigureTracesOptions); + return builder.AddZipkinExporter(options => + { + // Copy Auto settings to SDK settings + settings.BatchProcessorConfig?.CopyTo(options.BatchExportProcessorOptions); + settings.ZipkinSettings?.CopyTo(options); + + pluginManager.ConfigureTracesOptions(options); + }); } [MethodImpl(MethodImplOptions.NoInlining)] @@ -229,6 +237,7 @@ public static TracerProviderBuilder AddOtlpExporter(TracerProviderBuilder builde return builder.AddOtlpExporter(options => { // Copy Auto settings to SDK settings + settings.BatchProcessorConfig?.CopyTo(options.BatchExportProcessorOptions); settings.OtlpSettings?.CopyTo(options); pluginManager.ConfigureTracesOptions(options); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs index 0a0095e8db..46f94a5ecb 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs @@ -2,43 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 using System.Diagnostics; +using OpenTelemetry.Exporter; using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; internal class BatchProcessorConfig { - public BatchProcessorConfig() - { - } - - public BatchProcessorConfig( - int? scheduleDelay = null, - int? exportTimeout = null, - int? maxQueueSize = null, - int? maxExportBatchSize = null) - { - if (scheduleDelay is not null) - { - ScheduleDelay = scheduleDelay.Value; - } - - if (exportTimeout is not null) - { - ExportTimeout = exportTimeout.Value; - } - - if (maxQueueSize is not null) - { - MaxQueueSize = maxQueueSize.Value; - } - - if (maxExportBatchSize is not null) - { - MaxExportBatchSize = maxExportBatchSize.Value; - } - } - /// /// Gets or sets the delay interval (in milliseconds) between two consecutive exports. /// Value must be non-negative. @@ -77,14 +47,11 @@ public BatchProcessorConfig( [YamlMember(Alias = "exporter")] public ExporterConfig? Exporter { get; set; } - public BatchExportProcessorOptions ToBatchExportProcessorOptions() + public void CopyTo(BatchExportProcessorOptions options) { - return new BatchExportProcessorOptions - { - ScheduledDelayMilliseconds = this.ScheduleDelay, - ExporterTimeoutMilliseconds = this.ExportTimeout, - MaxQueueSize = this.MaxQueueSize, - MaxExportBatchSize = this.MaxExportBatchSize - }; + options.ScheduledDelayMilliseconds = ScheduleDelay; + options.ExporterTimeoutMilliseconds = ExportTimeout; + options.MaxQueueSize = MaxQueueSize; + options.MaxExportBatchSize = MaxExportBatchSize; } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs index 45fafd8429..bf53cce689 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs @@ -1,28 +1,22 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.Exporter; using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; internal class ZipkinExporterConfig { - public ZipkinExporterConfig() - { - } - - public ZipkinExporterConfig(string? endpoint) - { - if (endpoint is not null) - { - Endpoint = endpoint; - } - } - /// /// Gets or sets the Zipkin endpoint URL to which spans are exported. /// If omitted or null, the default value "http://localhost:9411/api/v2/spans" is used. /// [YamlMember(Alias = "endpoint")] public string Endpoint { get; set; } = "http://localhost:9411/api/v2/spans"; + + public void CopyTo(ZipkinExporterOptions options) + { + options.Endpoint = new Uri(Endpoint); + } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs index d7d72239a8..98d1988a2f 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs @@ -54,6 +54,10 @@ internal class TracerSettings : Settings /// public OtlpSettings? OtlpSettings { get; private set; } + public BatchProcessorConfig? BatchProcessorConfig { get; private set; } = null; + + public ZipkinExporterConfig? ZipkinSettings { get; private set; } = null; + protected override void OnLoadEnvVar(Configuration configuration) { TracesExporters = ParseTracesExporter(configuration); @@ -101,7 +105,7 @@ protected override void OnLoadFile(YamlConfiguration configuration) configuration.TracerProvider.Processors.TryGetValue("batch", out var batchProcessorConfig)) { TracesEnabled = true; - // BatchProcessorConfig = batchProcessorConfig; + BatchProcessorConfig = batchProcessorConfig; var exporters = batchProcessorConfig.Exporter; var tracesExporters = new List(); if (exporters != null) @@ -121,7 +125,7 @@ protected override void OnLoadFile(YamlConfiguration configuration) if (exporters.Zipkin != null) { tracesExporters.Add(TracesExporter.Zipkin); - // ZipkinSettings = exporters.Zipkin; + ZipkinSettings = exporters.Zipkin; } if (exporters.Console != null) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs index adf9aed492..88422a7315 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs @@ -18,7 +18,10 @@ public void LoadFile_SetsBatchProcessorAndExportersCorrectly() { Endpoint = "http://localhost:4317/" }, - Zipkin = new ZipkinExporterConfig("http://localhost:9411/") + Zipkin = new ZipkinExporterConfig + { + Endpoint = "http://localhost:9411/" + }, }; var batchProcessorConfig = new BatchProcessorConfig @@ -51,16 +54,17 @@ public void LoadFile_SetsBatchProcessorAndExportersCorrectly() Assert.Contains(TracesExporter.Zipkin, settings.TracesExporters); Assert.NotNull(settings.OtlpSettings); - // Assert.NotNull(settings.ZipkinSettings); + Assert.NotNull(settings.ZipkinSettings); Assert.NotNull(settings.OtlpSettings.Endpoint); Assert.Equal("http://localhost:4317/", settings.OtlpSettings.Endpoint.ToString()); - // Assert.Equal("http://localhost:9411/", settings.ZipkinSettings.Endpoint); + Assert.Equal("http://localhost:9411/", settings.ZipkinSettings.Endpoint); - // Assert.Equal(1000, settings.BatchProcessorConfig.ScheduleDelay); - // Assert.Equal(30000, settings.BatchProcessorConfig.ExportTimeout); - // Assert.Equal(2048, settings.BatchProcessorConfig.MaxQueueSize); - // Assert.Equal(512, settings.BatchProcessorConfig.MaxExportBatchSize); + Assert.NotNull(settings.BatchProcessorConfig); + Assert.Equal(1000, settings.BatchProcessorConfig.ScheduleDelay); + Assert.Equal(30000, settings.BatchProcessorConfig.ExportTimeout); + Assert.Equal(2048, settings.BatchProcessorConfig.MaxQueueSize); + Assert.Equal(512, settings.BatchProcessorConfig.MaxExportBatchSize); } [Fact] @@ -81,7 +85,7 @@ public void LoadFile_DisablesTraces_WhenNoBatchProcessorConfigured() Assert.False(settings.TracesEnabled); Assert.Empty(settings.TracesExporters); Assert.Null(settings.OtlpSettings); - // Assert.Null(settings.ZipkinSettings); + Assert.Null(settings.ZipkinSettings); } [Fact] @@ -155,7 +159,7 @@ public void LoadFile_SetsConsoleExporterCorrectly() Assert.Single(settings.TracesExporters); Assert.Contains(TracesExporter.Console, settings.TracesExporters); Assert.Null(settings.OtlpSettings); - // Assert.Null(settings.ZipkinSettings); + Assert.Null(settings.ZipkinSettings); } [Fact] @@ -165,7 +169,10 @@ public void LoadFile_SetsMultipleExportersCorrectly() { OtlpGrpc = new OtlpGrpcExporterConfig { Endpoint = "http://localhost:4317/" }, Console = new object(), - Zipkin = new ZipkinExporterConfig("http://localhost:9411/") + Zipkin = new ZipkinExporterConfig + { + Endpoint = "http://localhost:9411/" + }, }; var batchProcessorConfig = new BatchProcessorConfig @@ -221,6 +228,6 @@ public void LoadFile_HandlesNullExporterGracefully() Assert.True(settings.TracesEnabled); Assert.Empty(settings.TracesExporters); Assert.Null(settings.OtlpSettings); - // Assert.Null(settings.ZipkinSettings); + Assert.Null(settings.ZipkinSettings); } } From d35c3758e0412439f869bea8ba2449f607e0c8ce Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Tue, 30 Sep 2025 10:59:28 +0200 Subject: [PATCH 04/18] [File-Based] Add Tracer Provider Docs --- docs/file-based-configuration.md | 59 +++++++++++++++++++ .../Configurations/TracerSettings.cs | 10 ++++ 2 files changed, 69 insertions(+) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index 9ef632ca60..d615031f81 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -30,6 +30,65 @@ For more details, see: [OpenTelemetry YAML File Format Specification](https://gi ## Configuration Examples +### Tracer Provider Configuration + +``` yaml +tracer_provider: + processors: + # Configure a batch span processor. + batch: + # Configure delay interval (in milliseconds) between two consecutive exports. + # Value must be non-negative. + # If omitted or null, 5000 is used. + schedule_delay: 5000 + # Configure maximum allowed time (in milliseconds) to export data. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 30000 is used. + export_timeout: 30000 + # Configure maximum queue size. Value must be positive. + # If omitted or null, 2048 is used. + max_queue_size: 2048 + # Configure maximum batch size. Value must be positive. + # If omitted or null, 512 is used. + max_export_batch_size: 512 + # Configure exporters. + exporter: + # Configure the OTLP with HTTP transport exporter to enable it. + otlp_http: + # Configure endpoint, including the trace specific path. + # If omitted or null, http://localhost:4318/v1/traces is used + endpoint: http://localhost:4318/v1/traces + # Configure max time (in milliseconds) to wait for each export. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 10000 is used. + timeout: 10000 + # Configure headers. Entries have higher priority than entries from .headers_list. + # If an entry's .value is null, the entry is ignored. + headers: + - name: api-key + value: "1234" + # Configure headers. Entries have lower priority than entries from .headers. + # The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + # If omitted or null, no headers are added. + headers_list: ${OTEL_EXPORTER_OTLP_TRACES_HEADERS} + # Configure the OTLP with gRPC transport exporter to enable it. + otlp_grpc: + # Configuration otlp_grpc is the same as otlp_http. + # if otlp_http is used it will override otlp_grpc. + # On .NET Framework, the grpc OTLP exporter protocol is not supported. + # Configure the zipkin exporter to enable it. + zipkin: + # Configure endpoint. + # If omitted or null, http://localhost:9411/api/v2/spans is used. + endpoint: http://localhost:9411/api/v2/spans + # Configure max time (in milliseconds) to wait for each export. + # Value must be non-negative. A value of 0 indicates indefinite. + # If omitted or null, 10000 is used. + timeout: 10000 + # Add the console exporter to enable it. + console: +``` + ### Resource Configuration You can configure resource attributes directly in YAML or via the diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs index 98d1988a2f..47122b991e 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs @@ -54,8 +54,18 @@ internal class TracerSettings : Settings /// public OtlpSettings? OtlpSettings { get; private set; } + /// + /// Gets tracing Batch Processor Configuration. + /// For environment variable configuration, this must be null, + /// and the configuration will be handled inside the Otlp exporter package. + /// public BatchProcessorConfig? BatchProcessorConfig { get; private set; } = null; + /// + /// Gets the tracing Zipkin settings. + /// For environment variable configuration, this must be null, + /// and the configuration will be handled inside the Zipkin exporter package. + /// public ZipkinExporterConfig? ZipkinSettings { get; private set; } = null; protected override void OnLoadEnvVar(Configuration configuration) From bee1a0c6cd3be97bc0363137a1308a195af53676 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Tue, 30 Sep 2025 11:06:06 +0200 Subject: [PATCH 05/18] fix docs --- docs/file-based-configuration.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index d615031f81..08a9353d7b 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -81,10 +81,6 @@ tracer_provider: # Configure endpoint. # If omitted or null, http://localhost:9411/api/v2/spans is used. endpoint: http://localhost:9411/api/v2/spans - # Configure max time (in milliseconds) to wait for each export. - # Value must be non-negative. A value of 0 indicates indefinite. - # If omitted or null, 10000 is used. - timeout: 10000 # Add the console exporter to enable it. console: ``` From afd0ece6ca026907c44cb4300ecbd85ffee54053 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Mon, 13 Oct 2025 09:18:23 +0200 Subject: [PATCH 06/18] Add note about multiple processor support --- docs/file-based-configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index ad70b906fb..dad3d56f44 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -55,6 +55,7 @@ flush_on_unhandled_exception: false tracer_provider: processors: # Configure a batch span processor. + # Support for multiple processors is not available yet (which does not comply with the specification). batch: # Configure delay interval (in milliseconds) between two consecutive exports. # Value must be non-negative. From 6ad3fbcca8c5db59992600b69d80cb24143845f3 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Mon, 13 Oct 2025 10:15:34 +0200 Subject: [PATCH 07/18] fix no_code --- .../Helpers/MockSpansCollector.cs | 11 ++++++ .../Helpers/TestHttpServer.AspNetCore.cs | 35 +++++++++++++++++++ .../Helpers/TestHttpServer.NetFramework.cs | 17 +++++++++ test/IntegrationTests/NoCodeTests.cs | 2 +- .../TestApplication.NoCode/config.yaml | 7 ++++ 5 files changed, 71 insertions(+), 1 deletion(-) diff --git a/test/IntegrationTests/Helpers/MockSpansCollector.cs b/test/IntegrationTests/Helpers/MockSpansCollector.cs index 64b10ece25..c9d5f91a65 100644 --- a/test/IntegrationTests/Helpers/MockSpansCollector.cs +++ b/test/IntegrationTests/Helpers/MockSpansCollector.cs @@ -35,6 +35,17 @@ public MockSpansCollector(ITestOutputHelper output, string host = "localhost") #endif } + public MockSpansCollector(ITestOutputHelper output, int port, string host = "localhost") + { + _output = output; + +#if NETFRAMEWORK + _listener = new TestHttpServer(output, HandleHttpRequests, host, port, "/v1/traces/"); +#else + _listener = new TestHttpServer(output, nameof(MockSpansCollector), port, new PathHandler(HandleHttpRequests, "/v1/traces")); +#endif + } + /// /// Gets the TCP port that this collector is listening on. /// diff --git a/test/IntegrationTests/Helpers/TestHttpServer.AspNetCore.cs b/test/IntegrationTests/Helpers/TestHttpServer.AspNetCore.cs index 2284a35cff..da57c1136a 100644 --- a/test/IntegrationTests/Helpers/TestHttpServer.AspNetCore.cs +++ b/test/IntegrationTests/Helpers/TestHttpServer.AspNetCore.cs @@ -56,6 +56,41 @@ public TestHttpServer(ITestOutputHelper output, string name, params PathHandler[ WriteOutput($"Listening on: {string.Join(',', pathHandlers.Select(handler => $"{address}{handler.Path}"))}"); } + public TestHttpServer(ITestOutputHelper output, string name, int port, params PathHandler[] pathHandlers) + { + _output = output; + _name = name; + Port = port; + + _listener = new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseKestrel(options => + options.Listen(IPAddress.Loopback, port)) + .Configure(x => + { + foreach (var pathHandler in pathHandlers) + { + x.Map(pathHandler.Path, x => + { + x.Run(pathHandler.Delegate); + }); + } + }); + }) + .Build(); + + _listener.Start(); + + var server = _listener.Services.GetRequiredService(); + var address = server.Features + .Get()! + .Addresses + .First(); + WriteOutput($"Listening on: {string.Join(',', pathHandlers.Select(handler => $"{address}{handler.Path}"))}"); + } + /// /// Gets the TCP port that this listener is listening on. /// diff --git a/test/IntegrationTests/Helpers/TestHttpServer.NetFramework.cs b/test/IntegrationTests/Helpers/TestHttpServer.NetFramework.cs index b0eadb7398..59e669b70c 100644 --- a/test/IntegrationTests/Helpers/TestHttpServer.NetFramework.cs +++ b/test/IntegrationTests/Helpers/TestHttpServer.NetFramework.cs @@ -32,6 +32,23 @@ public TestHttpServer(ITestOutputHelper output, Action requ _listenerThread.Start(); } + public TestHttpServer(ITestOutputHelper output, Action requestHandler, string host, int port, string sufix = "/") + { + _output = output; + _requestHandler = requestHandler; + + Port = port; + + _listener = new HttpListener(); + _listener.Start(); + var prefix = new UriBuilder("http", host, port, sufix).ToString(); // See https://docs.microsoft.com/en-us/dotnet/api/system.net.httplistenerprefixcollection.add?redirectedfrom=MSDN&view=net-6.0#remarks for info about the host value. + _listener.Prefixes.Add(prefix); + WriteOutput($"Listening on '{prefix}'"); + + _listenerThread = new Thread(HandleHttpRequests); + _listenerThread.Start(); + } + /// /// Gets the TCP port that this listener is listening on. /// diff --git a/test/IntegrationTests/NoCodeTests.cs b/test/IntegrationTests/NoCodeTests.cs index 8dfd03f9e7..f6de2e8aed 100644 --- a/test/IntegrationTests/NoCodeTests.cs +++ b/test/IntegrationTests/NoCodeTests.cs @@ -21,7 +21,7 @@ public void SubmitsTraces() { EnableBytecodeInstrumentation(); EnableFileBasedConfigWithDefaultPath(); - using var collector = new MockSpansCollector(Output); + using var collector = new MockSpansCollector(Output, 4318); SetExporter(collector); List allTypeOfAttributes = [ diff --git a/test/test-applications/integrations/TestApplication.NoCode/config.yaml b/test/test-applications/integrations/TestApplication.NoCode/config.yaml index 9e37a9b8aa..dd2acfc29e 100644 --- a/test/test-applications/integrations/TestApplication.NoCode/config.yaml +++ b/test/test-applications/integrations/TestApplication.NoCode/config.yaml @@ -1,5 +1,12 @@ file_format: "1.0-rc.1" +tracer_provider: + processors: + batch: + exporter: + otlp_http: + endpoint: http://localhost:4318/v1/traces + no_code/development: targets: - target: From 56eb56c9ebca0ea4082e11655cf0c6abcf409b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Tue, 14 Oct 2025 07:18:45 +0200 Subject: [PATCH 08/18] remove redundant usings --- .../FileBasedConfiguration/BatchProcessorConfig.cs | 1 - .../FileBasedConfiguration/OtlpHttpExporterConfig.cs | 1 - .../Configurations/FileBasedConfiguration/YamlConfiguration.cs | 1 - 3 files changed, 3 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs index 46f94a5ecb..5153965572 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 using System.Diagnostics; -using OpenTelemetry.Exporter; using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs index 74a624882e..db4515148d 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs @@ -1,7 +1,6 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using System.Diagnostics; using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs index 6f9ae02461..11502f813a 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs @@ -1,7 +1,6 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using System.Diagnostics; using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; From 89c9f2beddb7ca083edf95405f4ae433e7c18ae6 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Tue, 14 Oct 2025 13:21:41 +0200 Subject: [PATCH 09/18] refactor tests --- .../Helpers/MockSpansCollector.cs | 11 ------ .../Helpers/TestHttpServer.AspNetCore.cs | 35 ------------------- .../Helpers/TestHttpServer.NetFramework.cs | 17 --------- test/IntegrationTests/NoCodeTests.cs | 2 +- .../TestApplication.NoCode/config.yaml | 2 +- 5 files changed, 2 insertions(+), 65 deletions(-) diff --git a/test/IntegrationTests/Helpers/MockSpansCollector.cs b/test/IntegrationTests/Helpers/MockSpansCollector.cs index c9d5f91a65..64b10ece25 100644 --- a/test/IntegrationTests/Helpers/MockSpansCollector.cs +++ b/test/IntegrationTests/Helpers/MockSpansCollector.cs @@ -35,17 +35,6 @@ public MockSpansCollector(ITestOutputHelper output, string host = "localhost") #endif } - public MockSpansCollector(ITestOutputHelper output, int port, string host = "localhost") - { - _output = output; - -#if NETFRAMEWORK - _listener = new TestHttpServer(output, HandleHttpRequests, host, port, "/v1/traces/"); -#else - _listener = new TestHttpServer(output, nameof(MockSpansCollector), port, new PathHandler(HandleHttpRequests, "/v1/traces")); -#endif - } - /// /// Gets the TCP port that this collector is listening on. /// diff --git a/test/IntegrationTests/Helpers/TestHttpServer.AspNetCore.cs b/test/IntegrationTests/Helpers/TestHttpServer.AspNetCore.cs index da57c1136a..2284a35cff 100644 --- a/test/IntegrationTests/Helpers/TestHttpServer.AspNetCore.cs +++ b/test/IntegrationTests/Helpers/TestHttpServer.AspNetCore.cs @@ -56,41 +56,6 @@ public TestHttpServer(ITestOutputHelper output, string name, params PathHandler[ WriteOutput($"Listening on: {string.Join(',', pathHandlers.Select(handler => $"{address}{handler.Path}"))}"); } - public TestHttpServer(ITestOutputHelper output, string name, int port, params PathHandler[] pathHandlers) - { - _output = output; - _name = name; - Port = port; - - _listener = new HostBuilder() - .ConfigureWebHost(webHostBuilder => - { - webHostBuilder - .UseKestrel(options => - options.Listen(IPAddress.Loopback, port)) - .Configure(x => - { - foreach (var pathHandler in pathHandlers) - { - x.Map(pathHandler.Path, x => - { - x.Run(pathHandler.Delegate); - }); - } - }); - }) - .Build(); - - _listener.Start(); - - var server = _listener.Services.GetRequiredService(); - var address = server.Features - .Get()! - .Addresses - .First(); - WriteOutput($"Listening on: {string.Join(',', pathHandlers.Select(handler => $"{address}{handler.Path}"))}"); - } - /// /// Gets the TCP port that this listener is listening on. /// diff --git a/test/IntegrationTests/Helpers/TestHttpServer.NetFramework.cs b/test/IntegrationTests/Helpers/TestHttpServer.NetFramework.cs index 59e669b70c..b0eadb7398 100644 --- a/test/IntegrationTests/Helpers/TestHttpServer.NetFramework.cs +++ b/test/IntegrationTests/Helpers/TestHttpServer.NetFramework.cs @@ -32,23 +32,6 @@ public TestHttpServer(ITestOutputHelper output, Action requ _listenerThread.Start(); } - public TestHttpServer(ITestOutputHelper output, Action requestHandler, string host, int port, string sufix = "/") - { - _output = output; - _requestHandler = requestHandler; - - Port = port; - - _listener = new HttpListener(); - _listener.Start(); - var prefix = new UriBuilder("http", host, port, sufix).ToString(); // See https://docs.microsoft.com/en-us/dotnet/api/system.net.httplistenerprefixcollection.add?redirectedfrom=MSDN&view=net-6.0#remarks for info about the host value. - _listener.Prefixes.Add(prefix); - WriteOutput($"Listening on '{prefix}'"); - - _listenerThread = new Thread(HandleHttpRequests); - _listenerThread.Start(); - } - /// /// Gets the TCP port that this listener is listening on. /// diff --git a/test/IntegrationTests/NoCodeTests.cs b/test/IntegrationTests/NoCodeTests.cs index f6de2e8aed..8dfd03f9e7 100644 --- a/test/IntegrationTests/NoCodeTests.cs +++ b/test/IntegrationTests/NoCodeTests.cs @@ -21,7 +21,7 @@ public void SubmitsTraces() { EnableBytecodeInstrumentation(); EnableFileBasedConfigWithDefaultPath(); - using var collector = new MockSpansCollector(Output, 4318); + using var collector = new MockSpansCollector(Output); SetExporter(collector); List allTypeOfAttributes = [ diff --git a/test/test-applications/integrations/TestApplication.NoCode/config.yaml b/test/test-applications/integrations/TestApplication.NoCode/config.yaml index dd2acfc29e..2e10e49ce5 100644 --- a/test/test-applications/integrations/TestApplication.NoCode/config.yaml +++ b/test/test-applications/integrations/TestApplication.NoCode/config.yaml @@ -5,7 +5,7 @@ tracer_provider: batch: exporter: otlp_http: - endpoint: http://localhost:4318/v1/traces + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT} no_code/development: targets: From 90590b86a71288c690071b680410fb89c089b688 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 15 Oct 2025 13:04:19 +0200 Subject: [PATCH 10/18] [File Based] accept multiple processors --- .../EnvironmentConfigurationTracerHelper.cs | 168 ++++++++++++++++-- .../OtlpGrpcExporterConfig.cs | 2 +- .../OtlpHttpExporterConfig.cs | 2 +- .../FileBasedConfiguration/ProcessorConfig.cs | 15 ++ .../SimpleProcessorConfig.cs | 12 ++ .../TracerProviderConfiguration.cs | 2 +- .../Configurations/Otlp/OtlpSettings.cs | 27 ++- .../Configurations/TracerSettings.cs | 56 +----- .../FileBased/FilebasedTracesSettingsTests.cs | 3 + .../FileBased/Files/TestTracesFile.yaml | 37 ++-- .../Files/TestTracesFileEnvVars.yaml | 20 +-- .../FileBased/Parser/ParserTracesTests.cs | 30 +++- 12 files changed, 278 insertions(+), 96 deletions(-) create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ProcessorConfig.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SimpleProcessorConfig.cs diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs index 97e1e2c800..2d8437c12c 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs @@ -2,15 +2,19 @@ // SPDX-License-Identifier: Apache-2.0 using System.Runtime.CompilerServices; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +using OpenTelemetry.AutoInstrumentation.Configurations.Otlp; using OpenTelemetry.AutoInstrumentation.Loading; +using OpenTelemetry.AutoInstrumentation.Logging; using OpenTelemetry.AutoInstrumentation.Plugins; -using OpenTelemetry.Exporter; using OpenTelemetry.Trace; namespace OpenTelemetry.AutoInstrumentation.Configurations; internal static class EnvironmentConfigurationTracerHelper { + private static readonly IOtelLogger Logger = OtelLogging.GetLogger(); + public static TracerProviderBuilder UseEnvironmentVariables( this TracerProviderBuilder builder, LazyInstrumentationLoader lazyInstrumentationLoader, @@ -89,15 +93,78 @@ private static TracerProviderBuilder AddWcfIfNeeded( private static TracerProviderBuilder SetExporter(this TracerProviderBuilder builder, TracerSettings settings, PluginManager pluginManager) { - foreach (var traceExporter in settings.TracesExporters) + // If no exporters are specified, it means to use processors (file-based configuration). + if (settings.TracesExporters.Count == 0) { - builder = traceExporter switch + if (settings.Processors != null) { - TracesExporter.Zipkin => Wrappers.AddZipkinExporter(builder, settings, pluginManager), - TracesExporter.Otlp => Wrappers.AddOtlpExporter(builder, settings, pluginManager), - TracesExporter.Console => Wrappers.AddConsoleExporter(builder, pluginManager), - _ => throw new ArgumentOutOfRangeException($"Traces exporter '{traceExporter}' is incorrect") - }; + foreach (var processor in settings.Processors) + { + if (processor.Batch != null) + { + var exporerter = processor.Batch.Exporter; + if (exporerter != null) + { + if (exporerter.OtlpHttp != null) + { + builder = Wrappers.AddOtlpHttpExporter(builder, pluginManager, processor.Batch, exporerter.OtlpHttp); + } + else if (exporerter.OtlpGrpc != null) + { + builder = Wrappers.AddOtlpGrpcExporter(builder, pluginManager, processor.Batch, exporerter.OtlpGrpc); + } + else if (exporerter.Zipkin != null) + { + builder = Wrappers.AddZipkinExporter(builder, pluginManager, processor.Batch, exporerter.Zipkin); + } + else + { + Logger.Debug("No valid exporter configured for batch processor, skipping."); + } + } + } + else if (processor.Simple != null) + { + var exporerter = processor.Simple.Exporter; + if (exporerter != null) + { + if (exporerter.OtlpHttp != null) + { + builder = Wrappers.AddOtlpHttpExporter(builder, pluginManager, exporerter.OtlpHttp); + } + else if (exporerter.OtlpGrpc != null) + { + builder = Wrappers.AddOtlpGrpcExporter(builder, pluginManager, exporerter.OtlpGrpc); + } + else if (exporerter.Zipkin != null) + { + builder = Wrappers.AddZipkinExporter(builder, pluginManager, exporerter.Zipkin); + } + else if (exporerter.Console != null) + { + builder = Wrappers.AddConsoleExporter(builder, pluginManager); + } + else + { + Logger.Debug("No valid exporter configured for simple processor, skipping."); + } + } + } + } + } + } + else + { + foreach (var traceExporter in settings.TracesExporters) + { + builder = traceExporter switch + { + TracesExporter.Zipkin => Wrappers.AddZipkinExporter(builder, pluginManager), + TracesExporter.Otlp => Wrappers.AddOtlpExporter(builder, settings, pluginManager), + TracesExporter.Console => Wrappers.AddConsoleExporter(builder, pluginManager), + _ => throw new ArgumentOutOfRangeException($"Traces exporter '{traceExporter}' is incorrect") + }; + } } return builder; @@ -219,26 +286,99 @@ public static TracerProviderBuilder AddConsoleExporter(TracerProviderBuilder bui } [MethodImpl(MethodImplOptions.NoInlining)] - public static TracerProviderBuilder AddZipkinExporter(TracerProviderBuilder builder, TracerSettings settings, PluginManager pluginManager) + public static TracerProviderBuilder AddZipkinExporter(TracerProviderBuilder builder, PluginManager pluginManager) + { + return builder.AddZipkinExporter(pluginManager.ConfigureTracesOptions); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static TracerProviderBuilder AddOtlpExporter(TracerProviderBuilder builder, TracerSettings settings, PluginManager pluginManager) + { + return builder.AddOtlpExporter(options => + { + settings.OtlpSettings?.CopyTo(options); + + pluginManager.ConfigureTracesOptions(options); + }); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static TracerProviderBuilder AddOtlpHttpExporter(TracerProviderBuilder builder, PluginManager pluginManager, BatchProcessorConfig batch, OtlpHttpExporterConfig otlpHttp) + { + var otlpSettings = new OtlpSettings(OtlpSignalType.Traces, otlpHttp); + return builder.AddOtlpExporter(options => + { + // Copy Auto settings to SDK settings + batch?.CopyTo(options.BatchExportProcessorOptions); + otlpSettings?.CopyTo(options); + + pluginManager.ConfigureTracesOptions(options); + }); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static TracerProviderBuilder AddOtlpGrpcExporter(TracerProviderBuilder builder, PluginManager pluginManager, BatchProcessorConfig batch, OtlpGrpcExporterConfig otlpGrpc) + { + var otlpSettings = new OtlpSettings(otlpGrpc); + return builder.AddOtlpExporter(options => + { + // Copy Auto settings to SDK settings + batch?.CopyTo(options.BatchExportProcessorOptions); + otlpSettings?.CopyTo(options); + + pluginManager.ConfigureTracesOptions(options); + }); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static TracerProviderBuilder AddZipkinExporter(TracerProviderBuilder builder, PluginManager pluginManager, BatchProcessorConfig batch, ZipkinExporterConfig zipkin) { return builder.AddZipkinExporter(options => { // Copy Auto settings to SDK settings - settings.BatchProcessorConfig?.CopyTo(options.BatchExportProcessorOptions); - settings.ZipkinSettings?.CopyTo(options); + batch?.CopyTo(options.BatchExportProcessorOptions); + zipkin?.CopyTo(options); pluginManager.ConfigureTracesOptions(options); }); } [MethodImpl(MethodImplOptions.NoInlining)] - public static TracerProviderBuilder AddOtlpExporter(TracerProviderBuilder builder, TracerSettings settings, PluginManager pluginManager) + public static TracerProviderBuilder AddOtlpHttpExporter(TracerProviderBuilder builder, PluginManager pluginManager, OtlpHttpExporterConfig otlpHttp) { + var otlpSettings = new OtlpSettings(OtlpSignalType.Traces, otlpHttp); return builder.AddOtlpExporter(options => { // Copy Auto settings to SDK settings - settings.BatchProcessorConfig?.CopyTo(options.BatchExportProcessorOptions); - settings.OtlpSettings?.CopyTo(options); + options.ExportProcessorType = ExportProcessorType.Simple; + otlpSettings?.CopyTo(options); + + pluginManager.ConfigureTracesOptions(options); + }); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static TracerProviderBuilder AddOtlpGrpcExporter(TracerProviderBuilder builder, PluginManager pluginManager, OtlpGrpcExporterConfig otlpGrpc) + { + var otlpSettings = new OtlpSettings(otlpGrpc); + return builder.AddOtlpExporter(options => + { + // Copy Auto settings to SDK settings + options.ExportProcessorType = ExportProcessorType.Simple; + otlpSettings?.CopyTo(options); + + pluginManager.ConfigureTracesOptions(options); + }); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static TracerProviderBuilder AddZipkinExporter(TracerProviderBuilder builder, PluginManager pluginManager, ZipkinExporterConfig zipkin) + { + return builder.AddZipkinExporter(options => + { + // Copy Auto settings to SDK settings + options.ExportProcessorType = ExportProcessorType.Simple; + zipkin?.CopyTo(options); pluginManager.ConfigureTracesOptions(options); }); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs index c625f53bd6..fde622939f 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs @@ -13,7 +13,7 @@ internal class OtlpGrpcExporterConfig /// If omitted or null, http://localhost:4317 is used. /// [YamlMember(Alias = "endpoint")] - public string? Endpoint { get; set; } + public string Endpoint { get; set; } = "http://localhost:4317"; /// /// Gets or sets the headers for the exporter. diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs index db4515148d..1e6ada71b2 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs @@ -10,7 +10,7 @@ internal class OtlpHttpExporterConfig /// /// Gets or sets the endpoint for the OTLP HTTP exporter. /// Configure endpoint. - /// If omitted or null, http://localhost:4318 is used. + /// If omitted or null, http://localhost:4318/v1/signal will be is used. /// [YamlMember(Alias = "endpoint")] public string? Endpoint { get; set; } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ProcessorConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ProcessorConfig.cs new file mode 100644 index 0000000000..b4cc8bdf1c --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ProcessorConfig.cs @@ -0,0 +1,15 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class ProcessorConfig +{ + [YamlMember(Alias = "batch")] + public BatchProcessorConfig Batch { get; set; } = new(); + + [YamlMember(Alias = "simple")] + public SimpleProcessorConfig Simple { get; set; } = new(); +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SimpleProcessorConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SimpleProcessorConfig.cs new file mode 100644 index 0000000000..07bc89b239 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SimpleProcessorConfig.cs @@ -0,0 +1,12 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class SimpleProcessorConfig +{ + [YamlMember(Alias = "exporter")] + public ExporterConfig? Exporter { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs index 21be9eaef9..1d52312968 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs @@ -8,5 +8,5 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguratio internal class TracerProviderConfiguration { [YamlMember(Alias = "processors")] - public Dictionary Processors { get; set; } = new(); + public List Processors { get; set; } = new(); } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs index 62af59ec9d..9d5be2854a 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs @@ -34,10 +34,10 @@ public OtlpSettings(OtlpSignalType signalType, OtlpHttpExporterConfig configurat TimeoutMilliseconds = configuration.Timeout; - Endpoint = !string.IsNullOrEmpty(configuration.Endpoint) ? new Uri(configuration.Endpoint) : null; + Endpoint = GetOtlpHttpEndpoint(configuration.Endpoint, signalType); } - public OtlpSettings(OtlpSignalType signalType, OtlpGrpcExporterConfig configuration) + public OtlpSettings(OtlpGrpcExporterConfig configuration) { #pragma warning disable CS0618 // OtlpExportProtocol.Grpc is obsolete Protocol = OtlpExportProtocol.Grpc; @@ -47,7 +47,7 @@ public OtlpSettings(OtlpSignalType signalType, OtlpGrpcExporterConfig configurat TimeoutMilliseconds = configuration.Timeout; - Endpoint = !string.IsNullOrEmpty(configuration.Endpoint) ? new Uri(configuration.Endpoint) : null; + Endpoint = new Uri(configuration.Endpoint); } /// @@ -95,6 +95,27 @@ public void CopyTo(OtlpExporterOptions options) } } + private static Uri GetOtlpHttpEndpoint(string? endpoint, OtlpSignalType signalType) + { + if (string.IsNullOrWhiteSpace(endpoint)) + { + endpoint = signalType switch + { + OtlpSignalType.Logs => "http://localhost:4318/v1/logs", + OtlpSignalType.Metrics => "http://localhost:4318/v1/metrics", + OtlpSignalType.Traces => "http://localhost:4318/v1/traces", + _ => throw new ArgumentOutOfRangeException(nameof(signalType), "Unknown signal type") + }; + } + + if (!Uri.TryCreate(endpoint, UriKind.Absolute, out var uri)) + { + throw new ArgumentException($"Invalid endpoint URI: {endpoint}", nameof(endpoint)); + } + + return uri; + } + private static string? CombineHeaders(List
? headers, string? headersList) { var headerDict = new Dictionary(StringComparer.OrdinalIgnoreCase); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs index 47122b991e..bb3d6b01bf 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs @@ -26,6 +26,8 @@ internal class TracerSettings : Settings /// /// Gets the list of enabled traces exporters. + /// For File based configuration, this must be empty, + /// and the configuration will be handled by Processors. /// public IReadOnlyList TracesExporters { get; private set; } = []; @@ -55,18 +57,11 @@ internal class TracerSettings : Settings public OtlpSettings? OtlpSettings { get; private set; } /// - /// Gets tracing Batch Processor Configuration. - /// For environment variable configuration, this must be null, - /// and the configuration will be handled inside the Otlp exporter package. - /// - public BatchProcessorConfig? BatchProcessorConfig { get; private set; } = null; - - /// - /// Gets the tracing Zipkin settings. + /// Gets tracing OTLP Settings. /// For environment variable configuration, this must be null, - /// and the configuration will be handled inside the Zipkin exporter package. + /// and the configuration will be handled by TracesExporters /// - public ZipkinExporterConfig? ZipkinSettings { get; private set; } = null; + public IReadOnlyList? Processors { get; private set; } = null; protected override void OnLoadEnvVar(Configuration configuration) { @@ -110,46 +105,13 @@ protected override void OnLoadEnvVar(Configuration configuration) protected override void OnLoadFile(YamlConfiguration configuration) { - if (configuration.TracerProvider != null && - configuration.TracerProvider.Processors != null && - configuration.TracerProvider.Processors.TryGetValue("batch", out var batchProcessorConfig)) + var processors = configuration.TracerProvider?.Processors; + if (processors != null && processors.Count > 0) { TracesEnabled = true; - BatchProcessorConfig = batchProcessorConfig; - var exporters = batchProcessorConfig.Exporter; - var tracesExporters = new List(); - if (exporters != null) - { - if (exporters.OtlpGrpc != null) - { - tracesExporters.Add(TracesExporter.Otlp); - OtlpSettings = new OtlpSettings(OtlpSignalType.Traces, exporters.OtlpGrpc); - } - - if (exporters.OtlpHttp != null) - { - tracesExporters.Add(TracesExporter.Otlp); - OtlpSettings = new OtlpSettings(OtlpSignalType.Traces, exporters.OtlpHttp); - } - - if (exporters.Zipkin != null) - { - tracesExporters.Add(TracesExporter.Zipkin); - ZipkinSettings = exporters.Zipkin; - } - - if (exporters.Console != null) - { - tracesExporters.Add(TracesExporter.Console); - } - - TracesExporters = tracesExporters; - } - } - else - { - TracesEnabled = false; } + + Processors = processors; } private static List ParseTracesExporter(Configuration configuration) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs index 88422a7315..8b2b9c12b5 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +/* + using OpenTelemetry.AutoInstrumentation.Configurations; using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using Xunit; @@ -231,3 +233,4 @@ public void LoadFile_HandlesNullExporterGracefully() Assert.Null(settings.ZipkinSettings); } } +*/ diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFile.yaml index 8b50ba567e..e560ffaff9 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFile.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFile.yaml @@ -1,15 +1,26 @@ tracer_provider: processors: - batch: - schedule_delay: 5000 - export_timeout: 30000 - max_queue_size: 2048 - max_export_batch_size: 512 - exporter: - otlp_http: - endpoint: http://localhost:4318/v1/traces - timeout: 10000 - headers: - - name: header1234 - value: "1234" - \ No newline at end of file + - batch: + schedule_delay: 5000 + export_timeout: 30000 + max_queue_size: 2048 + max_export_batch_size: 512 + exporter: + otlp_http: + endpoint: http://localhost:4318/v1/traces + timeout: 10000 + headers: + - name: header1234 + value: "1234" + - batch: + exporter: + zipkin: + endpoint: http://localhost:4318/v1/traces + + - batch: + exporter: + otlp_grpc: + endpoint: http://localhost:4318/v1/traces + - simple: + exporter: + console: diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFileEnvVars.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFileEnvVars.yaml index 33ab57bbc3..9b9e7433b6 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFileEnvVars.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFileEnvVars.yaml @@ -1,12 +1,12 @@ tracer_provider: processors: - batch: - schedule_delay: ${OTEL_BSP_SCHEDULE_DELAY} - export_timeout: ${OTEL_BSP_EXPORT_TIMEOUT} - max_queue_size: ${OTEL_BSP_MAX_QUEUE_SIZE} - max_export_batch_size: ${OTEL_BSP_MAX_EXPORT_BATCH_SIZE} - exporter: - otlp_http: - endpoint: ${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT} - timeout: ${OTEL_EXPORTER_OTLP_TRACES_TIMEOUT} - headers_list: ${OTEL_EXPORTER_OTLP_TRACES_HEADERS} \ No newline at end of file + - batch: + schedule_delay: ${OTEL_BSP_SCHEDULE_DELAY} + export_timeout: ${OTEL_BSP_EXPORT_TIMEOUT} + max_queue_size: ${OTEL_BSP_MAX_QUEUE_SIZE} + max_export_batch_size: ${OTEL_BSP_MAX_EXPORT_BATCH_SIZE} + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT} + timeout: ${OTEL_EXPORTER_OTLP_TRACES_TIMEOUT} + headers_list: ${OTEL_EXPORTER_OTLP_TRACES_HEADERS} \ No newline at end of file diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserTracesTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserTracesTests.cs index d61ca54fc9..d459fdc7d1 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserTracesTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserTracesTests.cs @@ -17,8 +17,9 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() Assert.NotNull(config.TracerProvider); Assert.NotNull(config.TracerProvider.Processors); - Assert.True(config.TracerProvider.Processors.ContainsKey("batch")); - var traceBatch = config.TracerProvider.Processors["batch"]; + Assert.Equal(4, config.TracerProvider.Processors.Count); + + var traceBatch = config.TracerProvider.Processors[0].Batch; Assert.NotNull(traceBatch); Assert.Equal(5000, traceBatch.ScheduleDelay); @@ -27,17 +28,35 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() Assert.Equal(512, traceBatch.MaxExportBatchSize); Assert.NotNull(traceBatch.Exporter); - Assert.NotNull(traceBatch.Exporter.OtlpHttp); var traceExporter = traceBatch.Exporter.OtlpHttp; Assert.NotNull(traceExporter); Assert.Equal("http://localhost:4318/v1/traces", traceExporter.Endpoint); Assert.Equal(10000, traceExporter.Timeout); - Assert.Null(traceExporter.HeadersList); + Assert.NotNull(traceExporter.Headers); Assert.Single(traceExporter.Headers); Assert.Equal("header1234", traceExporter.Headers[0].Name); Assert.Equal("1234", traceExporter.Headers[0].Value); + + var zipkinBatch = config.TracerProvider.Processors[1].Batch; + Assert.NotNull(zipkinBatch); + Assert.NotNull(zipkinBatch.Exporter); + var zipkinExporter = zipkinBatch.Exporter.Zipkin; + Assert.NotNull(zipkinExporter); + Assert.Equal("http://localhost:4318/v1/traces", zipkinExporter.Endpoint); + + var grpcBatch = config.TracerProvider.Processors[2].Batch; + Assert.NotNull(grpcBatch); + Assert.NotNull(grpcBatch.Exporter); + var grpcExporter = grpcBatch.Exporter.OtlpGrpc; + Assert.NotNull(grpcExporter); + Assert.Equal("http://localhost:4318/v1/traces", grpcExporter.Endpoint); + + var simpleProcessor = config.TracerProvider.Processors[3].Simple; + Assert.NotNull(simpleProcessor); + Assert.NotNull(simpleProcessor.Exporter); + Assert.NotNull(simpleProcessor.Exporter.Console); } [Fact] @@ -57,8 +76,7 @@ public void Parse_EnvVarYaml_ShouldPopulateModelCompletely() Assert.NotNull(config.TracerProvider); Assert.NotNull(config.TracerProvider.Processors); - Assert.True(config.TracerProvider.Processors.ContainsKey("batch")); - var traceBatch = config.TracerProvider.Processors["batch"]; + var traceBatch = config.TracerProvider.Processors[0].Batch; Assert.NotNull(traceBatch); Assert.NotNull(traceBatch.Exporter); From f24901e2cacc0f03eda10cd4368ada6fbdf139a3 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Thu, 16 Oct 2025 10:11:54 +0200 Subject: [PATCH 11/18] update tests --- .../FileBased/FilebasedTracesSettingsTests.cs | 186 ++++-------------- .../FileBased/Files/TestTracesFile.yaml | 4 +- .../FileBased/Parser/ParserTracesTests.cs | 4 +- .../TestApplication.NoCode/config.yaml | 8 +- 4 files changed, 45 insertions(+), 157 deletions(-) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs index 8b2b9c12b5..cbb5b7c79e 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs @@ -1,8 +1,6 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -/* - using OpenTelemetry.AutoInstrumentation.Configurations; using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using Xunit; @@ -14,35 +12,51 @@ public class FilebasedTracesSettingsTests [Fact] public void LoadFile_SetsBatchProcessorAndExportersCorrectly() { - var exporter = new ExporterConfig + var exporter1 = new ExporterConfig { OtlpGrpc = new OtlpGrpcExporterConfig { Endpoint = "http://localhost:4317/" - }, + } + }; + + var exporter2 = new ExporterConfig + { Zipkin = new ZipkinExporterConfig { Endpoint = "http://localhost:9411/" - }, + } }; - var batchProcessorConfig = new BatchProcessorConfig + var batchProcessorConfig1 = new BatchProcessorConfig { ScheduleDelay = 1000, ExportTimeout = 30000, MaxQueueSize = 2048, MaxExportBatchSize = 512, - Exporter = exporter + Exporter = exporter1 + }; + + var batchProcessorConfig2 = new BatchProcessorConfig + { + Exporter = exporter2 }; var conf = new YamlConfiguration { TracerProvider = new TracerProviderConfiguration { - Processors = new Dictionary - { - { "batch", batchProcessorConfig } - } + Processors = + [ + new ProcessorConfig + { + Batch = batchProcessorConfig1 + }, + new ProcessorConfig + { + Batch = batchProcessorConfig2 + } + ] } }; @@ -51,22 +65,10 @@ public void LoadFile_SetsBatchProcessorAndExportersCorrectly() settings.LoadFile(conf); Assert.True(settings.TracesEnabled); - Assert.Equal(2, settings.TracesExporters.Count); - Assert.Contains(TracesExporter.Otlp, settings.TracesExporters); - Assert.Contains(TracesExporter.Zipkin, settings.TracesExporters); - - Assert.NotNull(settings.OtlpSettings); - Assert.NotNull(settings.ZipkinSettings); - - Assert.NotNull(settings.OtlpSettings.Endpoint); - Assert.Equal("http://localhost:4317/", settings.OtlpSettings.Endpoint.ToString()); - Assert.Equal("http://localhost:9411/", settings.ZipkinSettings.Endpoint); - - Assert.NotNull(settings.BatchProcessorConfig); - Assert.Equal(1000, settings.BatchProcessorConfig.ScheduleDelay); - Assert.Equal(30000, settings.BatchProcessorConfig.ExportTimeout); - Assert.Equal(2048, settings.BatchProcessorConfig.MaxQueueSize); - Assert.Equal(512, settings.BatchProcessorConfig.MaxExportBatchSize); + Assert.NotNull(settings.Processors); + Assert.Equal(2, settings.Processors.Count); + + Assert.Empty(settings.TracesExporters); } [Fact] @@ -87,121 +89,7 @@ public void LoadFile_DisablesTraces_WhenNoBatchProcessorConfigured() Assert.False(settings.TracesEnabled); Assert.Empty(settings.TracesExporters); Assert.Null(settings.OtlpSettings); - Assert.Null(settings.ZipkinSettings); - } - - [Fact] - public void LoadFile_SetsOtlpHttpExporterCorrectly() - { - var exporter = new ExporterConfig - { - OtlpHttp = new OtlpHttpExporterConfig - { - Endpoint = "http://localhost:4318/" - } - }; - - var batchProcessorConfig = new BatchProcessorConfig - { - Exporter = exporter - }; - - var conf = new YamlConfiguration - { - TracerProvider = new TracerProviderConfiguration - { - Processors = new Dictionary - { - { "batch", batchProcessorConfig } - } - } - }; - - var settings = new TracerSettings(); - - settings.LoadFile(conf); - - Assert.True(settings.TracesEnabled); - Assert.Single(settings.TracesExporters); - Assert.Contains(TracesExporter.Otlp, settings.TracesExporters); - Assert.NotNull(settings.OtlpSettings); - Assert.NotNull(settings.OtlpSettings.Endpoint); - Assert.Equal("http://localhost:4318/", settings.OtlpSettings.Endpoint.ToString()); - } - - [Fact] - public void LoadFile_SetsConsoleExporterCorrectly() - { - var exporter = new ExporterConfig - { - Console = new object() - }; - - var batchProcessorConfig = new BatchProcessorConfig - { - Exporter = exporter - }; - - var conf = new YamlConfiguration - { - TracerProvider = new TracerProviderConfiguration - { - Processors = new Dictionary - { - { "batch", batchProcessorConfig } - } - } - }; - - var settings = new TracerSettings(); - - settings.LoadFile(conf); - - Assert.True(settings.TracesEnabled); - Assert.Single(settings.TracesExporters); - Assert.Contains(TracesExporter.Console, settings.TracesExporters); - Assert.Null(settings.OtlpSettings); - Assert.Null(settings.ZipkinSettings); - } - - [Fact] - public void LoadFile_SetsMultipleExportersCorrectly() - { - var exporter = new ExporterConfig - { - OtlpGrpc = new OtlpGrpcExporterConfig { Endpoint = "http://localhost:4317/" }, - Console = new object(), - Zipkin = new ZipkinExporterConfig - { - Endpoint = "http://localhost:9411/" - }, - }; - - var batchProcessorConfig = new BatchProcessorConfig - { - Exporter = exporter - }; - - var conf = new YamlConfiguration - { - TracerProvider = new TracerProviderConfiguration - { - Processors = new Dictionary - { - { "batch", batchProcessorConfig } - } - } - }; - - var settings = new TracerSettings(); - - settings.LoadFile(conf); - - Assert.True(settings.TracesEnabled); - Assert.Equal(3, settings.TracesExporters.Count); - Assert.Contains(TracesExporter.Otlp, settings.TracesExporters); - Assert.Contains(TracesExporter.Console, settings.TracesExporters); - Assert.Contains(TracesExporter.Zipkin, settings.TracesExporters); + Assert.Null(settings.Processors); } [Fact] @@ -216,10 +104,13 @@ public void LoadFile_HandlesNullExporterGracefully() { TracerProvider = new TracerProviderConfiguration { - Processors = new Dictionary - { - { "batch", batchProcessorConfig } - } + Processors = + [ + new ProcessorConfig + { + Batch = batchProcessorConfig + } + ] } }; @@ -229,8 +120,5 @@ public void LoadFile_HandlesNullExporterGracefully() Assert.True(settings.TracesEnabled); Assert.Empty(settings.TracesExporters); - Assert.Null(settings.OtlpSettings); - Assert.Null(settings.ZipkinSettings); } } -*/ diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFile.yaml index e560ffaff9..514737454e 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFile.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestTracesFile.yaml @@ -15,12 +15,12 @@ tracer_provider: - batch: exporter: zipkin: - endpoint: http://localhost:4318/v1/traces + endpoint: http://localhost:9411/zipkin - batch: exporter: otlp_grpc: - endpoint: http://localhost:4318/v1/traces + endpoint: http://localhost:4317 - simple: exporter: console: diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserTracesTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserTracesTests.cs index d459fdc7d1..48eeb664e3 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserTracesTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Parser/ParserTracesTests.cs @@ -44,14 +44,14 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() Assert.NotNull(zipkinBatch.Exporter); var zipkinExporter = zipkinBatch.Exporter.Zipkin; Assert.NotNull(zipkinExporter); - Assert.Equal("http://localhost:4318/v1/traces", zipkinExporter.Endpoint); + Assert.Equal("http://localhost:9411/zipkin", zipkinExporter.Endpoint); var grpcBatch = config.TracerProvider.Processors[2].Batch; Assert.NotNull(grpcBatch); Assert.NotNull(grpcBatch.Exporter); var grpcExporter = grpcBatch.Exporter.OtlpGrpc; Assert.NotNull(grpcExporter); - Assert.Equal("http://localhost:4318/v1/traces", grpcExporter.Endpoint); + Assert.Equal("http://localhost:4317", grpcExporter.Endpoint); var simpleProcessor = config.TracerProvider.Processors[3].Simple; Assert.NotNull(simpleProcessor); diff --git a/test/test-applications/integrations/TestApplication.NoCode/config.yaml b/test/test-applications/integrations/TestApplication.NoCode/config.yaml index 2e10e49ce5..0a5c40d0a9 100644 --- a/test/test-applications/integrations/TestApplication.NoCode/config.yaml +++ b/test/test-applications/integrations/TestApplication.NoCode/config.yaml @@ -2,10 +2,10 @@ file_format: "1.0-rc.1" tracer_provider: processors: - batch: - exporter: - otlp_http: - endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT} + - batch: + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT} no_code/development: targets: From de5d74f9b324cca8ed2ef37fd3ba4f94be630c11 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Thu, 16 Oct 2025 10:19:40 +0200 Subject: [PATCH 12/18] update docs --- docs/file-based-configuration.md | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/docs/file-based-configuration.md b/docs/file-based-configuration.md index dad3d56f44..1397c49ac5 100644 --- a/docs/file-based-configuration.md +++ b/docs/file-based-configuration.md @@ -54,9 +54,8 @@ flush_on_unhandled_exception: false ``` yaml tracer_provider: processors: - # Configure a batch span processor. - # Support for multiple processors is not available yet (which does not comply with the specification). - batch: + # Batch processor for OTLP HTTP + - batch: # Configure delay interval (in milliseconds) between two consecutive exports. # Value must be non-negative. # If omitted or null, 5000 is used. @@ -86,23 +85,31 @@ tracer_provider: # If an entry's .value is null, the entry is ignored. headers: - name: api-key - value: "1234" + value: "1234" # Configure headers. Entries have lower priority than entries from .headers. # The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. # If omitted or null, no headers are added. headers_list: ${OTEL_EXPORTER_OTLP_TRACES_HEADERS} - # Configure the OTLP with gRPC transport exporter to enable it. + + # Batch processor for OTLP gRPC + - batch: otlp_grpc: # Configuration otlp_grpc is the same as otlp_http. # if otlp_http is used it will override otlp_grpc. # On .NET Framework, the grpc OTLP exporter protocol is not supported. - # Configure the zipkin exporter to enable it. - zipkin: - # Configure endpoint. - # If omitted or null, http://localhost:9411/api/v2/spans is used. - endpoint: http://localhost:9411/api/v2/spans - # Add the console exporter to enable it. - console: + + # Batch processor for Zipkin + - batch: + exporter: + zipkin: + # Configure endpoint. + # If omitted or null, http://localhost:9411/api/v2/spans is used. + endpoint: http://localhost:9411/api/v2/spans + + # Simple processor for Console + - simple: + exporter: + console: ``` ### Resource Configuration From 28eb9cd76928d6efcfbfc670f47ed81b9eef8886 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Fri, 17 Oct 2025 09:17:06 +0200 Subject: [PATCH 13/18] fix --- .../Configurations/TracerSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs index bb3d6b01bf..624f138647 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs @@ -106,7 +106,7 @@ protected override void OnLoadEnvVar(Configuration configuration) protected override void OnLoadFile(YamlConfiguration configuration) { var processors = configuration.TracerProvider?.Processors; - if (processors != null && processors.Count > 0) + if (processors != null || processors?.Count > 0) { TracesEnabled = true; } From 482049545cee8b1bf7dd37f2d27179ddcd2952b9 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Fri, 17 Oct 2025 09:23:01 +0200 Subject: [PATCH 14/18] fix --- .../Configurations/TracerSettings.cs | 2 +- .../Configurations/FileBased/FilebasedTracesSettingsTests.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs index 624f138647..bb3d6b01bf 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs @@ -106,7 +106,7 @@ protected override void OnLoadEnvVar(Configuration configuration) protected override void OnLoadFile(YamlConfiguration configuration) { var processors = configuration.TracerProvider?.Processors; - if (processors != null || processors?.Count > 0) + if (processors != null && processors.Count > 0) { TracesEnabled = true; } diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs index cbb5b7c79e..fb0f5fd441 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs @@ -89,7 +89,8 @@ public void LoadFile_DisablesTraces_WhenNoBatchProcessorConfigured() Assert.False(settings.TracesEnabled); Assert.Empty(settings.TracesExporters); Assert.Null(settings.OtlpSettings); - Assert.Null(settings.Processors); + Assert.NotNull(settings.Processors); + Assert.Empty(settings.Processors); } [Fact] From 21b860a66cf4827111311064e052a376183e7610 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Mon, 20 Oct 2025 09:56:14 +0200 Subject: [PATCH 15/18] fix var name --- .../EnvironmentConfigurationTracerHelper.cs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs index 2d8437c12c..47eec702e4 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs @@ -102,20 +102,20 @@ private static TracerProviderBuilder SetExporter(this TracerProviderBuilder buil { if (processor.Batch != null) { - var exporerter = processor.Batch.Exporter; - if (exporerter != null) + var exporter = processor.Batch.Exporter; + if (exporter != null) { - if (exporerter.OtlpHttp != null) + if (exporter.OtlpHttp != null) { - builder = Wrappers.AddOtlpHttpExporter(builder, pluginManager, processor.Batch, exporerter.OtlpHttp); + builder = Wrappers.AddOtlpHttpExporter(builder, pluginManager, processor.Batch, exporter.OtlpHttp); } - else if (exporerter.OtlpGrpc != null) + else if (exporter.OtlpGrpc != null) { - builder = Wrappers.AddOtlpGrpcExporter(builder, pluginManager, processor.Batch, exporerter.OtlpGrpc); + builder = Wrappers.AddOtlpGrpcExporter(builder, pluginManager, processor.Batch, exporter.OtlpGrpc); } - else if (exporerter.Zipkin != null) + else if (exporter.Zipkin != null) { - builder = Wrappers.AddZipkinExporter(builder, pluginManager, processor.Batch, exporerter.Zipkin); + builder = Wrappers.AddZipkinExporter(builder, pluginManager, processor.Batch, exporter.Zipkin); } else { @@ -125,22 +125,22 @@ private static TracerProviderBuilder SetExporter(this TracerProviderBuilder buil } else if (processor.Simple != null) { - var exporerter = processor.Simple.Exporter; - if (exporerter != null) + var exporter = processor.Simple.Exporter; + if (exporter != null) { - if (exporerter.OtlpHttp != null) + if (exporter.OtlpHttp != null) { - builder = Wrappers.AddOtlpHttpExporter(builder, pluginManager, exporerter.OtlpHttp); + builder = Wrappers.AddOtlpHttpExporter(builder, pluginManager, exporter.OtlpHttp); } - else if (exporerter.OtlpGrpc != null) + else if (exporter.OtlpGrpc != null) { - builder = Wrappers.AddOtlpGrpcExporter(builder, pluginManager, exporerter.OtlpGrpc); + builder = Wrappers.AddOtlpGrpcExporter(builder, pluginManager, exporter.OtlpGrpc); } - else if (exporerter.Zipkin != null) + else if (exporter.Zipkin != null) { - builder = Wrappers.AddZipkinExporter(builder, pluginManager, exporerter.Zipkin); + builder = Wrappers.AddZipkinExporter(builder, pluginManager, exporter.Zipkin); } - else if (exporerter.Console != null) + else if (exporter.Console != null) { builder = Wrappers.AddConsoleExporter(builder, pluginManager); } From 5276b2593abd91008e94926b820ef734ac4b8beb Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Mon, 20 Oct 2025 09:56:37 +0200 Subject: [PATCH 16/18] fix test --- test/IntegrationTests/Helpers/TestHelper.cs | 6 ++++++ test/IntegrationTests/NoCodeTests.cs | 2 +- .../TestApplication.NoCode/Properties/launchSettings.json | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/test/IntegrationTests/Helpers/TestHelper.cs b/test/IntegrationTests/Helpers/TestHelper.cs index e986e8ad81..72cf64c9c4 100644 --- a/test/IntegrationTests/Helpers/TestHelper.cs +++ b/test/IntegrationTests/Helpers/TestHelper.cs @@ -59,6 +59,12 @@ public void SetExporter(MockSpansCollector collector) SetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT", $"http://localhost:{collector.Port}"); } + public void SetFileBasedExporter(MockSpansCollector collector) + { + SetEnvironmentVariable("OTEL_TRACES_EXPORTER", "otlp"); + SetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT", $"http://localhost:{collector.Port}/v1/traces"); + } + public void SetExporter(MockMetricsCollector collector) { SetEnvironmentVariable("OTEL_METRICS_EXPORTER", "otlp"); diff --git a/test/IntegrationTests/NoCodeTests.cs b/test/IntegrationTests/NoCodeTests.cs index 8dfd03f9e7..2f6a60f343 100644 --- a/test/IntegrationTests/NoCodeTests.cs +++ b/test/IntegrationTests/NoCodeTests.cs @@ -22,7 +22,7 @@ public void SubmitsTraces() EnableBytecodeInstrumentation(); EnableFileBasedConfigWithDefaultPath(); using var collector = new MockSpansCollector(Output); - SetExporter(collector); + SetFileBasedExporter(collector); List allTypeOfAttributes = [ new() { Key = "attribute_key_string", Value = new AnyValue { StringValue = "string_value" } }, diff --git a/test/test-applications/integrations/TestApplication.NoCode/Properties/launchSettings.json b/test/test-applications/integrations/TestApplication.NoCode/Properties/launchSettings.json index 02791064f8..a8acfea733 100644 --- a/test/test-applications/integrations/TestApplication.NoCode/Properties/launchSettings.json +++ b/test/test-applications/integrations/TestApplication.NoCode/Properties/launchSettings.json @@ -16,7 +16,8 @@ "DOTNET_STARTUP_HOOKS": "$(SolutionDir)bin\\tracer-home\\net\\OpenTelemetry.AutoInstrumentation.StartupHook.dll", "OTEL_DOTNET_AUTO_HOME": "$(SolutionDir)bin\\tracer-home", "OTEL_TRACES_EXPORTER": "otlp,console", - "OTEL_LOG_LEVEL": "debug" + "OTEL_LOG_LEVEL": "debug", + "OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED": "true" } } } From 0faa54fb90ac3b75b404af68ba468f7a1a6fdf36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 23 Oct 2025 09:48:50 +0200 Subject: [PATCH 17/18] Separate configuration for batch/simple processors --- .../BatchProcessorConfig.cs | 2 +- .../BatchTracerExporterConfig.cs | 27 +++++++++++++++++++ .../SimpleProcessorConfig.cs | 2 +- ...onfig.cs => SimpleTracerExporterConfig.cs} | 8 +----- .../FileBased/FilebasedTracesSettingsTests.cs | 4 +-- 5 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchTracerExporterConfig.cs rename src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/{ExporterConfig.cs => SimpleTracerExporterConfig.cs} (81%) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs index 5153965572..de31d367fb 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs @@ -44,7 +44,7 @@ internal class BatchProcessorConfig /// Gets or sets the exporters. ///
[YamlMember(Alias = "exporter")] - public ExporterConfig? Exporter { get; set; } + public BatchTracerExporterConfig? Exporter { get; set; } public void CopyTo(BatchExportProcessorOptions options) { diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchTracerExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchTracerExporterConfig.cs new file mode 100644 index 0000000000..86235ed440 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchTracerExporterConfig.cs @@ -0,0 +1,27 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class BatchTracerExporterConfig +{ + /// + /// Gets or sets the OTLP HTTP exporter configuration. + /// + [YamlMember(Alias = "otlp_http")] + public OtlpHttpExporterConfig? OtlpHttp { get; set; } + + /// + /// Gets or sets the OTLP gRPC exporter configuration. + /// + [YamlMember(Alias = "otlp_grpc")] + public OtlpGrpcExporterConfig? OtlpGrpc { get; set; } + + /// + /// Gets or sets the Zipkin exporter configuration. + /// + [YamlMember(Alias = "zipkin")] + public ZipkinExporterConfig? Zipkin { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SimpleProcessorConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SimpleProcessorConfig.cs index 07bc89b239..c73b238508 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SimpleProcessorConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SimpleProcessorConfig.cs @@ -8,5 +8,5 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguratio internal class SimpleProcessorConfig { [YamlMember(Alias = "exporter")] - public ExporterConfig? Exporter { get; set; } + public SimpleTracerExporterConfig? Exporter { get; set; } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SimpleTracerExporterConfig.cs similarity index 81% rename from src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs rename to src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SimpleTracerExporterConfig.cs index 8954eea496..6c25677238 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SimpleTracerExporterConfig.cs @@ -5,7 +5,7 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; -internal class ExporterConfig +internal class SimpleTracerExporterConfig { /// /// Gets or sets the OTLP HTTP exporter configuration. @@ -25,12 +25,6 @@ internal class ExporterConfig [YamlMember(Alias = "zipkin")] public ZipkinExporterConfig? Zipkin { get; set; } - /// - /// Gets or sets the Prometheus exporter configuration. - /// - [YamlMember(Alias = "prometheus")] - public object? Prometheus { get; set; } - /// /// Gets or sets the console exporter configuration. /// diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs index fb0f5fd441..020ee397d3 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs @@ -12,7 +12,7 @@ public class FilebasedTracesSettingsTests [Fact] public void LoadFile_SetsBatchProcessorAndExportersCorrectly() { - var exporter1 = new ExporterConfig + var exporter1 = new BatchTracerExporterConfig { OtlpGrpc = new OtlpGrpcExporterConfig { @@ -20,7 +20,7 @@ public void LoadFile_SetsBatchProcessorAndExportersCorrectly() } }; - var exporter2 = new ExporterConfig + var exporter2 = new BatchTracerExporterConfig { Zipkin = new ZipkinExporterConfig { From ff00c982595946471420874cd224019d95f0c237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 23 Oct 2025 10:31:04 +0200 Subject: [PATCH 18/18] Validate configuration while configuring exporters --- .../EnvironmentConfigurationTracerHelper.cs | 85 ++++++- .../FileBasedConfiguration/ProcessorConfig.cs | 4 +- .../FileBased/FilebasedTracesSettingsTests.cs | 236 ++++++++++++++++++ 3 files changed, 315 insertions(+), 10 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs index 47eec702e4..48fc7b6441 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs @@ -100,13 +100,58 @@ private static TracerProviderBuilder SetExporter(this TracerProviderBuilder buil { foreach (var processor in settings.Processors) { + if (processor.Batch != null && processor.Simple != null) + { + Logger.Debug("Both batch and simple processors are configured. It is not supported. Skipping."); + continue; + } + + if (processor.Batch == null && processor.Simple == null) + { + Logger.Debug("No valid processor configured, skipping."); + continue; + } + if (processor.Batch != null) { var exporter = processor.Batch.Exporter; if (exporter != null) { + var exportersCount = 0; + if (exporter.OtlpHttp != null) { + exportersCount++; + } + + if (exporter.OtlpGrpc != null) + { + exportersCount++; + } + + if (exporter.Zipkin != null) + { + exportersCount++; + } + + switch (exportersCount) + { + case 0: + Logger.Debug("No valid exporter configured for batch processor. Skipping."); + continue; + case > 1: + Logger.Debug("Multiple exporters are configured for batch processor. Only one exporter is supported. Skipping."); + continue; + } + + if (exporter.OtlpHttp != null) + { + if (exporter.OtlpGrpc != null || exporter.Zipkin != null) + { + Logger.Debug("Both gRPC and Zipkin exporters are configured, using gRPC."); + continue; + } + builder = Wrappers.AddOtlpHttpExporter(builder, pluginManager, processor.Batch, exporter.OtlpHttp); } else if (exporter.OtlpGrpc != null) @@ -117,10 +162,6 @@ private static TracerProviderBuilder SetExporter(this TracerProviderBuilder buil { builder = Wrappers.AddZipkinExporter(builder, pluginManager, processor.Batch, exporter.Zipkin); } - else - { - Logger.Debug("No valid exporter configured for batch processor, skipping."); - } } } else if (processor.Simple != null) @@ -128,6 +169,38 @@ private static TracerProviderBuilder SetExporter(this TracerProviderBuilder buil var exporter = processor.Simple.Exporter; if (exporter != null) { + var exportersCount = 0; + + if (exporter.OtlpHttp != null) + { + exportersCount++; + } + + if (exporter.OtlpGrpc != null) + { + exportersCount++; + } + + if (exporter.Zipkin != null) + { + exportersCount++; + } + + if (exporter.Console != null) + { + exportersCount++; + } + + switch (exportersCount) + { + case 0: + Logger.Debug("No valid exporter configured for batch processor. Skipping."); + continue; + case > 1: + Logger.Debug("Multiple exporters are configured for batch processor. Only one exporter is supported. Skipping."); + continue; + } + if (exporter.OtlpHttp != null) { builder = Wrappers.AddOtlpHttpExporter(builder, pluginManager, exporter.OtlpHttp); @@ -144,10 +217,6 @@ private static TracerProviderBuilder SetExporter(this TracerProviderBuilder buil { builder = Wrappers.AddConsoleExporter(builder, pluginManager); } - else - { - Logger.Debug("No valid exporter configured for simple processor, skipping."); - } } } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ProcessorConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ProcessorConfig.cs index b4cc8bdf1c..3ee9cd858c 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ProcessorConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ProcessorConfig.cs @@ -8,8 +8,8 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguratio internal class ProcessorConfig { [YamlMember(Alias = "batch")] - public BatchProcessorConfig Batch { get; set; } = new(); + public BatchProcessorConfig? Batch { get; set; } [YamlMember(Alias = "simple")] - public SimpleProcessorConfig Simple { get; set; } = new(); + public SimpleProcessorConfig? Simple { get; set; } } diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs index 020ee397d3..d3adca198d 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs @@ -9,6 +9,221 @@ namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; public class FilebasedTracesSettingsTests { + public static TheoryData LoadMethod_SkipWrongExporterConfiguration_Data() + { + return + [ + new(new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = [] + } + }), + new(new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = [new ProcessorConfig()] + } + }), + new(new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = + [ + new ProcessorConfig + { + Batch = new BatchProcessorConfig(), + Simple = new SimpleProcessorConfig() + } + ] + } + }), + new(new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = + [ + new ProcessorConfig + { + Batch = new BatchProcessorConfig + { + Exporter = new BatchTracerExporterConfig + { + OtlpHttp = new OtlpHttpExporterConfig(), + OtlpGrpc = new OtlpGrpcExporterConfig(), + } + }, + } + ] + } + }), + new(new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = + [ + new ProcessorConfig + { + Batch = new BatchProcessorConfig + { + Exporter = new BatchTracerExporterConfig + { + OtlpHttp = new OtlpHttpExporterConfig(), + Zipkin = new ZipkinExporterConfig() + } + }, + } + ] + } + }), + new(new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = + [ + new ProcessorConfig + { + Batch = new BatchProcessorConfig + { + Exporter = new BatchTracerExporterConfig + { + OtlpGrpc = new OtlpGrpcExporterConfig(), + Zipkin = new ZipkinExporterConfig() + } + }, + } + ] + } + }), + new(new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = + [ + new ProcessorConfig + { + Simple = new SimpleProcessorConfig + { + Exporter = new SimpleTracerExporterConfig + { + OtlpHttp = new OtlpHttpExporterConfig(), + OtlpGrpc = new OtlpGrpcExporterConfig() + } + }, + } + ] + } + }), + new(new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = + [ + new ProcessorConfig + { + Simple = new SimpleProcessorConfig + { + Exporter = new SimpleTracerExporterConfig + { + OtlpHttp = new OtlpHttpExporterConfig(), + Zipkin = new ZipkinExporterConfig() + } + }, + } + ] + } + }), + new(new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = + [ + new ProcessorConfig + { + Simple = new SimpleProcessorConfig + { + Exporter = new SimpleTracerExporterConfig + { + OtlpHttp = new OtlpHttpExporterConfig(), + Console = new object() + } + }, + } + ] + } + }), + new(new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = + [ + new ProcessorConfig + { + Simple = new SimpleProcessorConfig + { + Exporter = new SimpleTracerExporterConfig + { + OtlpGrpc = new OtlpGrpcExporterConfig(), + Zipkin = new ZipkinExporterConfig() + } + }, + } + ] + } + }), + new(new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = + [ + new ProcessorConfig + { + Simple = new SimpleProcessorConfig + { + Exporter = new SimpleTracerExporterConfig + { + OtlpGrpc = new OtlpGrpcExporterConfig(), + Console = new object() + } + }, + } + ] + } + }), + new(new YamlConfiguration + { + TracerProvider = new TracerProviderConfiguration + { + Processors = + [ + new ProcessorConfig + { + Simple = new SimpleProcessorConfig + { + Exporter = new SimpleTracerExporterConfig + { + Zipkin = new ZipkinExporterConfig(), + Console = new object() + } + }, + } + ] + } + }), + ]; + } + [Fact] public void LoadFile_SetsBatchProcessorAndExportersCorrectly() { @@ -122,4 +337,25 @@ public void LoadFile_HandlesNullExporterGracefully() Assert.True(settings.TracesEnabled); Assert.Empty(settings.TracesExporters); } + + [Theory] + [MemberData(nameof(LoadMethod_SkipWrongExporterConfiguration_Data))] + public void LoadMethod_SkipWrongExporterConfiguration(SkipConfigurationTestCase skipConfigurationTestCase) + { + var settings = new TracerSettings(); + + settings.LoadFile(skipConfigurationTestCase.Configuration); + + Assert.Empty(settings.TracesExporters); + } + + public class SkipConfigurationTestCase + { + internal SkipConfigurationTestCase(YamlConfiguration configuration) + { + Configuration = configuration; + } + + internal YamlConfiguration Configuration { get; } + } }