From b20820bf5eda6af308d4b53331a99db937bb6c5b Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Tue, 24 Jun 2025 10:55:54 +0200 Subject: [PATCH 01/28] implement parser with file based configuration working progress --- src/Directory.Packages.props | 1 + .../netfx_assembly_redirection.h | 3 +- .../Configurations/ConfigurationKeys.cs | 44 +++++ .../EnvironmentConfigurationTracerHelper.cs | 14 +- .../Configurations/FailFastSettings.cs | 8 +- .../FileBasedConfiguration/AttributeLimits.cs | 42 +++++ .../BatchProcessorConfig.cs | 90 +++++++++ .../CaptureHeadersConfiguration.cs | 23 +++ .../CaptureMetadataConfiguration.cs | 23 +++ .../FileBasedConfiguration/Conf.cs | 84 +++++++++ .../DetectionDevelopment.cs | 16 ++ .../FileBasedConfiguration/DotNetDetectors.cs | 45 +++++ .../DotNetInstrumentation.cs | 27 +++ .../FileBasedConfiguration/DotNetLogs.cs | 41 ++++ .../FileBasedConfiguration/DotNetMetrics.cs | 79 ++++++++ .../FileBasedConfiguration/DotNetTraces.cs | 175 ++++++++++++++++++ .../FileBasedConfiguration/ExporterConfig.cs | 39 ++++ .../FileBasedConfiguration/Header.cs | 21 +++ .../InstrumentationDevelopment.cs | 15 ++ .../LoggerProviderConfiguration.cs | 15 ++ .../MeterProviderConfiguration.cs | 15 ++ .../OtlpGrpcExporterConfig.cs | 96 ++++++++++ .../OtlpHttpExporterConfig.cs | 96 ++++++++++ .../Parser/EnvVarTypeConverter.cs | 79 ++++++++ .../FileBasedConfiguration/Parser/Parser.cs | 21 +++ .../PropagatorConfiguration.cs | 21 +++ .../ReaderConfiguration.cs | 15 ++ .../ResourceAttribute.cs | 27 +++ .../ResourceConfiguration.cs | 27 +++ .../SetDbStatementForTextConfuguration.cs | 16 ++ .../SetDocumentConfiguration.cs | 16 ++ .../TracerProviderConfiguration.cs | 12 ++ .../ZipkinExporterConfig.cs | 29 +++ .../Configurations/GeneralSettings.cs | 47 ++++- .../Configurations/InstrumentationOptions.cs | 69 ++++++- .../Configurations/LogSettings.cs | 48 ++++- .../Configurations/MetricSettings.cs | 65 ++++++- .../Configurations/Otlp/OtlpSettings.cs | 65 +++++++ .../Configurations/SdkSettings.cs | 81 +++++++- .../Configurations/Settings.cs | 43 ++++- .../Configurations/TracerSettings.cs | 76 +++++++- .../HeaderConfigurationExtensions.cs | 21 ++- .../OpenTelemetry.AutoInstrumentation.csproj | 1 + 43 files changed, 1762 insertions(+), 29 deletions(-) create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/AttributeLimits.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DetectionDevelopment.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetDetectors.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetInstrumentation.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetMetrics.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.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/InstrumentationDevelopment.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/LoggerProviderConfiguration.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/MeterProviderConfiguration.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/Parser/EnvVarTypeConverter.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/PropagatorConfiguration.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceAttribute.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.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/Directory.Packages.props b/src/Directory.Packages.props index 5146758e83..18a61b1897 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -31,6 +31,7 @@ + diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/netfx_assembly_redirection.h b/src/OpenTelemetry.AutoInstrumentation.Native/netfx_assembly_redirection.h index 964699b068..9033bf3a0f 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/netfx_assembly_redirection.h +++ b/src/OpenTelemetry.AutoInstrumentation.Native/netfx_assembly_redirection.h @@ -159,7 +159,8 @@ void CorProfiler::InitNetFxAssemblyRedirectsMap() { L"System.Xml.XmlDocument", {4, 0, 3, 0} }, { L"System.Xml.XmlSerializer", {4, 0, 11, 0} }, { L"System.Xml.XPath", {4, 0, 3, 0} }, - { L"System.Xml.XPath.XDocument", {4, 1, 0, 0} } + { L"System.Xml.XPath.XDocument", {4, 1, 0, 0} }, + { L"YamlDotNet", {16, 0, 0, 0} } }); } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs index 3a14495716..ba5fca2177 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs @@ -92,6 +92,38 @@ public static class Traces /// public const string AdditionalLegacySources = "OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_LEGACY_SOURCES"; + /// + /// Configuration key for ZipkinEndpoint. + /// + public const string ZipkinEndpoint = "OTEL_EXPORTER_ZIPKIN_ENDPOINT"; + + /// + /// Configuration keys for Batch Span Processor options. + /// + public static class BatchSpanProcessorConfig + { + /// + /// Configuration key for configuring the delay interval (in milliseconds) between two consecutive exports. + /// + public const string ScheduleDelay = "OTEL_BSP_SCHEDULE_DELAY"; + + /// + /// Configuration key for configuring the maximum allowed time (in milliseconds) to export data. + /// + public const string ExportTimeout = "OTEL_BSP_EXPORT_TIMEOUT"; + + /// + /// Configuration key for configuring the maximum queue size. + /// + public const string MaxQueueSize = "OTEL_BSP_MAX_QUEUE_SIZE"; + + /// + /// Configuration key for configuring the maximum batch size. + /// Must be less than or equal to OTEL_BSP_MAX_QUEUE_SIZE. + /// + public const string MaxExportBatchSize = "OTEL_BSP_MAX_EXPORT_BATCH_SIZE"; + } + /// /// Configuration keys for instrumentation options. /// @@ -244,5 +276,17 @@ public static class Sdk /// Default is "tracecontext,baggage". /// public const string Propagators = "OTEL_PROPAGATORS"; + + /// + /// Configuration key for the maximum allowed length of attribute values. + /// Default is no limit. Valid values are non-negative integers. + /// + public const string AttributeValueLengthLimit = "OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT"; + + /// + /// Configuration key for the maximum allowed number of attributes per resource, span, or event. + /// Default is 128. Valid values are non-negative integers. + /// + public const string AttributeCountLimit = "OTEL_ATTRIBUTE_COUNT_LIMIT"; } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs index 91bda52666..838c8ac820 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationTracerHelper.cs @@ -92,7 +92,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 +218,15 @@ 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 => + { + options.BatchExportProcessorOptions = settings.BatchProcessorConfig.ToBatchExportProcessorOptions(); + options.Endpoint = new Uri(settings.ZipkinSettings!.Endpoint); + + pluginManager.ConfigureTracesOptions(options); + }); } [MethodImpl(MethodImplOptions.NoInlining)] @@ -228,6 +234,8 @@ public static TracerProviderBuilder AddOtlpExporter(TracerProviderBuilder builde { return builder.AddOtlpExporter(options => { + options.BatchExportProcessorOptions = settings.BatchProcessorConfig.ToBatchExportProcessorOptions(); + // Copy Auto settings to SDK settings settings.OtlpSettings?.CopyTo(options); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FailFastSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FailFastSettings.cs index 02bd7ee8bd..59a45daed3 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FailFastSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FailFastSettings.cs @@ -1,14 +1,20 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + namespace OpenTelemetry.AutoInstrumentation.Configurations; internal class FailFastSettings : Settings { public bool FailFast { get; private set; } - protected override void OnLoad(Configuration configuration) + protected override void OnLoadEnvVar(Configuration configuration) { FailFast = configuration.GetBool(ConfigurationKeys.FailFast) ?? false; } + + protected override void OnLoadFile(Conf configuration) + { + } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/AttributeLimits.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/AttributeLimits.cs new file mode 100644 index 0000000000..d75e9f014f --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/AttributeLimits.cs @@ -0,0 +1,42 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class AttributeLimits +{ + public AttributeLimits() + { + } + + public AttributeLimits(int? attributeValueLengthLimit, int? attributeCountLimit) + { + if (attributeValueLengthLimit.HasValue && attributeValueLengthLimit.Value >= 0) + { + AttributeValueLengthLimit = attributeValueLengthLimit; + } + + if (attributeCountLimit.HasValue && attributeCountLimit.Value >= 0) + { + AttributeCountLimit = attributeCountLimit.Value; + } + } + + /// + /// Gets or sets the maximum attribute value size. + /// Value must be non-negative. + /// If omitted or null, there is no limit. + /// + [YamlMember(Alias = "attribute_value_length_limit")] + public int? AttributeValueLengthLimit { get; set; } + + /// + /// Gets or sets the maximum attribute count. + /// Value must be non-negative. + /// If omitted or null, 128 is used. + /// + [YamlMember(Alias = "attribute_count_limit")] + public int AttributeCountLimit { get; set; } = 128; +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs new file mode 100644 index 0000000000..a6f303768b --- /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 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/CaptureHeadersConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs new file mode 100644 index 0000000000..52a5c485aa --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs @@ -0,0 +1,23 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class CaptureHeadersConfiguration +{ + /// + /// Gets or sets a comma-separated list of HTTP header names. + /// Instrumentations will capture HTTP request header values for all configured header names. + /// + [YamlMember(Alias = "capture_request_headers")] + public string? CaptureRequestHeaders { get; set; } + + /// + /// Gets or sets a comma-separated list of HTTP header names. + /// Instrumentations will capture HTTP response header values for all configured header names. + /// + [YamlMember(Alias = "capture_response_headers")] + public string? CaptureResponseHeaders { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs new file mode 100644 index 0000000000..77df52fc57 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs @@ -0,0 +1,23 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class CaptureMetadataConfiguration +{ + /// + /// Gets or sets a comma-separated list of gRPC metadata names. + /// Grpc.Net.Client instrumentations will capture gRPC request metadata values for all configured metadata names. + /// + [YamlMember(Alias = "capture_request_metadata")] + public string? CaptureRequestMetadata { get; set; } + + /// + /// Gets or sets a comma-separated list of gRPC metadata names. + /// Grpc.Net.Client instrumentations will capture gRPC response metadata values for all configured metadata names. + /// + [YamlMember(Alias = "capture_response_metadata")] + public string? CaptureResponseMetadata { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs new file mode 100644 index 0000000000..d8b01592b8 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs @@ -0,0 +1,84 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class Conf +{ + /// + /// Gets or sets the file format version. + /// The yaml format is documented at + /// https://github.com/open-telemetry/opentelemetry-configuration/tree/main/schema + /// + [YamlMember(Alias = "file_format")] + public string? FileFormat { get; set; } + + /// + /// Gets or sets a value indicating whether the SDK is disabled. + /// If omitted or null, false is used. + /// + [YamlMember(Alias = "disabled")] + public bool Disabled { get; set; } = false; + + /// + /// Gets or sets the log level of the internal logger used by the SDK. + /// If omitted, info is used. + /// + [YamlMember(Alias = "log_level")] + public string LogLevel { get; set; } = "info"; + + /// + /// Gets or sets the attribute limits. + /// + [YamlMember(Alias = "attribute_limits")] + public AttributeLimits AttributeLimits { get; set; } = new(); + + /// + /// Gets or sets the logger provider configuration. + /// Configure logger provider. + /// If omitted, a noop logger provider is used. + /// + [YamlMember(Alias = "logger_provider")] + public LoggerProviderConfiguration? LoggerProvider { get; set; } + + /// + /// Gets or sets the meter provider configuration. + /// Configure meter provider. + /// If omitted, a noop meter provider is used. + /// + [YamlMember(Alias = "meter_provider")] + public MeterProviderConfiguration? MeterProvider { get; set; } + + /// + /// Gets or sets the text map context propagator configuration. + /// If omitted, a noop propagator is used. + /// + [YamlMember(Alias = "propagator")] + public PropagatorConfiguration? Propagator { 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; } + + /// + /// Gets or sets the resource configuration. + /// Configure resource for all signals. + /// If omitted, the default resource is used. + /// + [YamlMember(Alias = "resource")] + public ResourceConfiguration? Resource { get; set; } + + /// + /// Gets or sets the instrumentation development configuration. + /// Configure instrumentation. + /// This type is in development and subject to breaking changes in minor versions. + /// + [YamlMember(Alias = "instrumentation/development")] + public InstrumentationDevelopment? InstrumentationDevelopment { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DetectionDevelopment.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DetectionDevelopment.cs new file mode 100644 index 0000000000..e367dba566 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DetectionDevelopment.cs @@ -0,0 +1,16 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class DetectionDevelopment +{ + /// + /// Gets or sets the configuration for resource detectors. + /// If omitted or null, no resource detectors are enabled. + /// + [YamlMember(Alias = "detectors")] + public DotNetDetectors? Detectors { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetDetectors.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetDetectors.cs new file mode 100644 index 0000000000..4b0a650a39 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetDetectors.cs @@ -0,0 +1,45 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class DotNetDetectors +{ + /// + /// Gets or sets the Azure App Service detector configuration. + /// + [YamlMember(Alias = "azureappservice")] + public object? AzureAppService { get; set; } + + /// + /// Gets or sets the container detector configuration. + /// + [YamlMember(Alias = "container")] + public object? Container { get; set; } + + /// + /// Gets or sets the host detector configuration. + /// + [YamlMember(Alias = "host")] + public object? Host { get; set; } + + /// + /// Gets or sets the operating system detector configuration. + /// + [YamlMember(Alias = "operatingsystem")] + public object? OperatingSystem { get; set; } + + /// + /// Gets or sets the process detector configuration. + /// + [YamlMember(Alias = "process")] + public object? Process { get; set; } + + /// + /// Gets or sets the process runtime detector configuration. + /// + [YamlMember(Alias = "processruntime")] + public object? ProcessRuntime { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetInstrumentation.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetInstrumentation.cs new file mode 100644 index 0000000000..3b6a4274dd --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetInstrumentation.cs @@ -0,0 +1,27 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class DotNetInstrumentation +{ + /// + /// Gets or sets the configuration for .NET traces instrumentation. + /// + [YamlMember(Alias = "traces")] + public DotNetTraces? Traces { get; set; } + + /// + /// Gets or sets the configuration for .NET metrics instrumentation. + /// + [YamlMember(Alias = "metrics")] + public DotNetMetrics? Metrics { get; set; } + + /// + /// Gets or sets the configuration for .NET logs instrumentation. + /// + [YamlMember(Alias = "logs")] + public DotNetLogs? Logs { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs new file mode 100644 index 0000000000..11eebd53cf --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs @@ -0,0 +1,41 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class DotNetLogs +{ + /// + /// Gets or sets the ILogger logs instrumentation configuration. + /// + [YamlMember(Alias = "ilogger")] + public object? ILogger { get; set; } + + /// + /// Gets or sets the Log4Net logs instrumentation configuration. + /// + [YamlMember(Alias = "log4net")] + public object? Log4Net { get; set; } + + /// + /// Returns the list of enabled log instrumentations. + /// + public IReadOnlyList GetEnabledInstrumentations() + { + var result = new List(); + + if (ILogger != null) + { + result.Add(LogInstrumentation.ILogger); + } + + if (Log4Net != null) + { + result.Add(LogInstrumentation.Log4Net); + } + + return result; + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetMetrics.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetMetrics.cs new file mode 100644 index 0000000000..cd2ca5968b --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetMetrics.cs @@ -0,0 +1,79 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.Reflection; +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class DotNetMetrics +{ +#if NETFRAMEWORK + /// + /// Gets or sets the ASP.NET metrics instrumentation configuration. + /// + [YamlMember(Alias = "aspnet")] + public object? AspNet { get; set; } +#endif + +#if NET + /// + /// Gets or sets the ASP.NET Core metrics instrumentation configuration. + /// + [YamlMember(Alias = "aspnetcore")] + public object? AspNetCore { get; set; } +#endif + + /// + /// Gets or sets the HttpClient metrics instrumentation configuration. + /// + [YamlMember(Alias = "httpclient")] + public object? HttpClient { get; set; } + + /// + /// Gets or sets the .NET runtime metrics instrumentation configuration. + /// + [YamlMember(Alias = "netruntime")] + public object? NetRuntime { get; set; } + + /// + /// Gets or sets the NServiceBus metrics instrumentation configuration. + /// + [YamlMember(Alias = "nservicebus")] + public object? NServiceBus { get; set; } + + /// + /// Gets or sets the process metrics instrumentation configuration. + /// + [YamlMember(Alias = "process")] + public object? Process { get; set; } + + /// + /// Gets or sets the SqlClient metrics instrumentation configuration. + /// + [YamlMember(Alias = "sqlclient")] + public object? SqlClient { get; set; } + + /// + /// Returns the list of enabled metric instrumentations. + /// + public IReadOnlyList GetEnabledInstrumentations() + { + var enabled = new List(); + var properties = typeof(DotNetMetrics).GetProperties(BindingFlags.Instance | BindingFlags.Public); + + foreach (var prop in properties) + { + var value = prop.GetValue(this); + if (value != null) + { + if (Enum.TryParse(prop.Name, out var instrumentation)) + { + enabled.Add(instrumentation); + } + } + } + + return enabled; + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs new file mode 100644 index 0000000000..8ed7eda86a --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs @@ -0,0 +1,175 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.Reflection; +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class DotNetTraces +{ +#if NETFRAMEWORK + /// + /// Gets or sets the ASP.NET traces instrumentation configuration. + /// + [YamlMember(Alias = "aspnet")] + public CaptureHeadersConfiguration? AspNet { get; set; } + + /// + /// Gets or sets the WCF service traces instrumentation configuration. + /// + [YamlMember(Alias = "wcfservice")] + public object? WcfService { get; set; } +#endif + +#if NET + /// + /// Gets or sets the ASP.NET Core traces instrumentation configuration. + /// + [YamlMember(Alias = "aspnetcore")] + public CaptureHeadersConfiguration? AspNetCore { get; set; } + + /// + /// Gets or sets the StackExchange.Redis traces instrumentation configuration. + /// + [YamlMember(Alias = "stackexchangeredis")] + public object? StackExchangeRedis { get; set; } + + /// + /// Gets or sets the Entity Framework Core traces instrumentation configuration. + /// + [YamlMember(Alias = "entityframeworkcore")] + public SetDbStatementForTextConfuguration? EntityFrameworkCore { get; set; } + + /// + /// Gets or sets the GraphQL traces instrumentation configuration. + /// + [YamlMember(Alias = "graphql")] + public SetDocumentConfiguration? GraphQL { get; set; } + + /// + /// Gets or sets the MassTransit traces instrumentation configuration. + /// + [YamlMember(Alias = "masstransit")] + public object? MassTransit { get; set; } + + /// + /// Gets or sets the MySqlData traces instrumentation configuration. + /// + [YamlMember(Alias = "mysqldata")] + public object? MySqlData { get; set; } +#endif + + /// + /// Gets or sets the Azure traces instrumentation configuration. + /// + [YamlMember(Alias = "azure")] + public object? Azure { get; set; } + + /// + /// Gets or sets the Elasticsearch traces instrumentation configuration. + /// + [YamlMember(Alias = "elasticsearch")] + public object? Elasticsearch { get; set; } + + /// + /// Gets or sets the ElasticTransport traces instrumentation configuration. + /// + [YamlMember(Alias = "elastictransport")] + public object? ElasticTransport { get; set; } + + /// + /// Gets or sets the Grpc.Net.Client traces instrumentation configuration. + /// + [YamlMember(Alias = "grpcnetclient")] + public CaptureMetadataConfiguration? GrpcNetClient { get; set; } + + /// + /// Gets or sets the HttpClient traces instrumentation configuration. + /// + [YamlMember(Alias = "httpclient")] + public CaptureHeadersConfiguration? HttpClient { get; set; } + + /// + /// Gets or sets the Kafka traces instrumentation configuration. + /// + [YamlMember(Alias = "kafka")] + public object? Kafka { get; set; } + + /// + /// Gets or sets the MongoDB traces instrumentation configuration. + /// + [YamlMember(Alias = "mongodb")] + public object? MongoDb { get; set; } + + /// + /// Gets or sets the MySqlConnector traces instrumentation configuration. + /// + [YamlMember(Alias = "mysqlconnector")] + public object? MySqlConnector { get; set; } + + /// + /// Gets or sets the Npgsql traces instrumentation configuration. + /// + [YamlMember(Alias = "npgsql")] + public object? Npgsql { get; set; } + + /// + /// Gets or sets the NServiceBus traces instrumentation configuration. + /// + [YamlMember(Alias = "nservicebus")] + public object? NServiceBus { get; set; } + + /// + /// Gets or sets the Oracle MDA traces instrumentation configuration. + /// + [YamlMember(Alias = "oraclemda")] + public SetDbStatementForTextConfuguration? OracleMda { get; set; } + + /// + /// Gets or sets the RabbitMQ traces instrumentation configuration. + /// + [YamlMember(Alias = "rabbitmq")] + public object? RabbitMq { get; set; } + + /// + /// Gets or sets the Quartz traces instrumentation configuration. + /// + [YamlMember(Alias = "quartz")] + public object? Quartz { get; set; } + + /// + /// Gets or sets the SqlClient traces instrumentation configuration. + /// + [YamlMember(Alias = "sqlclient")] + public SetDbStatementForTextConfuguration? SqlClient { get; set; } + + /// + /// Gets or sets the WCF client traces instrumentation configuration. + /// + [YamlMember(Alias = "wcfclient")] + public object? WcfClient { get; set; } + + /// + /// Returns the list of enabled traces instrumentations. + /// + public IReadOnlyList GetEnabledInstrumentations() + { + var enabled = new List(); + var properties = typeof(DotNetTraces).GetProperties(BindingFlags.Instance | BindingFlags.Public); + + foreach (var prop in properties) + { + var value = prop.GetValue(this); + if (value != null) + { + if (Enum.TryParse(prop.Name, out var instrumentation)) + { + enabled.Add(instrumentation); + } + } + } + + return enabled; + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs new file mode 100644 index 0000000000..36a2e9aa9c --- /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 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..cf35439e0d --- /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 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/InstrumentationDevelopment.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/InstrumentationDevelopment.cs new file mode 100644 index 0000000000..a1254ca214 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/InstrumentationDevelopment.cs @@ -0,0 +1,15 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class InstrumentationDevelopment +{ + /// + /// Gets or sets the configuration for .NET language-specific instrumentation libraries. + /// + [YamlMember(Alias = "dotnet")] + public DotNetInstrumentation? DotNet { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/LoggerProviderConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/LoggerProviderConfiguration.cs new file mode 100644 index 0000000000..689e4887e4 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/LoggerProviderConfiguration.cs @@ -0,0 +1,15 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class LoggerProviderConfiguration +{ + /// + /// Gets or sets the processors for the logger provider. + /// + [YamlMember(Alias = "processors")] + public Dictionary Processors { get; set; } = new(); +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/MeterProviderConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/MeterProviderConfiguration.cs new file mode 100644 index 0000000000..4b64f8e9a2 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/MeterProviderConfiguration.cs @@ -0,0 +1,15 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class MeterProviderConfiguration +{ + /// + /// Gets or sets the readers for the meter provider. + /// + [YamlMember(Alias = "readers")] + public Dictionary Readers { get; set; } = new(); +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs new file mode 100644 index 0000000000..5dcce05765 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs @@ -0,0 +1,96 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using 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 certificate file used to verify a server's TLS credentials. + /// Absolute path to certificate file in PEM format. + /// If omitted or null, system default certificate verification is used for secure connections. + /// + [YamlMember(Alias = "certificate_file")] + public string? CertificateFile { get; set; } + + /// + /// Gets or sets the mTLS private client key. + /// Absolute path to client key file in PEM format. If set, client_certificate_file must also be set. + /// If omitted or null, mTLS is not used. + /// + [YamlMember(Alias = "client_key_file")] + public string? ClientKeyFile { get; set; } + + /// + /// Gets or sets the mTLS client certificate. + /// Absolute path to client certificate file in PEM format. If set, client_key_file must also be set. + /// If omitted or null, mTLS is not used. + /// + [YamlMember(Alias = "client_certificate_file")] + public string? ClientCertificateFile { 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 compression algorithm for the exporter. + /// Values include: gzip, none. Implementations may support other compression algorithms. + /// If omitted or null, none is used. + /// + [YamlMember(Alias = "compression")] + public string? Compression { 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; + + /// + /// Gets or sets the encoding for the exporter. + /// Supported values include: json, protobuf. If omitted or null, protobuf is used. + /// + [YamlMember(Alias = "encoding")] + public string? Encoding { get; set; } + + /// + /// Gets or sets the temporality preference for the exporter. + /// Supported values include: cumulative, delta. If omitted or null, cumulative is used. + /// + [YamlMember(Alias = "temporality_preference")] + public string? TemporalityPreference { get; set; } + + /// + /// Gets or sets the default histogram aggregation for the exporter. + /// Supported values include: explicit_bucket_histogram, base2_exponential_bucket_histogram. + /// If omitted or null, explicit_bucket_histogram is used. + /// + [YamlMember(Alias = "default_histogram_aggregation")] + public string? DefaultHistogramAggregation { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs new file mode 100644 index 0000000000..40edcfd5b3 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs @@ -0,0 +1,96 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using 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 certificate file used to verify a server's TLS credentials. + /// Absolute path to certificate file in PEM format. + /// If omitted or null, system default certificate verification is used for secure connections. + /// + [YamlMember(Alias = "certificate_file")] + public string? CertificateFile { get; set; } + + /// + /// Gets or sets the mTLS private client key. + /// Absolute path to client key file in PEM format. If set, client_certificate_file must also be set. + /// If omitted or null, mTLS is not used. + /// + [YamlMember(Alias = "client_key_file")] + public string? ClientKeyFile { get; set; } + + /// + /// Gets or sets the mTLS client certificate. + /// Absolute path to client certificate file in PEM format. If set, client_key_file must also be set. + /// If omitted or null, mTLS is not used. + /// + [YamlMember(Alias = "client_certificate_file")] + public string? ClientCertificateFile { 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 compression algorithm for the exporter. + /// Values include: gzip, none. Implementations may support other compression algorithms. + /// If omitted or null, none is used. + /// + [YamlMember(Alias = "compression")] + public string? Compression { 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; + + /// + /// Gets or sets the encoding for the exporter. + /// Supported values include: json, protobuf. If omitted or null, protobuf is used. + /// + [YamlMember(Alias = "encoding")] + public string? Encoding { get; set; } + + /// + /// Gets or sets the temporality preference for the exporter. + /// Supported values include: cumulative, delta. If omitted or null, cumulative is used. + /// + [YamlMember(Alias = "temporality_preference")] + public string? TemporalityPreference { get; set; } + + /// + /// Gets or sets the default histogram aggregation for the exporter. + /// Supported values include: explicit_bucket_histogram, base2_exponential_bucket_histogram. + /// If omitted or null, explicit_bucket_histogram is used. + /// + [YamlMember(Alias = "default_histogram_aggregation")] + public string? DefaultHistogramAggregation { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EnvVarTypeConverter.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EnvVarTypeConverter.cs new file mode 100644 index 0000000000..c84e561806 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EnvVarTypeConverter.cs @@ -0,0 +1,79 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.Globalization; +using System.Text.RegularExpressions; +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; + +internal class EnvVarTypeConverter : IYamlTypeConverter +{ + private static readonly HashSet SupportedTypes = + [ + typeof(string), + typeof(int), + typeof(long), + typeof(float), + typeof(double), + typeof(bool), + typeof(int?), + typeof(object), + ]; + + public bool Accepts(Type type) + { + return SupportedTypes.Contains(type); + } + + public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer) + { + if (parser.Current is not Scalar scalar) + { + throw new InvalidOperationException("Expected a scalar value in YAML but found null or a different node type."); + } + + var rawValue = scalar.Value ?? throw new InvalidOperationException("Scalar value is null."); + + var replacedValue = ReplaceEnvVariables(rawValue); + parser.MoveNext(); + + try + { + return type switch + { + Type t when t == typeof(string) => replacedValue, + Type t when t == typeof(int) => int.Parse(replacedValue), + Type t when t == typeof(long) => long.Parse(replacedValue), + Type t when t == typeof(float) => float.Parse(replacedValue, CultureInfo.InvariantCulture), + Type t when t == typeof(double) => double.Parse(replacedValue, CultureInfo.InvariantCulture), + Type t when t == typeof(bool) => bool.Parse(replacedValue), + Type t when t == typeof(int?) => int.Parse(replacedValue), + Type t when t == typeof(object) => replacedValue, + _ => throw new NotSupportedException($"Type {type.FullName} is not supported by the converter") + }; + } + catch (Exception ex) + { + throw new FormatException($"Error parsing value '{replacedValue}' as type {type.Name}", ex); + } + } + + public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer) + { + emitter.Emit(new Scalar(value?.ToString() ?? string.Empty)); + } + + private static string ReplaceEnvVariables(string input) + { + var pattern = @"\$\{([A-Z0-9_]+)\}"; + return Regex.Replace(input, pattern, match => + { + var varName = match.Groups[1].Value; + var envValue = Environment.GetEnvironmentVariable(varName); + return envValue ?? match.Value; + }); + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs new file mode 100644 index 0000000000..86edf6613c --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs @@ -0,0 +1,21 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; + +internal static class Parser +{ + public static Conf ParseYaml(string filePath) + { + var deserializer = new DeserializerBuilder() + // .WithNamingConvention(UnderscoredNamingConvention.Instance) + .WithTypeConverter(new EnvVarTypeConverter()) + .Build(); + + var yaml = File.ReadAllText(filePath); + var config = deserializer.Deserialize(yaml); + return config; + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/PropagatorConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/PropagatorConfiguration.cs new file mode 100644 index 0000000000..7c43ec53ca --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/PropagatorConfiguration.cs @@ -0,0 +1,21 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class PropagatorConfiguration +{ + /// + /// Gets or sets the composite propagator configuration. + /// + [YamlMember(Alias = "composite")] + public Dictionary? Composite { get; set; } + + /// + /// Gets or sets the composite list for the propagator. + /// + [YamlMember(Alias = "composite_list")] + public string? CompositeList { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs new file mode 100644 index 0000000000..d29b5e737a --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs @@ -0,0 +1,15 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class ReaderConfiguration +{ + /// + /// Gets or sets the exporter configuration for the reader. + /// + [YamlMember(Alias = "exporter")] + public ExporterConfig Exporter { get; set; } = new(); +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceAttribute.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceAttribute.cs new file mode 100644 index 0000000000..fd6b788dcb --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceAttribute.cs @@ -0,0 +1,27 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class ResourceAttribute +{ + /// + /// Gets or sets the name of the resource attribute. + /// + [YamlMember(Alias = "name")] + public string Name { get; set; } = null!; + + /// + /// Gets or sets the value of the resource attribute. + /// + [YamlMember(Alias = "value")] + public object Value { get; set; } = null!; + + /// + /// Gets or sets the type of the resource attribute. + /// + [YamlMember(Alias = "type")] + public string Type { get; set; } = "string"; +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs new file mode 100644 index 0000000000..3d2616141d --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs @@ -0,0 +1,27 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class ResourceConfiguration +{ + /// + /// Gets or sets the list of resource attributes. + /// + [YamlMember(Alias = "attributes")] + public List? Attributes { get; set; } + + /// + /// Gets or sets the attributes list for the resource. + /// + [YamlMember(Alias = "attributes_list")] + public string? AttributesList { get; set; } + + /// + /// Gets or sets the detection development configuration. + /// + [YamlMember(Alias = "detection/development")] + public DetectionDevelopment? DetectionDevelopment { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs new file mode 100644 index 0000000000..fa6d28d1ff --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs @@ -0,0 +1,16 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class SetDbStatementForTextConfuguration +{ + /// + /// Gets or sets a value indicating whether SQL statements are passed through the db.statement attribute. + /// If false, db.statement is recorded only for executing stored procedures. + /// + [YamlMember(Alias = "set_db_statement_for_text")] + public bool SetDbStatementForText { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs new file mode 100644 index 0000000000..8119cd082c --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs @@ -0,0 +1,16 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +internal class SetDocumentConfiguration +{ + /// + /// Gets or sets a value indicating whether the GraphQL instrumentation can pass raw queries through the graphql.document attribute. + /// Queries might contain sensitive information. + /// + [YamlMember(Alias = "set_document")] + public bool SetDocument { get; set; } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs new file mode 100644 index 0000000000..0de02e27b1 --- /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 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/ZipkinExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs new file mode 100644 index 0000000000..8b77c23cb6 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs @@ -0,0 +1,29 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using YamlDotNet.Serialization; +using static System.Net.WebRequestMethods; + +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/GeneralSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs index 732af52102..1eadd5fe7b 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + namespace OpenTelemetry.AutoInstrumentation.Configurations; internal class GeneralSettings : Settings @@ -32,7 +34,7 @@ internal class GeneralSettings : Settings /// public bool ProfilerEnabled { get; private set; } - protected override void OnLoad(Configuration configuration) + protected override void OnLoadEnvVar(Configuration configuration) { var providerPlugins = configuration.GetString(ConfigurationKeys.ProviderPlugins); if (providerPlugins != null) @@ -54,4 +56,47 @@ protected override void OnLoad(Configuration configuration) ProfilerEnabled = configuration.GetString(ConfigurationKeys.ProfilingEnabled) == "1"; } + + protected override void OnLoadFile(Conf configuration) + { + var detectors = configuration.Resource?.DetectionDevelopment?.Detectors; + if (detectors != null) + { + var enabledDetectors = new List(); +#if NET + if (detectors.Container != null) + { + enabledDetectors.Add(ResourceDetector.Container); + } +#endif + if (detectors.Process != null) + { + enabledDetectors.Add(ResourceDetector.Process); + } + + if (detectors.AzureAppService != null) + { + enabledDetectors.Add(ResourceDetector.AzureAppService); + } + + if (detectors.ProcessRuntime != null) + { + enabledDetectors.Add(ResourceDetector.ProcessRuntime); + } + + if (detectors.OperatingSystem != null) + { + enabledDetectors.Add(ResourceDetector.OperatingSystem); + } + + if (detectors.Host != null) + { + enabledDetectors.Add(ResourceDetector.Host); + } + + EnabledResourceDetectors = enabledDetectors; + } + + SetupSdk = configuration.Disabled; + } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs index 88a328ae19..0b3af6128d 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using OpenTelemetry.AutoInstrumentation.HeadersCapture; namespace OpenTelemetry.AutoInstrumentation.Configurations; @@ -31,28 +32,80 @@ internal InstrumentationOptions(Configuration configuration) SqlClientSetDbStatementForText = configuration.GetBool(ConfigurationKeys.Traces.InstrumentationOptions.SqlClientSetDbStatementForText) ?? false; } + internal InstrumentationOptions(DotNetTraces? instrumentationConfiguration) + { + if (instrumentationConfiguration != null) + { +#if NETFRAMEWORK + if (instrumentationConfiguration.AspNet != null) + { + AspNetInstrumentationCaptureRequestHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.AspNet.CaptureRequestHeaders, AdditionalTag.CreateHttpRequestCache); + AspNetInstrumentationCaptureResponseHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.AspNet.CaptureResponseHeaders, AdditionalTag.CreateHttpResponseCache); + } +#endif +#if NET + if (instrumentationConfiguration.AspNetCore != null) + { + AspNetCoreInstrumentationCaptureRequestHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.AspNetCore.CaptureRequestHeaders, AdditionalTag.CreateHttpRequestCache); + AspNetCoreInstrumentationCaptureResponseHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.AspNetCore.CaptureResponseHeaders, AdditionalTag.CreateHttpResponseCache); + } + + if (instrumentationConfiguration.EntityFrameworkCore != null) + { + EntityFrameworkCoreSetDbStatementForText = instrumentationConfiguration.EntityFrameworkCore.SetDbStatementForText; + } +#endif + if (instrumentationConfiguration.GraphQL != null) + { + GraphQLSetDocument = instrumentationConfiguration.GraphQL.SetDocument; + } + + if (instrumentationConfiguration.GrpcNetClient != null) + { + GrpcNetClientInstrumentationCaptureRequestMetadata = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.GrpcNetClient.CaptureRequestMetadata, AdditionalTag.CreateGrpcRequestCache); + GrpcNetClientInstrumentationCaptureResponseMetadata = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.GrpcNetClient.CaptureResponseMetadata, AdditionalTag.CreateGrpcResponseCache); + } + + if (instrumentationConfiguration.HttpClient != null) + { + HttpInstrumentationCaptureRequestHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.HttpClient.CaptureRequestHeaders, AdditionalTag.CreateHttpRequestCache); + HttpInstrumentationCaptureResponseHeaders = HeaderConfigurationExtensions.ParseHeaders(instrumentationConfiguration.HttpClient.CaptureResponseHeaders, AdditionalTag.CreateHttpResponseCache); + } + + if (instrumentationConfiguration.OracleMda != null) + { + OracleMdaSetDbStatementForText = instrumentationConfiguration.OracleMda.SetDbStatementForText; + } + + if (instrumentationConfiguration.SqlClient != null) + { + SqlClientSetDbStatementForText = instrumentationConfiguration.SqlClient.SetDbStatementForText; + } + } + } + #if NETFRAMEWORK /// /// Gets the list of HTTP request headers to be captured as the span tags by ASP.NET instrumentation. /// - public IReadOnlyList AspNetInstrumentationCaptureRequestHeaders { get; } + public IReadOnlyList AspNetInstrumentationCaptureRequestHeaders { get; } = []; /// /// Gets the list of HTTP response headers to be captured as the span tags by ASP.NET instrumentation. /// - public IReadOnlyList AspNetInstrumentationCaptureResponseHeaders { get; } + public IReadOnlyList AspNetInstrumentationCaptureResponseHeaders { get; } = []; #endif #if NET /// /// Gets the list of HTTP request headers to be captured as the span tags by ASP.NET Core instrumentation. /// - public IReadOnlyList AspNetCoreInstrumentationCaptureRequestHeaders { get; } + public IReadOnlyList AspNetCoreInstrumentationCaptureRequestHeaders { get; } = []; /// /// Gets the list of HTTP response headers to be captured as the span tags by ASP.NET Core instrumentation. /// - public IReadOnlyList AspNetCoreInstrumentationCaptureResponseHeaders { get; } + public IReadOnlyList AspNetCoreInstrumentationCaptureResponseHeaders { get; } = []; /// /// Gets a value indicating whether text query in Entity Framework Core can be passed as a db.statement tag. @@ -68,22 +121,22 @@ internal InstrumentationOptions(Configuration configuration) /// /// Gets the list of request metadata to be captured as the span tags by Grpc.Net.Client instrumentation. /// - public IReadOnlyList GrpcNetClientInstrumentationCaptureRequestMetadata { get; } + public IReadOnlyList GrpcNetClientInstrumentationCaptureRequestMetadata { get; } = []; /// /// Gets the list of response metadata to be captured as the span tags by Grpc.Net.Client instrumentation. /// - public IReadOnlyList GrpcNetClientInstrumentationCaptureResponseMetadata { get; } + public IReadOnlyList GrpcNetClientInstrumentationCaptureResponseMetadata { get; } = []; /// /// Gets the list of HTTP request headers to be captured as the span tags by HTTP instrumentation. /// - public IReadOnlyList HttpInstrumentationCaptureRequestHeaders { get; } + public IReadOnlyList HttpInstrumentationCaptureRequestHeaders { get; } = []; /// /// Gets the list of HTTP response headers to be captured as the span tags by HTTP instrumentation. /// - public IReadOnlyList HttpInstrumentationCaptureResponseHeaders { get; } + public IReadOnlyList HttpInstrumentationCaptureResponseHeaders { get; } = []; /// /// Gets a value indicating whether text query in Oracle Client can be passed as a db.statement tag. diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs index 7d98e346e2..5a27fc609a 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs @@ -1,8 +1,10 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using OpenTelemetry.AutoInstrumentation.Configurations.Otlp; using OpenTelemetry.AutoInstrumentation.Logging; +using YamlDotNet.Core.Tokens; namespace OpenTelemetry.AutoInstrumentation.Configurations; @@ -43,7 +45,7 @@ internal class LogSettings : Settings /// public OtlpSettings? OtlpSettings { get; private set; } - protected override void OnLoad(Configuration configuration) + protected override void OnLoadEnvVar(Configuration configuration) { LogsEnabled = configuration.GetBool(ConfigurationKeys.Logs.LogsEnabled) ?? true; LogExporters = ParseLogExporter(configuration); @@ -64,6 +66,50 @@ protected override void OnLoad(Configuration configuration) enabledConfigurationTemplate: ConfigurationKeys.Logs.EnabledLogsInstrumentationTemplate); } + protected override void OnLoadFile(Conf configuration) + { + if (configuration.LoggerProvider != null && + configuration.LoggerProvider.Processors != null && + configuration.LoggerProvider.Processors.TryGetValue("batch", out var batchProcessorConfig)) + { + LogsEnabled = true; + var logExporters = new List(); + var exporters = batchProcessorConfig.Exporter; + if (exporters != null) + { + if (exporters.OtlpGrpc != null) + { + logExporters.Add(LogExporter.Otlp); + OtlpSettings = new OtlpSettings(OtlpSignalType.Logs, exporters.OtlpGrpc); + } + + if (exporters.OtlpHttp != null) + { + logExporters.Add(LogExporter.Otlp); + OtlpSettings = new OtlpSettings(OtlpSignalType.Logs, exporters.OtlpHttp); + } + + if (exporters.Console != null) + { + logExporters.Add(LogExporter.Console); + } + + LogExporters = logExporters; + } + } + else + { + LogsEnabled = false; + } + + var logsInstrumentations = configuration.InstrumentationDevelopment?.DotNet?.Logs; + + if (logsInstrumentations != null) + { + EnabledInstrumentations = logsInstrumentations.GetEnabledInstrumentations(); + } + } + private static IReadOnlyList ParseLogExporter(Configuration configuration) { var logExporterEnvVar = configuration.GetString(ConfigurationKeys.Logs.Exporter); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs index a3a54e2c6e..15646bc256 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using System.Xml; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using OpenTelemetry.AutoInstrumentation.Configurations.Otlp; using OpenTelemetry.AutoInstrumentation.Logging; @@ -38,7 +40,7 @@ internal class MetricSettings : Settings /// public OtlpSettings? OtlpSettings { get; private set; } - protected override void OnLoad(Configuration configuration) + protected override void OnLoadEnvVar(Configuration configuration) { MetricExporters = ParseMetricExporter(configuration); if (MetricExporters.Contains(MetricsExporter.Otlp)) @@ -66,6 +68,67 @@ protected override void OnLoad(Configuration configuration) MetricsEnabled = configuration.GetBool(ConfigurationKeys.Metrics.MetricsEnabled) ?? true; } + protected override void OnLoadFile(Conf configuration) + { + var metricExporters = new List(); + + if (configuration.MeterProvider != null && + configuration.MeterProvider.Readers != null && + configuration.MeterProvider.Readers.TryGetValue("periodic", out var periodicReader) && + periodicReader != null) + { + var exporters = periodicReader.Exporter; + if (exporters != null) + { + if (exporters.OtlpGrpc != null) + { + metricExporters.Add(MetricsExporter.Otlp); + OtlpSettings = new OtlpSettings(OtlpSignalType.Metrics, exporters.OtlpGrpc); + } + + if (exporters.OtlpHttp != null) + { + metricExporters.Add(MetricsExporter.Otlp); + OtlpSettings = new OtlpSettings(OtlpSignalType.Metrics, exporters.OtlpHttp); + } + + if (exporters.Console != null) + { + metricExporters.Add(MetricsExporter.Console); + } + } + } + + if (configuration.MeterProvider != null && + configuration.MeterProvider.Readers != null && + configuration.MeterProvider.Readers.TryGetValue("pull", out var pullReader) && + pullReader != null) + { + var exporters = pullReader.Exporter; + if (exporters != null) + { + if (exporters.Prometheus != null) + { + metricExporters.Add(MetricsExporter.Prometheus); + } + } + } + + MetricExporters = metricExporters; + + MetricsEnabled = configuration.MeterProvider != null && + configuration.MeterProvider.Readers != null && + (configuration.MeterProvider.Readers.ContainsKey("periodic") || + configuration.MeterProvider.Readers.ContainsKey("pull")); + + var metricsInstrumentations = configuration.InstrumentationDevelopment?.DotNet?.Metrics; + + if (metricsInstrumentations != null) + { + EnabledInstrumentations = metricsInstrumentations.GetEnabledInstrumentations(); + } + } + private static IReadOnlyList ParseMetricExporter(Configuration configuration) { var metricsExporterEnvVar = configuration.GetString(ConfigurationKeys.Metrics.Exporter); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs index 366ad01c8d..c5a8dab976 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,46 @@ public void CopyTo(OtlpExporterOptions options) } } + private static string? CombineHeaders(List
? headers, string? headersList) + { + var headerDict = new Dictionary(StringComparer.OrdinalIgnoreCase); + + // Parse headersList (lower priority) + 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; + } + } + } + } + + // Override with headers (higher priority) + 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/SdkSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs index c0c0b14725..7b5d24be1b 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using System.Diagnostics.CodeAnalysis; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using OpenTelemetry.AutoInstrumentation.Logging; namespace OpenTelemetry.AutoInstrumentation.Configurations; @@ -16,14 +17,88 @@ internal class SdkSettings : Settings /// /// Gets the list of propagators to be used. /// - public IList Propagators { get; private set; } = new List(); + public IList Propagators { get; private set; } = []; - protected override void OnLoad(Configuration configuration) + /// + /// Gets the attribute limits. + /// + public AttributeLimits AttributeLimits { get; private set; } = new(); + + protected override void OnLoadEnvVar(Configuration configuration) { + AttributeLimits = new AttributeLimits( + attributeCountLimit: configuration.GetInt32(ConfigurationKeys.Sdk.AttributeCountLimit), + attributeValueLengthLimit: configuration.GetInt32(ConfigurationKeys.Sdk.AttributeValueLengthLimit)); + Propagators = ParsePropagator(configuration); } - private static IList ParsePropagator(Configuration configuration) + protected override void OnLoadFile(Conf configuration) + { + AttributeLimits = configuration.AttributeLimits; + + if (configuration.Propagator == null) + { + return; + } + + var seenPropagators = new HashSet(); + var resolvedPropagators = new List(); + + if (configuration.Propagator.Composite is Dictionary compositeDict) + { + foreach (var key in compositeDict.Keys) + { + if (seenPropagators.Add(key)) + { + resolvedPropagators.Add(key); + } + } + } + + if (string.IsNullOrEmpty(configuration.Propagator.CompositeList)) + { + var list = configuration.Propagator.CompositeList!.Split(Constants.ConfigurationValues.Separator); + foreach (var item in list) + { + if (seenPropagators.Add(item)) + { + resolvedPropagators.Add(item); + } + } + } + + foreach (var propagatorName in resolvedPropagators) + { + switch (propagatorName.ToLowerInvariant()) + { + case Constants.ConfigurationValues.Propagators.W3CTraceContext: + Propagators.Add(Propagator.W3CTraceContext); + break; + case Constants.ConfigurationValues.Propagators.W3CBaggage: + Propagators.Add(Propagator.W3CBaggage); + break; + case Constants.ConfigurationValues.Propagators.B3Multi: + Propagators.Add(Propagator.B3Multi); + break; + case Constants.ConfigurationValues.Propagators.B3Single: + Propagators.Add(Propagator.B3Single); + break; + default: + var unsupportedMessage = $"Propagator '{propagatorName}' is not supported."; + Logger.Error(unsupportedMessage); + + if (string.Equals(configuration.LogLevel, "fail_fast", StringComparison.OrdinalIgnoreCase)) + { + throw new NotSupportedException(unsupportedMessage); + } + + break; + } + } + } + + private static List ParsePropagator(Configuration configuration) { var propagatorEnvVar = configuration.GetString(ConfigurationKeys.Sdk.Propagators); var propagators = new List(); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs index eece253424..99a9ed891f 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs @@ -1,6 +1,9 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; + namespace OpenTelemetry.AutoInstrumentation.Configurations; /// @@ -11,15 +14,34 @@ internal abstract class Settings public static T FromDefaultSources(bool failFast) where T : Settings, new() { - var configuration = new Configuration(failFast, new EnvironmentConfigurationSource(failFast)); - var settings = new T(); - settings.Load(configuration); - return settings; + var isConfigFileEnabled = Environment.GetEnvironmentVariable("OTEL_EXPERIMENTAL_CONFIG_FILE_ENABLED") == "true"; + + if (isConfigFileEnabled) + { + var configFile = Environment.GetEnvironmentVariable("OTEL_EXPERIMENTAL_CONFIG_FILE") ?? "config.yaml"; + var config = Parser.ParseYaml(configFile); + Console.WriteLine("Parsed YAML configuration."); + var settings = new T(); + settings.LoadFile(config); + return settings; + } + else + { + var configuration = new Configuration(failFast, new EnvironmentConfigurationSource(failFast)); + var settings = new T(); + settings.LoadEnvVar(configuration); + return settings; + } + } + + public void LoadEnvVar(Configuration configuration) + { + OnLoadEnvVar(configuration); } - public void Load(Configuration configuration) + public void LoadFile(Conf configuration) { - OnLoad(configuration); + OnLoadFile(configuration); } /// @@ -27,5 +49,12 @@ public void Load(Configuration configuration) /// using the specified to initialize values. /// /// The to use when retrieving configuration values. - protected abstract void OnLoad(Configuration configuration); + protected abstract void OnLoadEnvVar(Configuration configuration); + + /// + /// Initializes a new instance of the class + /// using the specified to initialize values. + /// + /// The to use when retrieving configuration values. + protected abstract void OnLoadFile(Conf configuration); } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs index 69e21d9e07..869bd56f38 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; @@ -53,14 +54,35 @@ internal class TracerSettings : Settings /// public OtlpSettings? OtlpSettings { get; private set; } - protected override void OnLoad(Configuration configuration) + /// + /// Gets tracing Zipkin Settings. + /// + public ZipkinExporterConfig? ZipkinSettings { get; private set; } + + /// + /// Gets tracing Batch Processor Configuration. + /// + public BatchProcessorConfig BatchProcessorConfig { get; private set; } = new(); + + protected override void OnLoadEnvVar(Configuration configuration) { + BatchProcessorConfig = new BatchProcessorConfig( + scheduleDelay: configuration.GetInt32(ConfigurationKeys.Traces.BatchSpanProcessorConfig.ScheduleDelay), + exportTimeout: configuration.GetInt32(ConfigurationKeys.Traces.BatchSpanProcessorConfig.ExportTimeout), + maxQueueSize: configuration.GetInt32(ConfigurationKeys.Traces.BatchSpanProcessorConfig.MaxQueueSize), + maxExportBatchSize: configuration.GetInt32(ConfigurationKeys.Traces.BatchSpanProcessorConfig.MaxExportBatchSize)); + TracesExporters = ParseTracesExporter(configuration); if (TracesExporters.Contains(TracesExporter.Otlp)) { OtlpSettings = new OtlpSettings(OtlpSignalType.Traces, configuration); } + if (TracesExporters.Contains(TracesExporter.Zipkin)) + { + ZipkinSettings = new ZipkinExporterConfig(configuration.GetString(ConfigurationKeys.Traces.ZipkinEndpoint)); + } + var instrumentationEnabledByDefault = configuration.GetBool(ConfigurationKeys.Traces.TracesInstrumentationEnabled) ?? configuration.GetBool(ConfigurationKeys.InstrumentationEnabled) ?? true; @@ -93,6 +115,58 @@ protected override void OnLoad(Configuration configuration) InstrumentationOptions = new InstrumentationOptions(configuration); } + protected override void OnLoadFile(Conf 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; + } + + var tracesInstrumentations = configuration.InstrumentationDevelopment?.DotNet?.Traces; + if (tracesInstrumentations != null) + { + EnabledInstrumentations = tracesInstrumentations.GetEnabledInstrumentations(); + } + + InstrumentationOptions = new InstrumentationOptions(tracesInstrumentations); + } + private static IReadOnlyList ParseTracesExporter(Configuration configuration) { var tracesExporterEnvVar = configuration.GetString(ConfigurationKeys.Traces.Exporter); diff --git a/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/HeaderConfigurationExtensions.cs b/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/HeaderConfigurationExtensions.cs index 38e90be5b3..8d858bca27 100644 --- a/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/HeaderConfigurationExtensions.cs +++ b/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/HeaderConfigurationExtensions.cs @@ -9,11 +9,28 @@ internal static class HeaderConfigurationExtensions { public static IReadOnlyList ParseHeaders(this Configuration source, string key, Func stringToHeaderCacheConverter) { - var headers = source.ParseList(key, ','); + var headers = source.ParseList(key, Constants.ConfigurationValues.Separator); if (headers.Count == 0) { - return Array.Empty(); + return []; + } + + return headers.Select(stringToHeaderCacheConverter).ToArray(); + } + + public static IReadOnlyList ParseHeaders(string? headersList, Func stringToHeaderCacheConverter) + { + if (string.IsNullOrWhiteSpace(headersList)) + { + return []; + } + + var headers = headersList!.Split([Constants.ConfigurationValues.Separator], StringSplitOptions.RemoveEmptyEntries); + + if (headers.Length == 0) + { + return []; } return headers.Select(stringToHeaderCacheConverter).ToArray(); diff --git a/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj b/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj index 11b865a9c1..bca305f3b2 100644 --- a/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj +++ b/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj @@ -43,6 +43,7 @@ + From 7e9805b856f43886163b493ff1984d4e12e4a33b Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 25 Jun 2025 09:19:21 +0200 Subject: [PATCH 02/28] create method to get enabled detectors --- .../FileBasedConfiguration/DotNetDetectors.cs | 26 ++++++++++++++ .../Configurations/GeneralSettings.cs | 34 +------------------ 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetDetectors.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetDetectors.cs index 4b0a650a39..ba8fb12964 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetDetectors.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetDetectors.cs @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using System.Reflection; using YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; @@ -13,11 +14,13 @@ internal class DotNetDetectors [YamlMember(Alias = "azureappservice")] public object? AzureAppService { get; set; } +#if NET /// /// Gets or sets the container detector configuration. /// [YamlMember(Alias = "container")] public object? Container { get; set; } +#endif /// /// Gets or sets the host detector configuration. @@ -42,4 +45,27 @@ internal class DotNetDetectors /// [YamlMember(Alias = "processruntime")] public object? ProcessRuntime { get; set; } + + /// + /// Returns the list of enabled resource detectors. + /// + public IReadOnlyList GetEnabledResourceDetector() + { + var enabled = new List(); + var properties = typeof(DotNetDetectors).GetProperties(BindingFlags.Instance | BindingFlags.Public); + + foreach (var prop in properties) + { + var value = prop.GetValue(this); + if (value != null) + { + if (Enum.TryParse(prop.Name, out var resourceDetector)) + { + enabled.Add(resourceDetector); + } + } + } + + return enabled; + } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs index 1eadd5fe7b..c64c087976 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs @@ -62,39 +62,7 @@ protected override void OnLoadFile(Conf configuration) var detectors = configuration.Resource?.DetectionDevelopment?.Detectors; if (detectors != null) { - var enabledDetectors = new List(); -#if NET - if (detectors.Container != null) - { - enabledDetectors.Add(ResourceDetector.Container); - } -#endif - if (detectors.Process != null) - { - enabledDetectors.Add(ResourceDetector.Process); - } - - if (detectors.AzureAppService != null) - { - enabledDetectors.Add(ResourceDetector.AzureAppService); - } - - if (detectors.ProcessRuntime != null) - { - enabledDetectors.Add(ResourceDetector.ProcessRuntime); - } - - if (detectors.OperatingSystem != null) - { - enabledDetectors.Add(ResourceDetector.OperatingSystem); - } - - if (detectors.Host != null) - { - enabledDetectors.Add(ResourceDetector.Host); - } - - EnabledResourceDetectors = enabledDetectors; + EnabledResourceDetectors = detectors.GetEnabledResourceDetector(); } SetupSdk = configuration.Disabled; From 0ecd47a74d52c57861e9e070a35c1381aaf8c2d3 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 25 Jun 2025 09:20:30 +0200 Subject: [PATCH 03/28] remove unused properties --- .../OtlpGrpcExporterConfig.cs | 54 ------------------- .../OtlpHttpExporterConfig.cs | 54 ------------------- 2 files changed, 108 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs index 5dcce05765..1692329ab5 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs @@ -15,30 +15,6 @@ internal class OtlpGrpcExporterConfig [YamlMember(Alias = "endpoint")] public string? Endpoint { get; set; } - /// - /// Gets or sets the certificate file used to verify a server's TLS credentials. - /// Absolute path to certificate file in PEM format. - /// If omitted or null, system default certificate verification is used for secure connections. - /// - [YamlMember(Alias = "certificate_file")] - public string? CertificateFile { get; set; } - - /// - /// Gets or sets the mTLS private client key. - /// Absolute path to client key file in PEM format. If set, client_certificate_file must also be set. - /// If omitted or null, mTLS is not used. - /// - [YamlMember(Alias = "client_key_file")] - public string? ClientKeyFile { get; set; } - - /// - /// Gets or sets the mTLS client certificate. - /// Absolute path to client certificate file in PEM format. If set, client_key_file must also be set. - /// If omitted or null, mTLS is not used. - /// - [YamlMember(Alias = "client_certificate_file")] - public string? ClientCertificateFile { get; set; } - /// /// Gets or sets the headers for the exporter. /// Configure headers. Entries have higher priority than entries from headers_list. @@ -56,14 +32,6 @@ internal class OtlpGrpcExporterConfig [YamlMember(Alias = "headers_list")] public string? HeadersList { get; set; } - /// - /// Gets or sets the compression algorithm for the exporter. - /// Values include: gzip, none. Implementations may support other compression algorithms. - /// If omitted or null, none is used. - /// - [YamlMember(Alias = "compression")] - public string? Compression { 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). @@ -71,26 +39,4 @@ internal class OtlpGrpcExporterConfig /// [YamlMember(Alias = "timeout")] public int? Timeout { get; set; } = 10000; - - /// - /// Gets or sets the encoding for the exporter. - /// Supported values include: json, protobuf. If omitted or null, protobuf is used. - /// - [YamlMember(Alias = "encoding")] - public string? Encoding { get; set; } - - /// - /// Gets or sets the temporality preference for the exporter. - /// Supported values include: cumulative, delta. If omitted or null, cumulative is used. - /// - [YamlMember(Alias = "temporality_preference")] - public string? TemporalityPreference { get; set; } - - /// - /// Gets or sets the default histogram aggregation for the exporter. - /// Supported values include: explicit_bucket_histogram, base2_exponential_bucket_histogram. - /// If omitted or null, explicit_bucket_histogram is used. - /// - [YamlMember(Alias = "default_histogram_aggregation")] - public string? DefaultHistogramAggregation { get; set; } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs index 40edcfd5b3..f3154ae035 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs @@ -15,30 +15,6 @@ internal class OtlpHttpExporterConfig [YamlMember(Alias = "endpoint")] public string? Endpoint { get; set; } - /// - /// Gets or sets the certificate file used to verify a server's TLS credentials. - /// Absolute path to certificate file in PEM format. - /// If omitted or null, system default certificate verification is used for secure connections. - /// - [YamlMember(Alias = "certificate_file")] - public string? CertificateFile { get; set; } - - /// - /// Gets or sets the mTLS private client key. - /// Absolute path to client key file in PEM format. If set, client_certificate_file must also be set. - /// If omitted or null, mTLS is not used. - /// - [YamlMember(Alias = "client_key_file")] - public string? ClientKeyFile { get; set; } - - /// - /// Gets or sets the mTLS client certificate. - /// Absolute path to client certificate file in PEM format. If set, client_key_file must also be set. - /// If omitted or null, mTLS is not used. - /// - [YamlMember(Alias = "client_certificate_file")] - public string? ClientCertificateFile { get; set; } - /// /// Gets or sets the headers for the exporter. /// Configure headers. Entries have higher priority than entries from headers_list. @@ -56,14 +32,6 @@ internal class OtlpHttpExporterConfig [YamlMember(Alias = "headers_list")] public string? HeadersList { get; set; } - /// - /// Gets or sets the compression algorithm for the exporter. - /// Values include: gzip, none. Implementations may support other compression algorithms. - /// If omitted or null, none is used. - /// - [YamlMember(Alias = "compression")] - public string? Compression { 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). @@ -71,26 +39,4 @@ internal class OtlpHttpExporterConfig /// [YamlMember(Alias = "timeout")] public int? Timeout { get; set; } = 10000; - - /// - /// Gets or sets the encoding for the exporter. - /// Supported values include: json, protobuf. If omitted or null, protobuf is used. - /// - [YamlMember(Alias = "encoding")] - public string? Encoding { get; set; } - - /// - /// Gets or sets the temporality preference for the exporter. - /// Supported values include: cumulative, delta. If omitted or null, cumulative is used. - /// - [YamlMember(Alias = "temporality_preference")] - public string? TemporalityPreference { get; set; } - - /// - /// Gets or sets the default histogram aggregation for the exporter. - /// Supported values include: explicit_bucket_histogram, base2_exponential_bucket_histogram. - /// If omitted or null, explicit_bucket_histogram is used. - /// - [YamlMember(Alias = "default_histogram_aggregation")] - public string? DefaultHistogramAggregation { get; set; } } From f2aec25413e9ba5e25c3bfa77e411982bccec890 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 25 Jun 2025 09:21:09 +0200 Subject: [PATCH 04/28] fix lint --- .../Configurations/InstrumentationOptions.cs | 8 ++++---- .../Configurations/Otlp/OtlpSettings.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs index 0b3af6128d..cef1fac4b0 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/InstrumentationOptions.cs @@ -21,9 +21,8 @@ internal InstrumentationOptions(Configuration configuration) AspNetCoreInstrumentationCaptureRequestHeaders = configuration.ParseHeaders(ConfigurationKeys.Traces.InstrumentationOptions.AspNetCoreInstrumentationCaptureRequestHeaders, AdditionalTag.CreateHttpRequestCache); AspNetCoreInstrumentationCaptureResponseHeaders = configuration.ParseHeaders(ConfigurationKeys.Traces.InstrumentationOptions.AspNetCoreInstrumentationCaptureResponseHeaders, AdditionalTag.CreateHttpResponseCache); EntityFrameworkCoreSetDbStatementForText = configuration.GetBool(ConfigurationKeys.Traces.InstrumentationOptions.EntityFrameworkCoreSetDbStatementForText) ?? false; -#endif - GraphQLSetDocument = configuration.GetBool(ConfigurationKeys.Traces.InstrumentationOptions.GraphQLSetDocument) ?? false; +#endif GrpcNetClientInstrumentationCaptureRequestMetadata = configuration.ParseHeaders(ConfigurationKeys.Traces.InstrumentationOptions.GrpcNetClientInstrumentationCaptureRequestMetadata, AdditionalTag.CreateGrpcRequestCache); GrpcNetClientInstrumentationCaptureResponseMetadata = configuration.ParseHeaders(ConfigurationKeys.Traces.InstrumentationOptions.GrpcNetClientInstrumentationCaptureResponseMetadata, AdditionalTag.CreateGrpcResponseCache); HttpInstrumentationCaptureRequestHeaders = configuration.ParseHeaders(ConfigurationKeys.Traces.InstrumentationOptions.HttpInstrumentationCaptureRequestHeaders, AdditionalTag.CreateHttpRequestCache); @@ -54,11 +53,12 @@ internal InstrumentationOptions(DotNetTraces? instrumentationConfiguration) { EntityFrameworkCoreSetDbStatementForText = instrumentationConfiguration.EntityFrameworkCore.SetDbStatementForText; } -#endif + if (instrumentationConfiguration.GraphQL != null) { GraphQLSetDocument = instrumentationConfiguration.GraphQL.SetDocument; } +#endif if (instrumentationConfiguration.GrpcNetClient != null) { @@ -111,12 +111,12 @@ internal InstrumentationOptions(DotNetTraces? instrumentationConfiguration) /// Gets a value indicating whether text query in Entity Framework Core can be passed as a db.statement tag. /// public bool EntityFrameworkCoreSetDbStatementForText { get; } -#endif /// /// Gets a value indicating whether GraphQL query can be passed as a Document tag. /// public bool GraphQLSetDocument { get; } +#endif /// /// Gets the list of request metadata to be captured as the span tags by Grpc.Net.Client instrumentation. diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs index c5a8dab976..7c17000407 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/Otlp/OtlpSettings.cs @@ -127,7 +127,7 @@ public void CopyTo(OtlpExporterOptions options) { headerDict[header!.Name!] = header!.Value!; } - } + } } return headerDict.Count == 0 From 4b64c8f228a3e4816a7c67e21db124b30e7086e2 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 25 Jun 2025 09:22:07 +0200 Subject: [PATCH 05/28] Add support for `OTEL_METRIC_EXPORT_INTERVAL` `OTEL_METRIC_EXPORT_TIMEOUT` --- .../Configurations/ConfigurationKeys.cs | 10 +++++ .../EnvironmentConfigurationMetricHelper.cs | 1 + .../ReaderConfiguration.cs | 43 +++++++++++++++++++ .../Configurations/MetricSettings.cs | 10 +++++ 4 files changed, 64 insertions(+) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs index ba5fca2177..f28afd9c0c 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs @@ -225,6 +225,16 @@ public static class Metrics /// Configuration key for additional names to be added to the meter at the startup. /// public const string AdditionalSources = "OTEL_DOTNET_AUTO_METRICS_ADDITIONAL_SOURCES"; + + /// + /// Configuration key for metric reader export interval. + /// + public const string ExportInterval = "OTEL_METRIC_EXPORT_INTERVAL"; + + /// + /// Configuration key for metric reader export timeout. + /// + public const string ExportTimeout = "OTEL_METRIC_EXPORT_TIMEOUT"; } /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationMetricHelper.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationMetricHelper.cs index fc473fb342..19acd778d1 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationMetricHelper.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/EnvironmentConfigurationMetricHelper.cs @@ -151,6 +151,7 @@ public static MeterProviderBuilder AddOtlpExporter(MeterProviderBuilder builder, { return builder.AddOtlpExporter((options, metricReaderOptions) => { + metricReaderOptions.PeriodicExportingMetricReaderOptions = settings.ReaderConfiguration.ToPeriodicExportingMetricReaderOptions(); // Copy Auto settings to SDK settings settings.OtlpSettings?.CopyTo(options); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs index d29b5e737a..6c5d6ad346 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs @@ -1,15 +1,58 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.Metrics; using YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; internal class ReaderConfiguration { + public ReaderConfiguration() + { + } + + public ReaderConfiguration(int? interval, int? timeout) + { + if (interval is not null) + { + Interval = interval.Value; + } + + if (timeout is not null) + { + Timeout = timeout.Value; + } + } + + /// + /// Gets or sets the delay interval (in milliseconds) between the start of two consecutive exports. + /// Value must be non-negative. + /// If omitted or null, 60000 is used. + /// + [YamlMember(Alias = "interval")] + public int Interval { get; set; } = 60000; + + /// + /// 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 = "timeout")] + public int Timeout { get; set; } = 30000; + /// /// Gets or sets the exporter configuration for the reader. /// [YamlMember(Alias = "exporter")] public ExporterConfig Exporter { get; set; } = new(); + + public PeriodicExportingMetricReaderOptions ToPeriodicExportingMetricReaderOptions() + { + return new PeriodicExportingMetricReaderOptions + { + ExportIntervalMilliseconds = Interval, + ExportTimeoutMilliseconds = Timeout + }; + } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs index 15646bc256..069428bfc6 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs @@ -40,8 +40,17 @@ internal class MetricSettings : Settings /// public OtlpSettings? OtlpSettings { get; private set; } + /// + /// Gets Reader configuration. + /// + public ReaderConfiguration ReaderConfiguration { get; private set; } = new(); + protected override void OnLoadEnvVar(Configuration configuration) { + ReaderConfiguration = new ReaderConfiguration( + interval: configuration.GetInt32(ConfigurationKeys.Metrics.ExportInterval), + timeout: configuration.GetInt32(ConfigurationKeys.Metrics.ExportTimeout)); + MetricExporters = ParseMetricExporter(configuration); if (MetricExporters.Contains(MetricsExporter.Otlp)) { @@ -77,6 +86,7 @@ protected override void OnLoadFile(Conf configuration) configuration.MeterProvider.Readers.TryGetValue("periodic", out var periodicReader) && periodicReader != null) { + ReaderConfiguration = periodicReader; var exporters = periodicReader.Exporter; if (exporters != null) { From 42da3c4ebb9b351eb19872a739052552d90ad885 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Mon, 30 Jun 2025 10:38:07 +0200 Subject: [PATCH 06/28] Add Resources --- .../Configurations/ConfigurationKeys.cs | 10 ++ .../ResourceConfiguration.cs | 16 +++ .../Configurations/GeneralSettings.cs | 97 +++++++++++++++++++ .../Configurations/ResourceConfigurator.cs | 14 +-- .../Constants.cs | 5 + .../Instrumentation.cs | 6 +- .../Initializers/GraphQLInitializer.cs | 4 +- .../Logger/LoggerInitializer.cs | 2 +- 8 files changed, 138 insertions(+), 16 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs index f28afd9c0c..ef0d226311 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs @@ -51,6 +51,16 @@ internal partial class ConfigurationKeys /// public const string EnabledResourceDetectorTemplate = "OTEL_DOTNET_AUTO_{0}_RESOURCE_DETECTOR_ENABLED"; + /// + /// Configuration key template for resource attributes. + /// + public const string ResourceAttributes = "OTEL_RESOURCE_ATTRIBUTES"; + + /// + /// Configuration key for setting the service name. + /// + public const string ServiceName = "OTEL_SERVICE_NAME"; + /// /// Configuration keys for traces. /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs index 3d2616141d..7199f091bf 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs @@ -24,4 +24,20 @@ internal class ResourceConfiguration /// [YamlMember(Alias = "detection/development")] public DetectionDevelopment? DetectionDevelopment { get; set; } + + public List> ParseAttributes() + { + var result = new List>(); + if (Attributes == null) + { + return result; + } + + foreach (var attr in Attributes) + { + result.Add(new KeyValuePair(attr.Name, attr.Value)); + } + + return result; + } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs index c64c087976..a1453b173e 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs @@ -17,6 +17,11 @@ internal class GeneralSettings : Settings /// public IReadOnlyList EnabledResourceDetectors { get; private set; } = new List(); + /// + /// Gets the list of enabled resources. + /// + public IReadOnlyList> Resources { get; private set; } = new List>(); + /// /// Gets a value indicating whether the event should trigger /// the flushing of telemetry data. @@ -45,6 +50,35 @@ protected override void OnLoadEnvVar(Configuration configuration) } } + var baseResources = new List> + { + new(Constants.DistributionAttributes.TelemetryDistroNameAttributeName, Constants.DistributionAttributes.TelemetryDistroNameAttributeValue), + new(Constants.DistributionAttributes.TelemetryDistroVersionAttributeName, AutoInstrumentationVersion.Version) + }; + + var serviceName = configuration.GetString(ConfigurationKeys.ServiceName); + + if (!string.IsNullOrEmpty(serviceName)) + { + baseResources.Add(new KeyValuePair(Constants.ResourceAttributes.AttributeServiceName, serviceName!)); + } + + var resourceAttributes = ParseResourceAttributes(configuration.GetString(ConfigurationKeys.ResourceAttributes)); + if (resourceAttributes != null && resourceAttributes.Count > 0) + { + foreach (var attr in resourceAttributes) + { + if (attr.Key == Constants.ResourceAttributes.AttributeServiceName && !string.IsNullOrEmpty(serviceName)) + { + continue; // OTEL_SERVICE_NAME takes precedence + } + + baseResources.Add(attr); + } + } + + Resources = baseResources; + var resourceDetectorsEnabledByDefault = configuration.GetBool(ConfigurationKeys.ResourceDetectorEnabled) ?? true; EnabledResourceDetectors = configuration.ParseEnabledEnumList( @@ -65,6 +99,69 @@ protected override void OnLoadFile(Conf configuration) EnabledResourceDetectors = detectors.GetEnabledResourceDetector(); } + var baseResources = new List> + { + new(Constants.DistributionAttributes.TelemetryDistroNameAttributeName, Constants.DistributionAttributes.TelemetryDistroNameAttributeValue), + new(Constants.DistributionAttributes.TelemetryDistroVersionAttributeName, AutoInstrumentationVersion.Version) + }; + + var resourceAttributesWithPriority = configuration.Resource?.ParseAttributes() ?? []; + + var resourceAttributes = ParseResourceAttributes(configuration.Resource?.AttributesList); + + var merged = new Dictionary(); + foreach (var kv in baseResources) + { + merged[kv.Key] = kv.Value; + } + + foreach (var kv in resourceAttributesWithPriority) + { + if (!merged.ContainsKey(kv.Key)) + { + merged[kv.Key] = kv.Value; + } + } + + if (resourceAttributes != null) + { + foreach (var kv in resourceAttributes) + { + if (!merged.ContainsKey(kv.Key)) + { + merged[kv.Key] = kv.Value; + } + } + } + + Resources = merged.ToList(); + SetupSdk = configuration.Disabled; } + + private static List> ParseResourceAttributes(string? resourceAttributes) + { + if (string.IsNullOrEmpty(resourceAttributes)) + { + return []; + } + + var attributeListSplitter = ','; + var attributeKeyValueSplitter = '='; + var attributes = new List>(); + + var rawAttributes = resourceAttributes!.Split(attributeListSplitter); + foreach (var rawKeyValuePair in rawAttributes) + { + var keyValuePair = rawKeyValuePair.Split(attributeKeyValueSplitter); + if (keyValuePair.Length != 2) + { + continue; + } + + attributes.Add(new KeyValuePair(keyValuePair[0].Trim(), keyValuePair[1].Trim())); + } + + return attributes; + } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs index a19e30063f..97cff12973 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs @@ -8,19 +8,13 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations; internal static class ResourceConfigurator { - internal const string ServiceNameAttribute = "service.name"; - - public static ResourceBuilder CreateResourceBuilder(IReadOnlyList enabledResourceDetectors) + public static ResourceBuilder CreateResourceBuilder(IReadOnlyList enabledResourceDetectors, IReadOnlyList> resources) { var resourceBuilder = ResourceBuilder .CreateEmpty() // Don't use CreateDefault because it puts service name unknown by default. .AddEnvironmentVariableDetector() .AddTelemetrySdk() - .AddAttributes(new KeyValuePair[] - { - new(Constants.DistributionAttributes.TelemetryDistroNameAttributeName, Constants.DistributionAttributes.TelemetryDistroNameAttributeValue), - new(Constants.DistributionAttributes.TelemetryDistroVersionAttributeName, AutoInstrumentationVersion.Version) - }); + .AddAttributes(resources); foreach (var enabledResourceDetector in enabledResourceDetectors) { @@ -39,10 +33,10 @@ public static ResourceBuilder CreateResourceBuilder(IReadOnlyList kvp.Key == ServiceNameAttribute)) + if (!resource.Attributes.Any(kvp => kvp.Key == Constants.ResourceAttributes.AttributeServiceName)) { // service.name was not configured yet use the fallback. - resourceBuilder.AddAttributes(new KeyValuePair[] { new(ServiceNameAttribute, ServiceNameConfigurator.GetFallbackServiceName()) }); + resourceBuilder.AddAttributes([new(Constants.ResourceAttributes.AttributeServiceName, ServiceNameConfigurator.GetFallbackServiceName())]); } var pluginManager = Instrumentation.PluginManager; diff --git a/src/OpenTelemetry.AutoInstrumentation/Constants.cs b/src/OpenTelemetry.AutoInstrumentation/Constants.cs index bee459c4af..7471950386 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Constants.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Constants.cs @@ -24,6 +24,11 @@ public static class HttpSpanAttributes public const string AttributeHttpResponseHeaderPrefix = "http.response.header"; } + public static class ResourceAttributes + { + public const string AttributeServiceName = "service.name"; + } + public static class ConfigurationValues { public const string None = "none"; diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentation.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentation.cs index 53d0d9f079..51cdceaa2d 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentation.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentation.cs @@ -134,7 +134,7 @@ public static void Initialize() var builder = Sdk .CreateTracerProviderBuilder() .InvokePluginsBefore(_pluginManager) - .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(GeneralSettings.Value.EnabledResourceDetectors)) + .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(GeneralSettings.Value.EnabledResourceDetectors, GeneralSettings.Value.Resources)) .UseEnvironmentVariables(LazyInstrumentationLoader, TracerSettings.Value, _pluginManager) .InvokePluginsAfter(_pluginManager); @@ -156,7 +156,7 @@ public static void Initialize() var builder = Sdk .CreateMeterProviderBuilder() .InvokePluginsBefore(_pluginManager) - .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(GeneralSettings.Value.EnabledResourceDetectors)) + .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(GeneralSettings.Value.EnabledResourceDetectors, GeneralSettings.Value.Resources)) .UseEnvironmentVariables(LazyInstrumentationLoader, MetricSettings.Value, _pluginManager) .InvokePluginsAfter(_pluginManager); @@ -355,7 +355,7 @@ private static void InitializeBufferProcessing(TimeSpan exportInterval, TimeSpan // TODO: plugins support var loggerProvider = loggerProviderBuilder! - .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(GeneralSettings.Value.EnabledResourceDetectors)) + .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(GeneralSettings.Value.EnabledResourceDetectors, GeneralSettings.Value.Resources)) .UseEnvironmentVariables(LazyInstrumentationLoader, LogSettings.Value, _pluginManager!) .Build(); Logger.Information("OpenTelemetry logger provider initialized."); diff --git a/src/OpenTelemetry.AutoInstrumentation/Loading/Initializers/GraphQLInitializer.cs b/src/OpenTelemetry.AutoInstrumentation/Loading/Initializers/GraphQLInitializer.cs index d2c60f7ad1..7ec88bcb79 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Loading/Initializers/GraphQLInitializer.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Loading/Initializers/GraphQLInitializer.cs @@ -29,10 +29,10 @@ public override void Initialize(ILifespanManager lifespanManager) var optionsType = Type.GetType("GraphQL.Telemetry.GraphQLTelemetryOptions, GraphQL")!; var optionsInstance = Activator.CreateInstance(optionsType)!; - +#if NET optionsType?.GetProperty("RecordDocument")? .SetValue(optionsInstance, _tracerSettings.InstrumentationOptions.GraphQLSetDocument); - +#endif _pluginManager.ConfigureTracesOptions(optionsInstance); initializerType.GetMethod("EnableAutoInstrumentation", BindingFlags.Public | BindingFlags.Static)! diff --git a/src/OpenTelemetry.AutoInstrumentation/Logger/LoggerInitializer.cs b/src/OpenTelemetry.AutoInstrumentation/Logger/LoggerInitializer.cs index 57a5020e28..17fc623f22 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Logger/LoggerInitializer.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Logger/LoggerInitializer.cs @@ -57,7 +57,7 @@ private static void AddOpenTelemetryLogs(ILoggingBuilder builder) builder.AddOpenTelemetry(options => { - options.SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(Instrumentation.GeneralSettings.Value.EnabledResourceDetectors)); + options.SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(Instrumentation.GeneralSettings.Value.EnabledResourceDetectors, Instrumentation.GeneralSettings.Value.Resources)); options.IncludeFormattedMessage = settings.IncludeFormattedMessage; From 8c182c82f79efac734ff8dcc96fc6d34e34f5122 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 9 Jul 2025 10:53:09 +0200 Subject: [PATCH 07/28] add unit test/ minor fixes --- .../Parser/EnvVarTypeConverter.cs | 10 +- .../ReaderConfiguration.cs | 2 +- .../Configurations/LogSettings.cs | 12 + .../Configurations/SdkSettings.cs | 2 +- .../Configurations/Settings.cs | 2 +- .../FileBased/DetectorsTests.cs | 47 +++ .../FilebasedGeneralSettingsTests.cs | 193 ++++++++++++ .../FileBased/FilebasedLogsSettingsTests.cs | 246 ++++++++++++++++ .../FilebasedMetricsSettingsTests.cs | 276 ++++++++++++++++++ .../FileBased/FilebasedSdkSettingsTests.cs | 119 ++++++++ .../FileBased/FilebasedTracesSettingsTests.cs | 256 ++++++++++++++++ .../FileBased/Files/TestFile.yaml | 112 +++++++ .../FileBased/Files/TestFileEnvVars.yaml | 102 +++++++ .../Configurations/FileBased/ParserTests.cs | 275 +++++++++++++++++ .../Configurations/PluginManagerTests.cs | 2 +- .../ServiceNameConfiguratorTests.cs | 4 +- .../Configurations/SettingsTests.cs | 2 +- ...Telemetry.AutoInstrumentation.Tests.csproj | 9 + 18 files changed, 1663 insertions(+), 8 deletions(-) create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/DetectorsTests.cs create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedLogsSettingsTests.cs create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedMetricsSettingsTests.cs create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedSdkSettingsTests.cs create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EnvVarTypeConverter.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EnvVarTypeConverter.cs index c84e561806..61884896af 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EnvVarTypeConverter.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EnvVarTypeConverter.cs @@ -32,7 +32,7 @@ public bool Accepts(Type type) { if (parser.Current is not Scalar scalar) { - throw new InvalidOperationException("Expected a scalar value in YAML but found null or a different node type."); + return rootDeserializer(type); } var rawValue = scalar.Value ?? throw new InvalidOperationException("Scalar value is null."); @@ -42,6 +42,14 @@ public bool Accepts(Type type) try { + if (string.IsNullOrWhiteSpace(replacedValue)) + { + if (Nullable.GetUnderlyingType(type) != null) + { + return null; + } + } + return type switch { Type t when t == typeof(string) => replacedValue, diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs index 6c5d6ad346..09f4d1534a 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs @@ -45,7 +45,7 @@ public ReaderConfiguration(int? interval, int? timeout) /// Gets or sets the exporter configuration for the reader. /// [YamlMember(Alias = "exporter")] - public ExporterConfig Exporter { get; set; } = new(); + public ExporterConfig? Exporter { get; set; } = new(); public PeriodicExportingMetricReaderOptions ToPeriodicExportingMetricReaderOptions() { diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs index 5a27fc609a..cda0e3f30c 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs @@ -45,6 +45,11 @@ internal class LogSettings : Settings /// public OtlpSettings? OtlpSettings { get; private set; } + /// + /// Gets tracing Batch Processor Configuration. + /// + public BatchProcessorConfig BatchProcessorConfig { get; private set; } = new(); + protected override void OnLoadEnvVar(Configuration configuration) { LogsEnabled = configuration.GetBool(ConfigurationKeys.Logs.LogsEnabled) ?? true; @@ -54,6 +59,12 @@ protected override void OnLoadEnvVar(Configuration configuration) OtlpSettings = new OtlpSettings(OtlpSignalType.Logs, configuration); } + BatchProcessorConfig = new BatchProcessorConfig( + scheduleDelay: configuration.GetInt32(ConfigurationKeys.Traces.BatchSpanProcessorConfig.ScheduleDelay), + exportTimeout: configuration.GetInt32(ConfigurationKeys.Traces.BatchSpanProcessorConfig.ExportTimeout), + maxQueueSize: configuration.GetInt32(ConfigurationKeys.Traces.BatchSpanProcessorConfig.MaxQueueSize), + maxExportBatchSize: configuration.GetInt32(ConfigurationKeys.Traces.BatchSpanProcessorConfig.MaxExportBatchSize)); + IncludeFormattedMessage = configuration.GetBool(ConfigurationKeys.Logs.IncludeFormattedMessage) ?? false; EnableLog4NetBridge = configuration.GetBool(ConfigurationKeys.Logs.EnableLog4NetBridge) ?? false; @@ -72,6 +83,7 @@ protected override void OnLoadFile(Conf configuration) configuration.LoggerProvider.Processors != null && configuration.LoggerProvider.Processors.TryGetValue("batch", out var batchProcessorConfig)) { + BatchProcessorConfig = batchProcessorConfig; LogsEnabled = true; var logExporters = new List(); var exporters = batchProcessorConfig.Exporter; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs index 7b5d24be1b..4ef5813a89 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs @@ -56,7 +56,7 @@ protected override void OnLoadFile(Conf configuration) } } - if (string.IsNullOrEmpty(configuration.Propagator.CompositeList)) + if (!string.IsNullOrEmpty(configuration.Propagator.CompositeList)) { var list = configuration.Propagator.CompositeList!.Split(Constants.ConfigurationValues.Separator); foreach (var item in list) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs index 99a9ed891f..8d7b0407a7 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs @@ -14,7 +14,7 @@ internal abstract class Settings public static T FromDefaultSources(bool failFast) where T : Settings, new() { - var isConfigFileEnabled = Environment.GetEnvironmentVariable("OTEL_EXPERIMENTAL_CONFIG_FILE_ENABLED") == "true"; + var isConfigFileEnabled = Environment.GetEnvironmentVariable("OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED") == "true"; if (isConfigFileEnabled) { diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/DetectorsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/DetectorsTests.cs new file mode 100644 index 0000000000..fb44a2fc64 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/DetectorsTests.cs @@ -0,0 +1,47 @@ +// 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 DetectorsTests +{ + [Fact] + public void GetEnabledResourceDetector_ReturnsCorrectEnabledDetectors() + { + var detectors = new DotNetDetectors + { + AzureAppService = new object(), + Host = new object(), + OperatingSystem = null, + Process = new object(), + ProcessRuntime = null + }; + +#if NET + detectors.Container = new object(); +#endif + + var result = detectors.GetEnabledResourceDetector(); + + var expected = new List + { + ResourceDetector.AzureAppService, + ResourceDetector.Host, + ResourceDetector.Process + }; + +#if NET + expected.Add(ResourceDetector.Container); +#endif + + Assert.Equal(expected.Count, result.Count); + foreach (var detector in expected) + { + Assert.Contains(detector, result); + } + } +} diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs new file mode 100644 index 0000000000..e5217a3d46 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs @@ -0,0 +1,193 @@ +// 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 FilebasedGeneralSettingsTests +{ + [Fact] + public void LoadFile_MergesBaseAndCustomResourceAttributes() + { + var resource = new ResourceConfiguration + { + AttributesList = "custom1=value1,custom2=value2", + Attributes = + [ + new() { Name = "custom1", Value = "OverridesAttributesList" }, + new() { Name = "custom3", Value = "value3" } + ] + }; + + var conf = new Conf { Resource = resource }; + var settings = new GeneralSettings(); + + settings.LoadFile(conf); + + var result = settings.Resources.ToDictionary(kv => kv.Key, kv => kv.Value); + + Assert.Equal("OverridesAttributesList", result["custom1"]); + Assert.Equal("value2", result["custom2"]); + Assert.Equal("value3", result["custom3"]); + + Assert.True(result.ContainsKey(Constants.DistributionAttributes.TelemetryDistroNameAttributeName)); + Assert.True(result.ContainsKey(Constants.DistributionAttributes.TelemetryDistroVersionAttributeName)); + } + + [Fact] + public void LoadFile_AttributesListOnly_IsParsedCorrectly() + { + var resource = new ResourceConfiguration + { + AttributesList = "key1=value1,key2=value2" + }; + + var conf = new Conf { Resource = resource }; + var settings = new GeneralSettings(); + + settings.LoadFile(conf); + + var result = settings.Resources.ToDictionary(kv => kv.Key, kv => kv.Value); + + Assert.Equal("value1", result["key1"]); + Assert.Equal("value2", result["key2"]); + } + + [Fact] + public void LoadFile_AttributesOnly_IsParsedCorrectly() + { + var resource = new ResourceConfiguration + { + Attributes = + [ + new() { Name = "a", Value = "1" }, + new() { Name = "b", Value = "2" } + ] + }; + + var conf = new Conf { Resource = resource }; + var settings = new GeneralSettings(); + + settings.LoadFile(conf); + + var result = settings.Resources.ToDictionary(kv => kv.Key, kv => kv.Value); + + Assert.Equal("1", result["a"]); + Assert.Equal("2", result["b"]); + } + + [Fact] + public void LoadFile_BaseAttributes_AreAlwaysIncluded() + { + var settings = new GeneralSettings(); + settings.LoadFile(new Conf()); + + var result = settings.Resources.ToDictionary(kv => kv.Key, kv => kv.Value); + + Assert.True(result.ContainsKey(Constants.DistributionAttributes.TelemetryDistroNameAttributeName)); + Assert.True(result.ContainsKey(Constants.DistributionAttributes.TelemetryDistroVersionAttributeName)); + } + + [Fact] + public void LoadFile_AttributesListOverwrittenByAttributes() + { + var resource = new ResourceConfiguration + { + AttributesList = "key1=fromList", + Attributes = + [ + new() { Name = "key1", Value = "fromAttributes" } + ] + }; + + var conf = new Conf { Resource = resource }; + var settings = new GeneralSettings(); + + settings.LoadFile(conf); + + var result = settings.Resources.ToDictionary(kv => kv.Key, kv => kv.Value); + + Assert.Equal("fromAttributes", result["key1"]); + } + + [Fact] + public void LoadFile_NullAttributesHandledGracefully() + { + var resource = new ResourceConfiguration + { + AttributesList = null, + Attributes = null + }; + + var conf = new Conf { Resource = resource }; + var settings = new GeneralSettings(); + + settings.LoadFile(conf); + + var result = settings.Resources.ToDictionary(kv => kv.Key, kv => kv.Value); + + Assert.True(result.ContainsKey(Constants.DistributionAttributes.TelemetryDistroNameAttributeName)); + Assert.True(result.ContainsKey(Constants.DistributionAttributes.TelemetryDistroVersionAttributeName)); + } + + [Fact] + public void LoadFile_EmptyAttributesList_StillIncludesBaseAttributes() + { + var resource = new ResourceConfiguration + { + AttributesList = string.Empty + }; + + var conf = new Conf { Resource = resource }; + var settings = new GeneralSettings(); + + settings.LoadFile(conf); + + var result = settings.Resources.ToDictionary(kv => kv.Key, kv => kv.Value); + + Assert.True(result.ContainsKey(Constants.DistributionAttributes.TelemetryDistroNameAttributeName)); + Assert.True(result.ContainsKey(Constants.DistributionAttributes.TelemetryDistroVersionAttributeName)); + } + + [Fact] + public void LoadFile_SetsSetupSdkFromDisabledFlag() + { + var conf = new Conf + { + Disabled = true + }; + + var settings = new GeneralSettings(); + settings.LoadFile(conf); + + Assert.True(settings.SetupSdk); + } + + [Fact] + public void LoadFile_SetsEnabledResourceDetectors() + { + var conf = new Conf + { + Resource = new ResourceConfiguration + { + DetectionDevelopment = new DetectionDevelopment + { + Detectors = new DotNetDetectors + { + OperatingSystem = new object(), + AzureAppService = new object() + } + } + } + }; + + var settings = new GeneralSettings(); + settings.LoadFile(conf); + + Assert.Contains(ResourceDetector.OperatingSystem, settings.EnabledResourceDetectors); + Assert.Contains(ResourceDetector.AzureAppService, settings.EnabledResourceDetectors); + } +} diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedLogsSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedLogsSettingsTests.cs new file mode 100644 index 0000000000..1045d49b6f --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedLogsSettingsTests.cs @@ -0,0 +1,246 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +using OpenTelemetry.Trace; +using Xunit; + +namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; + +public class FilebasedLogsSettingsTests +{ + [Fact] + public void LoadFile_SetsBatchProcessorAndExportersCorrectly() + { + var exporter = new ExporterConfig + { + OtlpGrpc = new OtlpGrpcExporterConfig + { + Endpoint = "http://localhost:4317/" + } + }; + + var batchProcessorConfig = new BatchProcessorConfig + { + ScheduleDelay = 2000, + ExportTimeout = 10000, + MaxQueueSize = 1024, + MaxExportBatchSize = 256, + Exporter = exporter + }; + + var conf = new Conf + { + LoggerProvider = new LoggerProviderConfiguration + { + Processors = new Dictionary + { + { "batch", batchProcessorConfig } + } + } + }; + + var settings = new LogSettings(); + + settings.LoadFile(conf); + + Assert.True(settings.LogsEnabled); + Assert.Single(settings.LogExporters); + Assert.Contains(LogExporter.Otlp, settings.LogExporters); + + Assert.NotNull(settings.OtlpSettings); + Assert.NotNull(settings.OtlpSettings.Endpoint); + Assert.Equal("http://localhost:4317/", settings.OtlpSettings.Endpoint.ToString()); + + Assert.Equal(2000, settings.BatchProcessorConfig.ScheduleDelay); + Assert.Equal(10000, settings.BatchProcessorConfig.ExportTimeout); + Assert.Equal(1024, settings.BatchProcessorConfig.MaxQueueSize); + Assert.Equal(256, settings.BatchProcessorConfig.MaxExportBatchSize); + } + + [Fact] + public void LoadFile_DisablesLogs_WhenNoBatchProcessorConfigured() + { + var conf = new Conf + { + LoggerProvider = new LoggerProviderConfiguration + { + Processors = [] + } + }; + + var settings = new LogSettings(); + + settings.LoadFile(conf); + + Assert.False(settings.LogsEnabled); + Assert.Empty(settings.LogExporters); + Assert.Null(settings.OtlpSettings); + } + + [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 Conf + { + LoggerProvider = new LoggerProviderConfiguration + { + Processors = new Dictionary + { + { "batch", batchProcessorConfig } + } + } + }; + + var settings = new LogSettings(); + + settings.LoadFile(conf); + + Assert.True(settings.LogsEnabled); + Assert.Single(settings.LogExporters); + Assert.Contains(LogExporter.Otlp, settings.LogExporters); + 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 Conf + { + LoggerProvider = new LoggerProviderConfiguration + { + Processors = new Dictionary + { + { "batch", batchProcessorConfig } + } + } + }; + + var settings = new LogSettings(); + + settings.LoadFile(conf); + + Assert.True(settings.LogsEnabled); + Assert.Single(settings.LogExporters); + Assert.Contains(LogExporter.Console, settings.LogExporters); + Assert.Null(settings.OtlpSettings); + } + + [Fact] + public void LoadFile_SetsMultipleExportersCorrectly() + { + var exporter = new ExporterConfig + { + OtlpGrpc = new OtlpGrpcExporterConfig { Endpoint = "http://localhost:4317/" }, + Console = new object() + }; + + var batchProcessorConfig = new BatchProcessorConfig + { + Exporter = exporter + }; + + var conf = new Conf + { + LoggerProvider = new LoggerProviderConfiguration + { + Processors = new Dictionary + { + { "batch", batchProcessorConfig } + } + } + }; + + var settings = new LogSettings(); + + settings.LoadFile(conf); + + Assert.True(settings.LogsEnabled); + Assert.Equal(2, settings.LogExporters.Count); + Assert.Contains(LogExporter.Otlp, settings.LogExporters); + Assert.Contains(LogExporter.Console, settings.LogExporters); + } + + [Fact] + public void LoadFile_HandlesNullExporterGracefully() + { + var batchProcessorConfig = new BatchProcessorConfig + { + Exporter = null + }; + + var conf = new Conf + { + LoggerProvider = new LoggerProviderConfiguration + { + Processors = new Dictionary + { + { "batch", batchProcessorConfig } + } + } + }; + + var settings = new LogSettings(); + + settings.LoadFile(conf); + + Assert.True(settings.LogsEnabled); + Assert.Empty(settings.LogExporters); + Assert.Null(settings.OtlpSettings); + } + + [Fact] + public void LoadFile_SetsEnabledInstrumentations_IfPresent() + { + var instrumentation = new DotNetInstrumentation + { + Logs = new DotNetLogs + { + ILogger = new object(), + Log4Net = new object(), + } + }; + + var conf = new Conf + { + InstrumentationDevelopment = new InstrumentationDevelopment + { + DotNet = instrumentation + } + }; + + var settings = new LogSettings(); + + settings.LoadFile(conf); + + Assert.NotNull(settings.EnabledInstrumentations); + Assert.Contains(LogInstrumentation.ILogger, settings.EnabledInstrumentations); + Assert.Contains(LogInstrumentation.Log4Net, settings.EnabledInstrumentations); + } +} diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedMetricsSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedMetricsSettingsTests.cs new file mode 100644 index 0000000000..536c9d1872 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedMetricsSettingsTests.cs @@ -0,0 +1,276 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +using OpenTelemetry.Trace; +using Xunit; + +namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; + +public class FilebasedMetricsSettingsTests +{ + [Fact] + public void LoadFile_SetsBatchProcessorAndExportersCorrectly() + { + var exporter = new ExporterConfig + { + OtlpGrpc = new OtlpGrpcExporterConfig + { + Endpoint = "http://localhost:4317/" + } + }; + + var readerConfig = new ReaderConfiguration + { + Interval = 1000, + Timeout = 30000, + Exporter = exporter + }; + + var conf = new Conf + { + MeterProvider = new MeterProviderConfiguration + { + Readers = new Dictionary + { + { "periodic", readerConfig } + } + } + }; + + var settings = new MetricSettings(); + settings.LoadFile(conf); + + Assert.True(settings.MetricsEnabled); + Assert.Single(settings.MetricExporters); + Assert.Contains(MetricsExporter.Otlp, settings.MetricExporters); + Assert.NotNull(settings.OtlpSettings); + Assert.NotNull(settings.OtlpSettings.Endpoint); + Assert.Equal("http://localhost:4317/", settings.OtlpSettings.Endpoint.ToString()); + + Assert.Equal(1000, settings.ReaderConfiguration.Interval); + Assert.Equal(30000, settings.ReaderConfiguration.Timeout); + } + + [Fact] + public void LoadFile_DisablesMetrics_WhenNoReadersConfigured() + { + var conf = new Conf + { + MeterProvider = new MeterProviderConfiguration + { + Readers = [] + } + }; + + var settings = new MetricSettings(); + settings.LoadFile(conf); + + Assert.False(settings.MetricsEnabled); + Assert.Empty(settings.MetricExporters); + Assert.Null(settings.OtlpSettings); + } + + [Fact] + public void LoadFile_SetsOtlpHttpExporterCorrectly() + { + var exporter = new ExporterConfig + { + OtlpHttp = new OtlpHttpExporterConfig + { + Endpoint = "http://localhost:4318/" + } + }; + + var readerConfig = new ReaderConfiguration + { + Exporter = exporter + }; + + var conf = new Conf + { + MeterProvider = new MeterProviderConfiguration + { + Readers = new Dictionary + { + { "periodic", readerConfig } + } + } + }; + + var settings = new MetricSettings(); + settings.LoadFile(conf); + + Assert.True(settings.MetricsEnabled); + Assert.Single(settings.MetricExporters); + Assert.Contains(MetricsExporter.Otlp, settings.MetricExporters); + 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 readerConfig = new ReaderConfiguration + { + Exporter = exporter + }; + + var conf = new Conf + { + MeterProvider = new MeterProviderConfiguration + { + Readers = new Dictionary + { + { "periodic", readerConfig } + } + } + }; + + var settings = new MetricSettings(); + settings.LoadFile(conf); + + Assert.True(settings.MetricsEnabled); + Assert.Single(settings.MetricExporters); + Assert.Contains(MetricsExporter.Console, settings.MetricExporters); + Assert.Null(settings.OtlpSettings); + } + + [Fact] + public void LoadFile_SetsPrometheusExporterCorrectly_FromPullReader() + { + var exporter = new ExporterConfig + { + Prometheus = new object() + }; + + var pullReader = new ReaderConfiguration + { + Exporter = exporter + }; + + var conf = new Conf + { + MeterProvider = new MeterProviderConfiguration + { + Readers = new Dictionary + { + { "pull", pullReader } + } + } + }; + + var settings = new MetricSettings(); + settings.LoadFile(conf); + + Assert.True(settings.MetricsEnabled); + Assert.Single(settings.MetricExporters); + Assert.Contains(MetricsExporter.Prometheus, settings.MetricExporters); + } + + [Fact] + public void LoadFile_SetsMultipleExportersCorrectly() + { + var exporter = new ExporterConfig + { + OtlpGrpc = new OtlpGrpcExporterConfig { Endpoint = "http://localhost:4317/" }, + Console = new object() + }; + + var periodicReader = new ReaderConfiguration + { + Exporter = exporter + }; + + var pullReader = new ReaderConfiguration + { + Exporter = new ExporterConfig + { + Prometheus = new object() + } + }; + + var conf = new Conf + { + MeterProvider = new MeterProviderConfiguration + { + Readers = new Dictionary + { + { "periodic", periodicReader }, + { "pull", pullReader } + } + } + }; + + var settings = new MetricSettings(); + settings.LoadFile(conf); + + Assert.True(settings.MetricsEnabled); + Assert.Equal(3, settings.MetricExporters.Count); + Assert.Contains(MetricsExporter.Otlp, settings.MetricExporters); + Assert.Contains(MetricsExporter.Console, settings.MetricExporters); + Assert.Contains(MetricsExporter.Prometheus, settings.MetricExporters); + } + + [Fact] + public void LoadFile_HandlesNullExporterGracefully() + { + var readerConfig = new ReaderConfiguration + { + Exporter = null + }; + + var conf = new Conf + { + MeterProvider = new MeterProviderConfiguration + { + Readers = new Dictionary + { + { "periodic", readerConfig } + } + } + }; + + var settings = new MetricSettings(); + settings.LoadFile(conf); + + Assert.True(settings.MetricsEnabled); + Assert.Empty(settings.MetricExporters); + Assert.Null(settings.OtlpSettings); + } + + [Fact] + public void LoadFile_SetsEnabledInstrumentations_IfPresent() + { + var instrumentation = new DotNetInstrumentation + { + Metrics = new DotNetMetrics + { + HttpClient = new object(), + NetRuntime = new object() + } + }; + + var conf = new Conf + { + InstrumentationDevelopment = new InstrumentationDevelopment + { + DotNet = instrumentation + } + }; + + var settings = new MetricSettings(); + settings.LoadFile(conf); + + Assert.NotNull(settings.EnabledInstrumentations); + Assert.Contains(MetricInstrumentation.HttpClient, settings.EnabledInstrumentations); + Assert.Contains(MetricInstrumentation.NetRuntime, settings.EnabledInstrumentations); + } +} diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedSdkSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedSdkSettingsTests.cs new file mode 100644 index 0000000000..56b408e1b9 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedSdkSettingsTests.cs @@ -0,0 +1,119 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +using Xunit; +using Xunit.Sdk; + +namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; + +public class FilebasedSdkSettingsTests +{ + [Fact] + public void Loads_AttributeLimits() + { + var config = new Conf + { + AttributeLimits = new AttributeLimits + { + AttributeCountLimit = 100, + AttributeValueLengthLimit = 256, + } + }; + + var settings = new SdkSettings(); + + settings.LoadFile(config); + + Assert.Equal(100, settings.AttributeLimits.AttributeCountLimit); + Assert.Equal(256, settings.AttributeLimits.AttributeValueLengthLimit); + } + + [Fact] + public void Returns_When_Propagator_IsNull() + { + var config = new Conf { Propagator = null }; + var settings = new SdkSettings(); + + settings.LoadFile(config); + + Assert.Empty(settings.Propagators); + } + + [Fact] + public void Adds_Unique_Propagators_From_Composite() + { + var config = new Conf + { + Propagator = new PropagatorConfiguration + { + Composite = new Dictionary + { + { Constants.ConfigurationValues.Propagators.W3CTraceContext, new object() }, + { Constants.ConfigurationValues.Propagators.W3CBaggage, new object() } + } + } + }; + var settings = new SdkSettings(); + + settings.LoadFile(config); + + Assert.Contains(Propagator.W3CTraceContext, settings.Propagators); + Assert.Contains(Propagator.W3CBaggage, settings.Propagators); + } + + [Fact] + public void Adds_Propagators_From_CompositeList() + { + var config = new Conf + { + Propagator = new PropagatorConfiguration + { + CompositeList = "tracecontext,baggage" + } + }; + var settings = new SdkSettings(); + + settings.LoadFile(config); + + Assert.Contains(Propagator.W3CTraceContext, settings.Propagators); + Assert.Contains(Propagator.W3CBaggage, settings.Propagators); + } + + [Fact] + public void Ignores_Duplicates_From_Composite_And_CompositeList() + { + var config = new Conf + { + Propagator = new PropagatorConfiguration + { + Composite = new Dictionary + { + { "tracecontext", new object() } + }, + CompositeList = "tracecontext,baggage" + } + }; + var settings = new SdkSettings(); + + settings.LoadFile(config); + + Assert.Equal(2, settings.Propagators.Count); + } + + [Fact] + public void Logs_And_Skips_Unknown_Propagator() + { + var config = new Conf + { + Propagator = new PropagatorConfiguration + { + CompositeList = "custom" + } + }; + var settings = new SdkSettings(); + + settings.LoadFile(config); + } +} 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..27ac0b06e8 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs @@ -0,0 +1,256 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +using OpenTelemetry.Trace; +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 Conf + { + 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 Conf + { + 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 Conf + { + 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 Conf + { + 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 Conf + { + 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 Conf + { + 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); + } + + [Fact] + public void LoadFile_SetsEnabledInstrumentations_IfPresent() + { + var instrumentation = new DotNetInstrumentation + { + Traces = new DotNetTraces + { + Azure = new object(), + Elasticsearch = new object() + } + }; + + var conf = new Conf + { + InstrumentationDevelopment = new InstrumentationDevelopment + { + DotNet = instrumentation + } + }; + + var settings = new TracerSettings(); + + settings.LoadFile(conf); + + Assert.NotNull(settings.EnabledInstrumentations); + Assert.Contains(TracerInstrumentation.Azure, settings.EnabledInstrumentations); + Assert.Contains(TracerInstrumentation.Elasticsearch, settings.EnabledInstrumentations); + } +} diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml new file mode 100644 index 0000000000..1517815750 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml @@ -0,0 +1,112 @@ +file_format: "0.4" +disabled: false +log_level: info +attribute_limits: + attribute_value_length_limit: + attribute_count_limit: 128 +propagator: + composite: + tracecontext: + baggage: + b3: + b3multi: + jaeger: + ottrace: + composite_list: tracecontext,baggage +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: [] + headers_list: + # limits: + # attribute_value_length_limit: + # attribute_count_limit: 128 + # event_count_limit: 128 + # link_count_limit: 128 + # event_attribute_count_limit: 128 + # link_attribute_count_limit: 128 + +meter_provider: + readers: + periodic: + interval: 60000 + timeout: 30000 + exporter: + otlp_http: + endpoint: http://localhost:4318/v1/metrics + timeout: 10000 + headers: [] + headers_list: + +logger_provider: + processors: + batch: + schedule_delay: 1000 + export_timeout: 30000 + max_queue_size: 2048 + max_export_batch_size: 512 + exporter: + otlp_http: + endpoint: http://localhost:4318/v1/logs + timeout: 10000 + headers: [] + headers_list: +resource: + attributes: + - name: service.name + value: unknown_service + attributes_list: + detection/development: + detectors: + azureappservice: + container: + host: + operatingsystem: + process: + processruntime: + + +instrumentation/development: + dotnet: + traces: +# aspnet: + aspnetcore: + azure: + elasticsearch: + elastictransport: + entityframeworkcore: + graphql: + grpcnetclient: + httpclient: + kafka: + masstransit: + mongodb: + mysqlconnector: + mysqldata: + npgsql: + nservicebus: + oraclemda: + rabbitmq: + quartz: + sqlclient: + stackexchangeredis: + wcfclient: +# wcfservice: + metrics: + aspnetcore: + httpclient: + netruntime: + nservicebus: + process: + sqlclient: + logs: + ilogger: + log4net: diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml new file mode 100644 index 0000000000..9586907904 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml @@ -0,0 +1,102 @@ +file_format: "0.4" +disabled: ${OTEL_SDK_DISABLED} +log_level: ${OTEL_LOG_LEVEL} +resource: + attributes: + - name: service.name + value: ${OTEL_SERVICE_NAME} + attributes_list: ${OTEL_RESOURCE_ATTRIBUTES} + detection/development: + detectors: + azureappservice: + container: + host: + operatingsystem: + process: + processruntime: + +attribute_limits: + attribute_value_length_limit: ${OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT} + attribute_count_limit: ${OTEL_ATTRIBUTE_COUNT_LIMIT} +propagator: + composite_list: ${OTEL_PROPAGATORS} +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} + # limits: + # attribute_value_length_limit: ${OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT} + # attribute_count_limit: ${OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT:-128} + # event_count_limit: ${OTEL_SPAN_EVENT_COUNT_LIMIT:-128} + # link_count_limit: ${OTEL_SPAN_LINK_COUNT_LIMIT:-128} + # event_attribute_count_limit: ${OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT:-128} + # link_attribute_count_limit: ${OTEL_LINK_ATTRIBUTE_COUNT_LIMIT:-128} + +meter_provider: + readers: + periodic: + interval: ${OTEL_METRIC_EXPORT_INTERVAL} + timeout: ${OTEL_METRIC_EXPORT_TIMEOUT} + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_METRICS_ENDPOINT} + timeout: ${OTEL_EXPORTER_OTLP_METRICS_TIMEOUT} + headers_list: ${OTEL_EXPORTER_OTLP_METRICS_HEADERS} + +logger_provider: + processors: + batch: + schedule_delay: ${OTEL_BLRP_SCHEDULE_DELAY} + export_timeout: ${OTEL_BLRP_EXPORT_TIMEOUT} + max_queue_size: ${OTEL_BLRP_MAX_QUEUE_SIZE} + max_export_batch_size: ${OTEL_BLRP_MAX_EXPORT_BATCH_SIZE} + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_LOGS_ENDPOINT} + timeout: ${OTEL_EXPORTER_OTLP_LOGS_TIMEOUT} + headers_list: ${OTEL_EXPORTER_OTLP_LOGS_HEADERS} + +instrumentation/development: + dotnet: + traces: +# aspnet: + aspnetcore: + azure: + elasticsearch: + elastictransport: + entityframeworkcore: + graphql: + grpcnetclient: + httpclient: + kafka: + masstransit: + mongodb: + mysqlconnector: + mysqldata: + npgsql: + nservicebus: + oraclemda: + rabbitmq: + quartz: + sqlclient: + stackexchangeredis: + wcfclient: +# wcfservice: + metrics: + aspnetcore: + httpclient: + netruntime: + nservicebus: + process: + sqlclient: + logs: + ilogger: + log4net: diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs new file mode 100644 index 0000000000..4e54396048 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs @@ -0,0 +1,275 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.Reflection; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; +using Xunit; +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; + +public class ParserTests +{ + [Fact] + public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() + { + var config = Parser.ParseYaml("Configurations/FileBased/Files/TestFile.yaml"); + + Assert.NotNull(config); + + Assert.Equal("0.4", config.FileFormat); + Assert.False(config.Disabled); + Assert.Equal("info", config.LogLevel); + + Assert.NotNull(config.AttributeLimits); + Assert.Null(config.AttributeLimits.AttributeValueLengthLimit); + Assert.Equal(128, config.AttributeLimits.AttributeCountLimit); + + Assert.NotNull(config.Propagator); + Assert.Equal("tracecontext,baggage", config.Propagator.CompositeList); + + var composite = config.Propagator.Composite; + Assert.NotNull(composite); + + string[] expectedCompositeKeys = [ + "tracecontext", "baggage", "b3", "b3multi", "jaeger", "ottrace" + ]; + + foreach (var key in expectedCompositeKeys) + { + Assert.True(composite.TryGetValue(key, out var value)); + Assert.NotNull(value); + } + + 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.NotNull(traceExporter.Headers); + Assert.Empty(traceExporter.Headers); + + Assert.NotNull(config.MeterProvider); + Assert.NotNull(config.MeterProvider.Readers); + Assert.True(config.MeterProvider.Readers.ContainsKey("periodic")); + var metricReader = config.MeterProvider.Readers["periodic"]; + Assert.Equal(60000, metricReader.Interval); + Assert.Equal(30000, metricReader.Timeout); + Assert.NotNull(metricReader.Exporter); + var metricExporter = metricReader.Exporter.OtlpHttp; + Assert.NotNull(metricExporter); + Assert.NotNull(metricExporter.Headers); + Assert.Empty(metricExporter.Headers); + Assert.Equal("http://localhost:4318/v1/metrics", metricExporter.Endpoint); + Assert.Equal(10000, metricExporter.Timeout); + Assert.Empty(metricExporter.Headers); + + Assert.NotNull(config.LoggerProvider); + Assert.NotNull(config.LoggerProvider.Processors); + Assert.True(config.LoggerProvider.Processors.ContainsKey("batch")); + var logBatch = config.LoggerProvider.Processors["batch"]; + Assert.Equal(1000, logBatch.ScheduleDelay); + Assert.Equal(30000, logBatch.ExportTimeout); + Assert.Equal(2048, logBatch.MaxQueueSize); + Assert.Equal(512, logBatch.MaxExportBatchSize); + var logExporter = logBatch.Exporter?.OtlpHttp; + Assert.NotNull(logExporter); + Assert.Equal("http://localhost:4318/v1/logs", logExporter.Endpoint); + Assert.Equal(10000, logExporter.Timeout); + Assert.NotNull(logExporter.Headers); + Assert.Empty(logExporter.Headers); + + Assert.NotNull(config.Resource); + Assert.NotNull(config.Resource.Attributes); + Assert.Single(config.Resource.Attributes); + + var serviceAttr = config.Resource.Attributes.First(); + Assert.Equal("service.name", serviceAttr.Name); + Assert.Equal("unknown_service", serviceAttr.Value); + Assert.NotNull(config.Resource.AttributesList); + Assert.Empty(config.Resource.AttributesList); + + Assert.NotNull(config.Resource.DetectionDevelopment); + Assert.NotNull(config.Resource.DetectionDevelopment.Detectors); + + Assert.NotNull(config.InstrumentationDevelopment); + Assert.NotNull(config.InstrumentationDevelopment.DotNet); + + /* string[] expectedTraces = [ + "aspnetcore", "azure", "elasticsearch", "elastictransport", + "entityframeworkcore", "graphql", "grpcnetclient", "httpclient", + "kafka", "masstransit", "mongodb", "mysqlconnector", + "mysqldata", "npgsql", "nservicebus", "oraclemda", + "rabbitmq", "quartz", "sqlclient", "stackexchangeredis", + "wcfclient" + ]; + + var traces = config.InstrumentationDevelopment.DotNet.Traces; + Assert.NotNull(traces); + foreach (var alias in expectedTraces) + { + AssertAliasPropertyNotNull(traces, alias); + }*/ + + string[] expectedMetrics = + [ + "aspnetcore", "httpclient", "netruntime", + "nservicebus", "process", "sqlclient" + ]; + + foreach (var alias in expectedMetrics) + { + AssertAliasPropertyExists(alias); + } + + string[] expectedLogs = ["ilogger", "log4net"]; + + foreach (var alias in expectedLogs) + { + AssertAliasPropertyExists(alias); + } + } + + [Fact] + public void Parse_EnvVarYaml_ShouldPopulateModelCompletely() + { + Environment.SetEnvironmentVariable("OTEL_SDK_DISABLED", "true"); + Environment.SetEnvironmentVariable("OTEL_LOG_LEVEL", "debug"); + Environment.SetEnvironmentVariable("OTEL_SERVICE_NAME", "my‑service"); + Environment.SetEnvironmentVariable("OTEL_RESOURCE_ATTRIBUTES", "key=value"); + + Environment.SetEnvironmentVariable("OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", "256"); + Environment.SetEnvironmentVariable("OTEL_ATTRIBUTE_COUNT_LIMIT", "256"); + Environment.SetEnvironmentVariable("OTEL_PROPAGATORS", "tracecontext,baggage"); + + 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"); + + Environment.SetEnvironmentVariable("OTEL_METRIC_EXPORT_INTERVAL", "65000"); + Environment.SetEnvironmentVariable("OTEL_METRIC_EXPORT_TIMEOUT", "35000"); + Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT", "http://collector:4318/v1/metrics"); + Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_METRICS_TIMEOUT", "15000"); + Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_METRICS_HEADERS", "mheader=value"); + + Environment.SetEnvironmentVariable("OTEL_BLRP_SCHEDULE_DELAY", "1500"); + Environment.SetEnvironmentVariable("OTEL_BLRP_EXPORT_TIMEOUT", "40000"); + Environment.SetEnvironmentVariable("OTEL_BLRP_MAX_QUEUE_SIZE", "4096"); + Environment.SetEnvironmentVariable("OTEL_BLRP_MAX_EXPORT_BATCH_SIZE", "1024"); + Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_LOGS_ENDPOINT", "http://collector:4318/v1/logs"); + Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_LOGS_TIMEOUT", "15000"); + Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_LOGS_HEADERS", "lheader=value"); + + var config = Parser.ParseYaml("Configurations/FileBased/Files/TestFileEnvVars.yaml"); + + Assert.Equal("0.4", config.FileFormat); + Assert.True(config.Disabled); + Assert.Equal("debug", config.LogLevel); + + Assert.NotNull(config.AttributeLimits); + Assert.Equal(256, config.AttributeLimits.AttributeValueLengthLimit); + Assert.Equal(256, config.AttributeLimits.AttributeCountLimit); + + Assert.NotNull(config.Propagator); + Assert.Equal("tracecontext,baggage", config.Propagator.CompositeList); + + 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.NotNull(config.MeterProvider); + Assert.NotNull(config.MeterProvider.Readers); + Assert.True(config.MeterProvider.Readers.ContainsKey("periodic")); + var metricReader = config.MeterProvider.Readers["periodic"]; + Assert.Equal(65000, metricReader.Interval); + Assert.Equal(35000, metricReader.Timeout); + Assert.NotNull(metricReader.Exporter); + var metricExporter = metricReader.Exporter.OtlpHttp; + Assert.NotNull(metricExporter); + Assert.Equal("http://collector:4318/v1/metrics", metricExporter.Endpoint); + + Assert.NotNull(config.LoggerProvider); + Assert.NotNull(config.LoggerProvider.Processors); + Assert.True(config.LoggerProvider.Processors.ContainsKey("batch")); + var logBatch = config.LoggerProvider.Processors["batch"]; + Assert.Equal(1500, logBatch.ScheduleDelay); + Assert.Equal(40000, logBatch.ExportTimeout); + Assert.Equal(4096, logBatch.MaxQueueSize); + Assert.Equal(1024, logBatch.MaxExportBatchSize); + Assert.NotNull(logBatch); + Assert.NotNull(logBatch.Exporter); + Assert.NotNull(logBatch.Exporter.OtlpHttp); + var logExporter = logBatch.Exporter.OtlpHttp; + Assert.Equal("http://collector:4318/v1/logs", logExporter.Endpoint); + var serviceAttr = config.Resource?.Attributes?.First(a => a.Name == "service.name"); + Assert.NotNull(serviceAttr); + Assert.Equal("my‑service", serviceAttr.Value); + + // Instrumentation alias existence (same helper) +/* string[] expectedTraces = [ + "aspnetcore", "azure", "elasticsearch", "elastictransport", + "entityframeworkcore", "graphql", "grpcnetclient", "httpclient", + "kafka", "masstransit", "mongodb", "mysqlconnector", + "mysqldata", "npgsql", "nservicebus", "oraclemda", + "rabbitmq", "quartz", "sqlclient", "stackexchangeredis", + "wcfclient" + ]; + + foreach (var alias in expectedTraces) + { + AssertAliasPropertyExists(alias); + }*/ + + string[] expectedMetrics = + [ + "aspnetcore", "httpclient", "netruntime", + "nservicebus", "process", "sqlclient" + ]; + + foreach (var alias in expectedMetrics) + { + AssertAliasPropertyExists(alias); + } + + string[] expectedLogs = ["ilogger", "log4net"]; + + foreach (var alias in expectedLogs) + { + AssertAliasPropertyExists(alias); + } + } + + private static void AssertAliasPropertyExists(string alias) + { + var prop = typeof(T).GetProperties() + .FirstOrDefault(p => p.GetCustomAttribute()?.Alias == alias); + Assert.NotNull(prop); + } +} diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/PluginManagerTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/PluginManagerTests.cs index bac9d714d7..2c1317b8c7 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/PluginManagerTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/PluginManagerTests.cs @@ -158,7 +158,7 @@ private static GeneralSettings GetSettings(string assemblyQualifiedName) })); var settings = new GeneralSettings(); - settings.Load(config); + settings.LoadEnvVar(config); return settings; } diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ServiceNameConfiguratorTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ServiceNameConfiguratorTests.cs index 58497f2728..48e1379602 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ServiceNameConfiguratorTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ServiceNameConfiguratorTests.cs @@ -14,7 +14,7 @@ public class ServiceNameConfiguratorTests [Fact] public void GetFallbackServiceName() { - var resourceBuilder = ResourceConfigurator.CreateResourceBuilder(new List()); + var resourceBuilder = ResourceConfigurator.CreateResourceBuilder(new List(), []); var resource = resourceBuilder.Build(); var serviceName = resource.Attributes.FirstOrDefault(a => a.Key == ServiceName).Value as string; @@ -29,7 +29,7 @@ public void ServiceName_Retained_EnvVarSet() { Environment.SetEnvironmentVariable(OtelServiceVariable, setServiceName); - var resourceBuilder = ResourceConfigurator.CreateResourceBuilder(Array.Empty()); + var resourceBuilder = ResourceConfigurator.CreateResourceBuilder(Array.Empty(), []); var resource = resourceBuilder.Build(); var serviceName = resource.Attributes.FirstOrDefault(a => a.Key == ServiceName).Value as string; diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs index 9cabff7379..5a6d530e09 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs @@ -56,8 +56,8 @@ internal void TracerSettings_DefaultValues() Assert.Empty(settings.InstrumentationOptions.AspNetCoreInstrumentationCaptureRequestHeaders); Assert.Empty(settings.InstrumentationOptions.AspNetCoreInstrumentationCaptureResponseHeaders); Assert.False(settings.InstrumentationOptions.EntityFrameworkCoreSetDbStatementForText); -#endif Assert.False(settings.InstrumentationOptions.GraphQLSetDocument); +#endif Assert.Empty(settings.InstrumentationOptions.GrpcNetClientInstrumentationCaptureRequestMetadata); Assert.Empty(settings.InstrumentationOptions.GrpcNetClientInstrumentationCaptureResponseMetadata); Assert.Empty(settings.InstrumentationOptions.HttpInstrumentationCaptureRequestHeaders); diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj b/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj index 3323675c6f..0aa0bc3fb7 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/OpenTelemetry.AutoInstrumentation.Tests.csproj @@ -11,4 +11,13 @@ + + + PreserveNewest + + + PreserveNewest + + + From 7a6b0e3f39e3d22cf70dff04ae6e32bf2618293e Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 23 Jul 2025 16:31:57 +0200 Subject: [PATCH 08/28] fix test --- .../FileBased/Files/TestFile.yaml | 9 +- .../Configurations/FileBased/ParserTests.cs | 92 ++++++++++++------- 2 files changed, 62 insertions(+), 39 deletions(-) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml index 1517815750..969eaba5da 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml @@ -2,7 +2,7 @@ file_format: "0.4" disabled: false log_level: info attribute_limits: - attribute_value_length_limit: + attribute_value_length_limit: 4096 attribute_count_limit: 128 propagator: composite: @@ -26,13 +26,6 @@ tracer_provider: timeout: 10000 headers: [] headers_list: - # limits: - # attribute_value_length_limit: - # attribute_count_limit: 128 - # event_count_limit: 128 - # link_count_limit: 128 - # event_attribute_count_limit: 128 - # link_attribute_count_limit: 128 meter_provider: readers: diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs index 4e54396048..3d3e419168 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs @@ -23,7 +23,7 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() Assert.Equal("info", config.LogLevel); Assert.NotNull(config.AttributeLimits); - Assert.Null(config.AttributeLimits.AttributeValueLengthLimit); + Assert.Equal(4096, config.AttributeLimits.AttributeValueLengthLimit); Assert.Equal(128, config.AttributeLimits.AttributeCountLimit); Assert.NotNull(config.Propagator); @@ -39,7 +39,6 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() foreach (var key in expectedCompositeKeys) { Assert.True(composite.TryGetValue(key, out var value)); - Assert.NotNull(value); } Assert.NotNull(config.TracerProvider); @@ -60,6 +59,9 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() Assert.NotNull(traceExporter.Headers); Assert.Empty(traceExporter.Headers); + Assert.NotNull(traceExporter.HeadersList); + Assert.Empty(traceExporter.HeadersList); + Assert.NotNull(config.MeterProvider); Assert.NotNull(config.MeterProvider.Readers); Assert.True(config.MeterProvider.Readers.ContainsKey("periodic")); @@ -97,6 +99,7 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() var serviceAttr = config.Resource.Attributes.First(); Assert.Equal("service.name", serviceAttr.Name); Assert.Equal("unknown_service", serviceAttr.Value); + Assert.NotNull(config.Resource.AttributesList); Assert.Empty(config.Resource.AttributesList); @@ -106,21 +109,25 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() Assert.NotNull(config.InstrumentationDevelopment); Assert.NotNull(config.InstrumentationDevelopment.DotNet); - /* string[] expectedTraces = [ + Assert.NotNull(config.InstrumentationDevelopment); + Assert.NotNull(config.InstrumentationDevelopment.DotNet); + + string[] expectedTraces = [ "aspnetcore", "azure", "elasticsearch", "elastictransport", - "entityframeworkcore", "graphql", "grpcnetclient", "httpclient", - "kafka", "masstransit", "mongodb", "mysqlconnector", - "mysqldata", "npgsql", "nservicebus", "oraclemda", - "rabbitmq", "quartz", "sqlclient", "stackexchangeredis", - "wcfclient" + "entityframeworkcore", "graphql", "grpcnetclient", "httpclient", + "kafka", "masstransit", "mongodb", "mysqlconnector", + "mysqldata", "npgsql", "nservicebus", "oraclemda", + "rabbitmq", "quartz", "sqlclient", "stackexchangeredis", + "wcfclient" ]; - var traces = config.InstrumentationDevelopment.DotNet.Traces; - Assert.NotNull(traces); - foreach (var alias in expectedTraces) - { - AssertAliasPropertyNotNull(traces, alias); - }*/ + var traces = config.InstrumentationDevelopment.DotNet.Traces; + Assert.NotNull(traces); + + foreach (var alias in expectedTraces) + { + AssertAliasPropertyExists(traces, alias); + } string[] expectedMetrics = [ @@ -128,16 +135,22 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() "nservicebus", "process", "sqlclient" ]; + var metrics = config.InstrumentationDevelopment.DotNet.Metrics; + Assert.NotNull(metrics); + foreach (var alias in expectedMetrics) { - AssertAliasPropertyExists(alias); + AssertAliasPropertyExists(metrics, alias); } string[] expectedLogs = ["ilogger", "log4net"]; + var logs = config.InstrumentationDevelopment.DotNet.Logs; + Assert.NotNull(logs); + foreach (var alias in expectedLogs) { - AssertAliasPropertyExists(alias); + AssertAliasPropertyExists(logs, alias); } } @@ -232,20 +245,25 @@ public void Parse_EnvVarYaml_ShouldPopulateModelCompletely() Assert.NotNull(serviceAttr); Assert.Equal("my‑service", serviceAttr.Value); - // Instrumentation alias existence (same helper) -/* string[] expectedTraces = [ - "aspnetcore", "azure", "elasticsearch", "elastictransport", - "entityframeworkcore", "graphql", "grpcnetclient", "httpclient", - "kafka", "masstransit", "mongodb", "mysqlconnector", - "mysqldata", "npgsql", "nservicebus", "oraclemda", - "rabbitmq", "quartz", "sqlclient", "stackexchangeredis", - "wcfclient" - ]; + Assert.NotNull(config.InstrumentationDevelopment); + Assert.NotNull(config.InstrumentationDevelopment.DotNet); + + string[] expectedTraces = [ + "aspnetcore", "azure", "elasticsearch", "elastictransport", + "entityframeworkcore", "graphql", "grpcnetclient", "httpclient", + "kafka", "masstransit", "mongodb", "mysqlconnector", + "mysqldata", "npgsql", "nservicebus", "oraclemda", + "rabbitmq", "quartz", "sqlclient", "stackexchangeredis", + "wcfclient" + ]; + + var traces = config.InstrumentationDevelopment.DotNet.Traces; + Assert.NotNull(traces); foreach (var alias in expectedTraces) { - AssertAliasPropertyExists(alias); - }*/ + AssertAliasPropertyExists(traces, alias); + } string[] expectedMetrics = [ @@ -253,23 +271,35 @@ public void Parse_EnvVarYaml_ShouldPopulateModelCompletely() "nservicebus", "process", "sqlclient" ]; + var metrics = config.InstrumentationDevelopment.DotNet.Metrics; + Assert.NotNull(metrics); + foreach (var alias in expectedMetrics) { - AssertAliasPropertyExists(alias); + AssertAliasPropertyExists(metrics, alias); } string[] expectedLogs = ["ilogger", "log4net"]; + var logs = config.InstrumentationDevelopment.DotNet.Logs; + Assert.NotNull(logs); + foreach (var alias in expectedLogs) { - AssertAliasPropertyExists(alias); + AssertAliasPropertyExists(logs, alias); } } - private static void AssertAliasPropertyExists(string alias) + private static void AssertAliasPropertyExists(T obj, string alias) { + Assert.NotNull(obj); + var prop = typeof(T).GetProperties() - .FirstOrDefault(p => p.GetCustomAttribute()?.Alias == alias); + .FirstOrDefault(p => p.GetCustomAttribute()?.Alias == alias); + Assert.NotNull(prop); + + var value = prop.GetValue(obj); + Assert.NotNull(value); } } From 03ca73c15b37caf0381986bbf9f339a443060085 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 30 Jul 2025 16:25:18 +0200 Subject: [PATCH 09/28] remove unused usings + minor fix --- .../Configurations/FileBased/FilebasedLogsSettingsTests.cs | 1 - .../Configurations/FileBased/FilebasedMetricsSettingsTests.cs | 1 - .../Configurations/FileBased/FilebasedSdkSettingsTests.cs | 4 ++-- .../Configurations/FileBased/FilebasedTracesSettingsTests.cs | 1 - 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedLogsSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedLogsSettingsTests.cs index 1045d49b6f..7ae6579e21 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedLogsSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedLogsSettingsTests.cs @@ -3,7 +3,6 @@ using OpenTelemetry.AutoInstrumentation.Configurations; using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; -using OpenTelemetry.Trace; using Xunit; namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedMetricsSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedMetricsSettingsTests.cs index 536c9d1872..9a425585ed 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedMetricsSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedMetricsSettingsTests.cs @@ -3,7 +3,6 @@ using OpenTelemetry.AutoInstrumentation.Configurations; using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; -using OpenTelemetry.Trace; using Xunit; namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedSdkSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedSdkSettingsTests.cs index 56b408e1b9..3845ad203b 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedSdkSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedSdkSettingsTests.cs @@ -4,7 +4,6 @@ using OpenTelemetry.AutoInstrumentation.Configurations; using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using Xunit; -using Xunit.Sdk; namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; @@ -103,7 +102,7 @@ public void Ignores_Duplicates_From_Composite_And_CompositeList() } [Fact] - public void Logs_And_Skips_Unknown_Propagator() + public void Skips_Unknown_Propagator() { var config = new Conf { @@ -115,5 +114,6 @@ public void Logs_And_Skips_Unknown_Propagator() var settings = new SdkSettings(); settings.LoadFile(config); + Assert.Empty(settings.Propagators); } } diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs index 27ac0b06e8..be4512f4ae 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedTracesSettingsTests.cs @@ -3,7 +3,6 @@ using OpenTelemetry.AutoInstrumentation.Configurations; using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; -using OpenTelemetry.Trace; using Xunit; namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; From d5294cad4b74f0519bab8651ba573b3134dbdad5 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 30 Jul 2025 16:27:54 +0200 Subject: [PATCH 10/28] fix bug with null entry --- .../CaptureHeadersConfiguration.cs | 2 + .../CaptureMetadataConfiguration.cs | 2 + .../Parser/ConditionalDeserializer.cs | 55 +++++++++++++++++++ .../Parser/EmptyObjectOnEmptyYamlAttribute.cs | 9 +++ .../FileBasedConfiguration/Parser/Parser.cs | 4 +- .../SetDbStatementForTextConfuguration.cs | 2 + .../SetDocumentConfiguration.cs | 2 + 7 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/ConditionalDeserializer.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EmptyObjectOnEmptyYamlAttribute.cs diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs index 52a5c485aa..f37fa0c878 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs @@ -1,10 +1,12 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; using YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +[EmptyObjectOnEmptyYaml] internal class CaptureHeadersConfiguration { /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs index 77df52fc57..970a539423 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs @@ -1,10 +1,12 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; using YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +[EmptyObjectOnEmptyYaml] internal class CaptureMetadataConfiguration { /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/ConditionalDeserializer.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/ConditionalDeserializer.cs new file mode 100644 index 0000000000..adc89854aa --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/ConditionalDeserializer.cs @@ -0,0 +1,55 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using System.Reflection; +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; + +internal class ConditionalDeserializer : INodeDeserializer +{ + private readonly INodeDeserializer _inner; + + public ConditionalDeserializer(INodeDeserializer inner) + { + this._inner = inner; + } + + public bool Deserialize( + IParser reader, + Type expectedType, + Func nestedObjectDeserializer, + out object? value, + ObjectDeserializer rootDeserializer) + { + if (!expectedType.IsDefined(typeof(EmptyObjectOnEmptyYamlAttribute), inherit: true)) + { + return _inner.Deserialize(reader, expectedType, nestedObjectDeserializer, out value, rootDeserializer); + } + + if (reader.Accept(out var scalar)) + { + if (string.IsNullOrEmpty(scalar.Value)) + { + value = Activator.CreateInstance(expectedType); + reader.MoveNext(); + return true; + } + } + + if (reader.Accept(out _)) + { + object tempValue = Activator.CreateInstance(expectedType)!; + + bool result = _inner.Deserialize(reader, expectedType, nestedObjectDeserializer, out var deserialized, rootDeserializer); + + value = deserialized ?? tempValue; + return result; + } + + value = null; + return false; + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EmptyObjectOnEmptyYamlAttribute.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EmptyObjectOnEmptyYamlAttribute.cs new file mode 100644 index 0000000000..9863a486b3 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EmptyObjectOnEmptyYamlAttribute.cs @@ -0,0 +1,9 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; + +[AttributeUsage(AttributeTargets.Class)] +internal sealed class EmptyObjectOnEmptyYamlAttribute : Attribute +{ +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs index 86edf6613c..5a1dc7ef80 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NodeDeserializers; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; @@ -10,8 +11,9 @@ internal static class Parser public static Conf ParseYaml(string filePath) { var deserializer = new DeserializerBuilder() - // .WithNamingConvention(UnderscoredNamingConvention.Instance) + .WithNodeDeserializer(existing => new ConditionalDeserializer(existing), s => s.InsteadOf()) .WithTypeConverter(new EnvVarTypeConverter()) + .IgnoreUnmatchedProperties() .Build(); var yaml = File.ReadAllText(filePath); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs index fa6d28d1ff..235632a195 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs @@ -1,10 +1,12 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; using YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +[EmptyObjectOnEmptyYaml] internal class SetDbStatementForTextConfuguration { /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs index 8119cd082c..225cfc6fd1 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs @@ -1,10 +1,12 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; using YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; +[EmptyObjectOnEmptyYaml] internal class SetDocumentConfiguration { /// From afc51419e44494e1ec7238d8b626967611e2fb52 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 30 Jul 2025 16:28:31 +0200 Subject: [PATCH 11/28] fix lint in yaml files --- .../FileBased/Files/TestFile.yaml | 71 ++++++------ .../FileBased/Files/TestFileEnvVars.yaml | 103 ++++++------------ 2 files changed, 67 insertions(+), 107 deletions(-) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml index 969eaba5da..7f735ab75f 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml @@ -10,48 +10,48 @@ propagator: baggage: b3: b3multi: - jaeger: - ottrace: composite_list: tracecontext,baggage + 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: [] - headers_list: + 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: [] + headers_list: meter_provider: readers: - periodic: - interval: 60000 - timeout: 30000 - exporter: - otlp_http: - endpoint: http://localhost:4318/v1/metrics - timeout: 10000 - headers: [] - headers_list: + periodic: + interval: 60000 + timeout: 30000 + exporter: + otlp_http: + endpoint: http://localhost:4318/v1/metrics + timeout: 10000 + headers: [] + headers_list: logger_provider: processors: - batch: - schedule_delay: 1000 - export_timeout: 30000 - max_queue_size: 2048 - max_export_batch_size: 512 - exporter: - otlp_http: - endpoint: http://localhost:4318/v1/logs - timeout: 10000 - headers: [] - headers_list: + batch: + schedule_delay: 1000 + export_timeout: 30000 + max_queue_size: 2048 + max_export_batch_size: 512 + exporter: + otlp_http: + endpoint: http://localhost:4318/v1/logs + timeout: 10000 + headers: [] + headers_list: + resource: attributes: - name: service.name @@ -70,7 +70,7 @@ resource: instrumentation/development: dotnet: traces: -# aspnet: + aspnet: aspnetcore: azure: elasticsearch: @@ -92,8 +92,9 @@ instrumentation/development: sqlclient: stackexchangeredis: wcfclient: -# wcfservice: + wcfservice: metrics: + aspnet: aspnetcore: httpclient: netruntime: diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml index 9586907904..a64ce312fd 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml @@ -1,6 +1,7 @@ file_format: "0.4" disabled: ${OTEL_SDK_DISABLED} log_level: ${OTEL_LOG_LEVEL} + resource: attributes: - name: service.name @@ -20,83 +21,41 @@ attribute_limits: attribute_count_limit: ${OTEL_ATTRIBUTE_COUNT_LIMIT} propagator: composite_list: ${OTEL_PROPAGATORS} + 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} - # limits: - # attribute_value_length_limit: ${OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT} - # attribute_count_limit: ${OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT:-128} - # event_count_limit: ${OTEL_SPAN_EVENT_COUNT_LIMIT:-128} - # link_count_limit: ${OTEL_SPAN_LINK_COUNT_LIMIT:-128} - # event_attribute_count_limit: ${OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT:-128} - # link_attribute_count_limit: ${OTEL_LINK_ATTRIBUTE_COUNT_LIMIT:-128} + 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} + meter_provider: readers: - periodic: - interval: ${OTEL_METRIC_EXPORT_INTERVAL} - timeout: ${OTEL_METRIC_EXPORT_TIMEOUT} - exporter: - otlp_http: - endpoint: ${OTEL_EXPORTER_OTLP_METRICS_ENDPOINT} - timeout: ${OTEL_EXPORTER_OTLP_METRICS_TIMEOUT} - headers_list: ${OTEL_EXPORTER_OTLP_METRICS_HEADERS} + periodic: + interval: ${OTEL_METRIC_EXPORT_INTERVAL} + timeout: ${OTEL_METRIC_EXPORT_TIMEOUT} + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_METRICS_ENDPOINT} + timeout: ${OTEL_EXPORTER_OTLP_METRICS_TIMEOUT} + headers_list: ${OTEL_EXPORTER_OTLP_METRICS_HEADERS} logger_provider: processors: - batch: - schedule_delay: ${OTEL_BLRP_SCHEDULE_DELAY} - export_timeout: ${OTEL_BLRP_EXPORT_TIMEOUT} - max_queue_size: ${OTEL_BLRP_MAX_QUEUE_SIZE} - max_export_batch_size: ${OTEL_BLRP_MAX_EXPORT_BATCH_SIZE} - exporter: - otlp_http: - endpoint: ${OTEL_EXPORTER_OTLP_LOGS_ENDPOINT} - timeout: ${OTEL_EXPORTER_OTLP_LOGS_TIMEOUT} - headers_list: ${OTEL_EXPORTER_OTLP_LOGS_HEADERS} - -instrumentation/development: - dotnet: - traces: -# aspnet: - aspnetcore: - azure: - elasticsearch: - elastictransport: - entityframeworkcore: - graphql: - grpcnetclient: - httpclient: - kafka: - masstransit: - mongodb: - mysqlconnector: - mysqldata: - npgsql: - nservicebus: - oraclemda: - rabbitmq: - quartz: - sqlclient: - stackexchangeredis: - wcfclient: -# wcfservice: - metrics: - aspnetcore: - httpclient: - netruntime: - nservicebus: - process: - sqlclient: - logs: - ilogger: - log4net: + batch: + schedule_delay: ${OTEL_BLRP_SCHEDULE_DELAY} + export_timeout: ${OTEL_BLRP_EXPORT_TIMEOUT} + max_queue_size: ${OTEL_BLRP_MAX_QUEUE_SIZE} + max_export_batch_size: ${OTEL_BLRP_MAX_EXPORT_BATCH_SIZE} + exporter: + otlp_http: + endpoint: ${OTEL_EXPORTER_OTLP_LOGS_ENDPOINT} + timeout: ${OTEL_EXPORTER_OTLP_LOGS_TIMEOUT} + headers_list: ${OTEL_EXPORTER_OTLP_LOGS_HEADERS} \ No newline at end of file From 37e1e5c8281dccf23f263641dcfc3e6f36d92072 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 30 Jul 2025 16:29:45 +0200 Subject: [PATCH 12/28] fix parser test for framework + cleanup --- .../Configurations/FileBased/ParserTests.cs | 96 ++++++++----------- 1 file changed, 42 insertions(+), 54 deletions(-) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs index 3d3e419168..ab4c80adca 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 using System.Reflection; -using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; using Xunit; using YamlDotNet.Serialization; @@ -33,7 +32,7 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() Assert.NotNull(composite); string[] expectedCompositeKeys = [ - "tracecontext", "baggage", "b3", "b3multi", "jaeger", "ottrace" + "tracecontext", "baggage", "b3", "b3multi", ]; foreach (var key in expectedCompositeKeys) @@ -104,22 +103,46 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() Assert.Empty(config.Resource.AttributesList); Assert.NotNull(config.Resource.DetectionDevelopment); - Assert.NotNull(config.Resource.DetectionDevelopment.Detectors); - Assert.NotNull(config.InstrumentationDevelopment); - Assert.NotNull(config.InstrumentationDevelopment.DotNet); +#if NET + string[] expectedDetecors = [ + "azureappservice", "container", "host", "operatingsystem", "process", "processruntime" + ]; +#endif +#if NETFRAMEWORK + string[] expectedDetecors = [ + "azureappservice", "host", "operatingsystem", "process", "processruntime" + ]; +#endif + + var detectors = config.Resource.DetectionDevelopment.Detectors; + Assert.NotNull(detectors); + + foreach (var alias in expectedDetecors) + { + AssertAliasPropertyExists(detectors, alias); + } Assert.NotNull(config.InstrumentationDevelopment); Assert.NotNull(config.InstrumentationDevelopment.DotNet); +#if NET string[] expectedTraces = [ "aspnetcore", "azure", "elasticsearch", "elastictransport", - "entityframeworkcore", "graphql", "grpcnetclient", "httpclient", - "kafka", "masstransit", "mongodb", "mysqlconnector", - "mysqldata", "npgsql", "nservicebus", "oraclemda", - "rabbitmq", "quartz", "sqlclient", "stackexchangeredis", - "wcfclient" + "entityframeworkcore", "graphql", "grpcnetclient", "httpclient", + "kafka", "masstransit", "mongodb", "mysqlconnector", + "mysqldata", "npgsql", "nservicebus", "oraclemda", "rabbitmq", + "quartz", "sqlclient", "stackexchangeredis", "wcfclient" + ]; +#endif +#if NETFRAMEWORK + string[] expectedTraces = [ + "aspnet", "azure", "elasticsearch", "elastictransport", + "grpcnetclient", "httpclient", "kafka", "mongodb", + "mysqlconnector", "npgsql", "nservicebus", "oraclemda", + "rabbitmq", "quartz", "sqlclient", "wcfclient", "wcfservice" ]; +#endif var traces = config.InstrumentationDevelopment.DotNet.Traces; Assert.NotNull(traces); @@ -129,11 +152,20 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() AssertAliasPropertyExists(traces, alias); } +#if NET string[] expectedMetrics = [ "aspnetcore", "httpclient", "netruntime", + "nservicebus", "process", "sqlclient" + ]; +#endif +#if NETFRAMEWORK + string[] expectedMetrics = + [ + "aspnet", "httpclient", "netruntime", "nservicebus", "process", "sqlclient" ]; +#endif var metrics = config.InstrumentationDevelopment.DotNet.Metrics; Assert.NotNull(metrics); @@ -244,50 +276,6 @@ public void Parse_EnvVarYaml_ShouldPopulateModelCompletely() var serviceAttr = config.Resource?.Attributes?.First(a => a.Name == "service.name"); Assert.NotNull(serviceAttr); Assert.Equal("my‑service", serviceAttr.Value); - - Assert.NotNull(config.InstrumentationDevelopment); - Assert.NotNull(config.InstrumentationDevelopment.DotNet); - - string[] expectedTraces = [ - "aspnetcore", "azure", "elasticsearch", "elastictransport", - "entityframeworkcore", "graphql", "grpcnetclient", "httpclient", - "kafka", "masstransit", "mongodb", "mysqlconnector", - "mysqldata", "npgsql", "nservicebus", "oraclemda", - "rabbitmq", "quartz", "sqlclient", "stackexchangeredis", - "wcfclient" - ]; - - var traces = config.InstrumentationDevelopment.DotNet.Traces; - Assert.NotNull(traces); - - foreach (var alias in expectedTraces) - { - AssertAliasPropertyExists(traces, alias); - } - - string[] expectedMetrics = - [ - "aspnetcore", "httpclient", "netruntime", - "nservicebus", "process", "sqlclient" - ]; - - var metrics = config.InstrumentationDevelopment.DotNet.Metrics; - Assert.NotNull(metrics); - - foreach (var alias in expectedMetrics) - { - AssertAliasPropertyExists(metrics, alias); - } - - string[] expectedLogs = ["ilogger", "log4net"]; - - var logs = config.InstrumentationDevelopment.DotNet.Logs; - Assert.NotNull(logs); - - foreach (var alias in expectedLogs) - { - AssertAliasPropertyExists(logs, alias); - } } private static void AssertAliasPropertyExists(T obj, string alias) From e378484dbfd86cdcf5836a23365cdd95ddd7add5 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 30 Jul 2025 16:31:01 +0200 Subject: [PATCH 13/28] fix bug with disabled --- .../Configurations/GeneralSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs index a1453b173e..43ddbffc11 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs @@ -136,7 +136,7 @@ protected override void OnLoadFile(Conf configuration) Resources = merged.ToList(); - SetupSdk = configuration.Disabled; + SetupSdk = !configuration.Disabled; } private static List> ParseResourceAttributes(string? resourceAttributes) From 8aa99abb35af4adc54b2d82a9cf0b7957e3998a8 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 30 Jul 2025 16:33:02 +0200 Subject: [PATCH 14/28] add integration tests --- test/IntegrationTests/FileBased/LogsTests.cs | 42 ++++++++++++++ .../FileBased/MetricsTests.cs | 36 ++++++++++++ .../IntegrationTests/FileBased/TrasesTests.cs | 58 +++++++++++++++++++ .../Helpers/MockLogsCollector.cs | 11 ++++ .../Helpers/MockMetricsCollector.cs | 10 ++++ .../Helpers/MockSpansCollector.cs | 12 ++++ .../Helpers/TestHttpServer.AspNetCore.cs | 30 ++++++++++ .../Helpers/TestHttpServer.NetFramework.cs | 17 ++++++ .../TestApplication.Http.csproj | 6 ++ .../TestApplication.Http/config.yaml | 11 ++++ .../TestApplication.Logs.csproj | 6 ++ .../TestApplication.Logs/config.yaml | 11 ++++ .../TestApplication.Smoke.csproj | 6 ++ .../TestApplication.Smoke/config.yaml | 13 +++++ 14 files changed, 269 insertions(+) create mode 100644 test/IntegrationTests/FileBased/LogsTests.cs create mode 100644 test/IntegrationTests/FileBased/MetricsTests.cs create mode 100644 test/IntegrationTests/FileBased/TrasesTests.cs create mode 100644 test/test-applications/integrations/TestApplication.Http/config.yaml create mode 100644 test/test-applications/integrations/TestApplication.Logs/config.yaml create mode 100644 test/test-applications/integrations/TestApplication.Smoke/config.yaml diff --git a/test/IntegrationTests/FileBased/LogsTests.cs b/test/IntegrationTests/FileBased/LogsTests.cs new file mode 100644 index 0000000000..4f748e1328 --- /dev/null +++ b/test/IntegrationTests/FileBased/LogsTests.cs @@ -0,0 +1,42 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#if NET +using IntegrationTests.Helpers; +using OpenTelemetry.Proto.Logs.V1; +using Xunit.Abstractions; + +namespace IntegrationTests.FileBased; + +public class LogsTests : TestHelper +{ + public LogsTests(ITestOutputHelper output) + : base("Logs", output) + { + } + + [Fact] + public void SubmitLogs() + { + using var collector = new MockLogsCollector(Output, 4318); + SetExporter(collector); + + // When includeFormattedMessage is set to false + // LogRecord is not parsed and body will not have data. + // This is a default collector behavior. + collector.Expect(logRecord => + { + var logsAsString = Convert.ToString(logRecord); + return logsAsString != null && logsAsString.Contains("TestApplication.Logs.Controllers.TestController"); + }); + + SetEnvironmentVariable("ASPNETCORE_HOSTINGSTARTUPASSEMBLIES", "OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper"); + SetEnvironmentVariable("OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED", "true"); + + RunTestApplication(); + + collector.AssertExpectations(); + } +} +#endif + diff --git a/test/IntegrationTests/FileBased/MetricsTests.cs b/test/IntegrationTests/FileBased/MetricsTests.cs new file mode 100644 index 0000000000..f20528d052 --- /dev/null +++ b/test/IntegrationTests/FileBased/MetricsTests.cs @@ -0,0 +1,36 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using IntegrationTests.Helpers; +using Xunit.Abstractions; + +namespace IntegrationTests.FileBased; + +public class MetricsTests : TestHelper +{ + public MetricsTests(ITestOutputHelper output) + : base("Smoke", output) + { + SetEnvironmentVariable("LONG_RUNNING", "true"); + SetEnvironmentVariable("OTEL_METRIC_EXPORT_INTERVAL", "100"); + } + + [Fact] + [Trait("Category", "EndToEnd")] + public void SubmitMetrics() + { + using var collector = new MockMetricsCollector(Output, 4318); + SetExporter(collector); + collector.Expect("OpenTelemetry.Instrumentation.Process"); + SetEnvironmentVariable("OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED", "true"); + using var process = StartTestApplication(); + try + { + collector.AssertExpectations(); + } + finally + { + process?.Kill(); + } + } +} diff --git a/test/IntegrationTests/FileBased/TrasesTests.cs b/test/IntegrationTests/FileBased/TrasesTests.cs new file mode 100644 index 0000000000..70656c6cac --- /dev/null +++ b/test/IntegrationTests/FileBased/TrasesTests.cs @@ -0,0 +1,58 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#if NET +using IntegrationTests.Helpers; +using OpenTelemetry.Proto.Trace.V1; +using Xunit.Abstractions; + +namespace IntegrationTests.FileBased; + +public class TrasesTests : TestHelper +{ + public TrasesTests(ITestOutputHelper output) + : base("Http", output) + { + } + + [Fact] + [Trait("Category", "EndToEnd")] + public void SubmitTraces() + { + using var collector = new MockSpansCollector(Output, 4318); + SetExporter(collector); + Span? clientSpan = null; + collector.Expect("System.Net.Http", span => + { + clientSpan = span; + return true; + }); + + Span? serverSpan = null; + collector.Expect("Microsoft.AspNetCore", span => + { + serverSpan = span; + return true; + }); + + Span? manualSpan = null; + collector.Expect("TestApplication.Http", span => + { + manualSpan = span; + return true; + }); + + SetEnvironmentVariable("OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED", "true"); + + RunTestApplication(); + + collector.AssertExpectations(); + + // testing context propagation via trace hierarchy + Assert.True(clientSpan!.ParentSpanId.IsEmpty, "parent of client span should be empty"); + Assert.Equal(clientSpan.SpanId, serverSpan!.ParentSpanId); + Assert.Equal(serverSpan.SpanId, manualSpan!.ParentSpanId); + } +} +#endif + diff --git a/test/IntegrationTests/Helpers/MockLogsCollector.cs b/test/IntegrationTests/Helpers/MockLogsCollector.cs index 6121a9b30c..9d467b60d0 100644 --- a/test/IntegrationTests/Helpers/MockLogsCollector.cs +++ b/test/IntegrationTests/Helpers/MockLogsCollector.cs @@ -35,6 +35,17 @@ public MockLogsCollector(ITestOutputHelper output, string host = "localhost") #endif } + public MockLogsCollector(ITestOutputHelper output, int port, string host = "localhost") + { + _output = output; + +#if NETFRAMEWORK + _listener = new(output, HandleHttpRequests, host, port, "/v1/logs/"); +#else + _listener = new(output, nameof(MockLogsCollector), port, new PathHandler(HandleHttpRequests, "/v1/logs")); +#endif + } + /// /// Gets the TCP port that this collector is listening on. /// diff --git a/test/IntegrationTests/Helpers/MockMetricsCollector.cs b/test/IntegrationTests/Helpers/MockMetricsCollector.cs index f8227fbdad..7cbf4ffc40 100644 --- a/test/IntegrationTests/Helpers/MockMetricsCollector.cs +++ b/test/IntegrationTests/Helpers/MockMetricsCollector.cs @@ -34,6 +34,16 @@ public MockMetricsCollector(ITestOutputHelper output, string host = "localhost") #endif } + public MockMetricsCollector(ITestOutputHelper output, int port, string host = "localhost") + { + _output = output; +#if NETFRAMEWORK + _listener = new(output, HandleHttpRequests, host, port, "/v1/metrics/"); +#else + _listener = new(output, nameof(MockMetricsCollector), port, new PathHandler(HandleHttpRequests, "/v1/metrics")); +#endif + } + /// /// Gets the TCP port that this collector is listening on. /// diff --git a/test/IntegrationTests/Helpers/MockSpansCollector.cs b/test/IntegrationTests/Helpers/MockSpansCollector.cs index 64b10ece25..7193981bb6 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. /// @@ -95,6 +106,7 @@ public void AssertExpectations(TimeSpan? timeout = null) continue; } + Console.WriteLine(resourceSpans); expectationsMet.Add(resourceSpans); missingExpectations.RemoveAt(i); found = true; diff --git a/test/IntegrationTests/Helpers/TestHttpServer.AspNetCore.cs b/test/IntegrationTests/Helpers/TestHttpServer.AspNetCore.cs index d062f5fe48..e4c29cf0df 100644 --- a/test/IntegrationTests/Helpers/TestHttpServer.AspNetCore.cs +++ b/test/IntegrationTests/Helpers/TestHttpServer.AspNetCore.cs @@ -48,6 +48,36 @@ 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 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 address = _listener.ServerFeatures! + .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/test-applications/integrations/TestApplication.Http/TestApplication.Http.csproj b/test/test-applications/integrations/TestApplication.Http/TestApplication.Http.csproj index def814a846..93f93c8375 100644 --- a/test/test-applications/integrations/TestApplication.Http/TestApplication.Http.csproj +++ b/test/test-applications/integrations/TestApplication.Http/TestApplication.Http.csproj @@ -8,4 +8,10 @@ + + + PreserveNewest + + + diff --git a/test/test-applications/integrations/TestApplication.Http/config.yaml b/test/test-applications/integrations/TestApplication.Http/config.yaml new file mode 100644 index 0000000000..98b5ef9e76 --- /dev/null +++ b/test/test-applications/integrations/TestApplication.Http/config.yaml @@ -0,0 +1,11 @@ +tracer_provider: + processors: + batch: + exporter: + otlp_http: + endpoint: http://localhost:4318/v1/traces + +instrumentation/development: + dotnet: + traces: + httpclient: diff --git a/test/test-applications/integrations/TestApplication.Logs/TestApplication.Logs.csproj b/test/test-applications/integrations/TestApplication.Logs/TestApplication.Logs.csproj index ce7844057a..4c87d9e79d 100644 --- a/test/test-applications/integrations/TestApplication.Logs/TestApplication.Logs.csproj +++ b/test/test-applications/integrations/TestApplication.Logs/TestApplication.Logs.csproj @@ -4,4 +4,10 @@ net9.0;net8.0 + + + PreserveNewest + + + diff --git a/test/test-applications/integrations/TestApplication.Logs/config.yaml b/test/test-applications/integrations/TestApplication.Logs/config.yaml new file mode 100644 index 0000000000..d370a547db --- /dev/null +++ b/test/test-applications/integrations/TestApplication.Logs/config.yaml @@ -0,0 +1,11 @@ +logger_provider: + processors: + batch: + exporter: + otlp_http: + endpoint: http://localhost:4318/v1/logs + +instrumentation/development: + dotnet: + logs: + ilogger: diff --git a/test/test-applications/integrations/TestApplication.Smoke/TestApplication.Smoke.csproj b/test/test-applications/integrations/TestApplication.Smoke/TestApplication.Smoke.csproj index bf48edbe9b..03795a4d38 100644 --- a/test/test-applications/integrations/TestApplication.Smoke/TestApplication.Smoke.csproj +++ b/test/test-applications/integrations/TestApplication.Smoke/TestApplication.Smoke.csproj @@ -7,4 +7,10 @@ + + + PreserveNewest + + + diff --git a/test/test-applications/integrations/TestApplication.Smoke/config.yaml b/test/test-applications/integrations/TestApplication.Smoke/config.yaml new file mode 100644 index 0000000000..7685c5e514 --- /dev/null +++ b/test/test-applications/integrations/TestApplication.Smoke/config.yaml @@ -0,0 +1,13 @@ +meter_provider: + readers: + periodic: + exporter: + otlp_http: + endpoint: http://localhost:4318/v1/metrics + +instrumentation/development: + dotnet: + metrics: + httpclient: + netruntime: + process: From f0bb42ea897c6a6a0c39b4b14351d2bd930327b2 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 30 Jul 2025 16:36:00 +0200 Subject: [PATCH 15/28] remove unused using --- .../FileBasedConfiguration/ZipkinExporterConfig.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs index 8b77c23cb6..a4ce8ab6e0 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 using YamlDotNet.Serialization; -using static System.Net.WebRequestMethods; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; From 900baa25923272f6d9bf61886e3c0e48993b64ef Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Wed, 30 Jul 2025 17:43:33 +0200 Subject: [PATCH 16/28] fix tests --- .../Configurations/AssemblyInfo.cs | 5 +++++ .../FileBased/FilebasedGeneralSettingsTests.cs | 2 +- .../Configurations/FileBased/ParserTests.cs | 1 + .../Configurations/ServiceNameConfiguratorTests.cs | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/AssemblyInfo.cs diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/AssemblyInfo.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/AssemblyInfo.cs new file mode 100644 index 0000000000..e47741118c --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/AssemblyInfo.cs @@ -0,0 +1,5 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs index e5217a3d46..b44f81cc5b 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs @@ -163,7 +163,7 @@ public void LoadFile_SetsSetupSdkFromDisabledFlag() var settings = new GeneralSettings(); settings.LoadFile(conf); - Assert.True(settings.SetupSdk); + Assert.False(settings.SetupSdk); } [Fact] diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs index ab4c80adca..07d11b3bb3 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs @@ -8,6 +8,7 @@ namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; +[Collection("Non-Parallel Collection")] public class ParserTests { [Fact] diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ServiceNameConfiguratorTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ServiceNameConfiguratorTests.cs index 48e1379602..da07b98ed3 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ServiceNameConfiguratorTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ServiceNameConfiguratorTests.cs @@ -6,6 +6,7 @@ namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations; +[Collection("Non-Parallel Collection")] public class ServiceNameConfiguratorTests { private const string ServiceName = "service.name"; From 252061cfd22fef04a98927bfa2157a4936ebcfa5 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Fri, 1 Aug 2025 09:12:32 +0200 Subject: [PATCH 17/28] Add FailFast --- .../Configurations/FailFastSettings.cs | 1 + .../Configurations/FileBasedConfiguration/Conf.cs | 7 +++++++ .../Configurations/SdkSettings.cs | 2 +- .../Configurations/FileBased/Files/TestFile.yaml | 1 + .../Configurations/FileBased/ParserTests.cs | 1 + 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FailFastSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FailFastSettings.cs index 59a45daed3..e8a854d143 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FailFastSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FailFastSettings.cs @@ -16,5 +16,6 @@ protected override void OnLoadEnvVar(Configuration configuration) protected override void OnLoadFile(Conf configuration) { + FailFast = configuration.FailFast; } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs index d8b01592b8..a3f10312dc 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs @@ -29,6 +29,13 @@ internal class Conf [YamlMember(Alias = "log_level")] public string LogLevel { get; set; } = "info"; + /// + /// Gets or sets a value indicating whether the Fail Fast is enabled. + /// If omitted or null, false is used. + /// + [YamlMember(Alias = "fail_fast")] + public bool FailFast { get; set; } = false; + /// /// Gets or sets the attribute limits. /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs index 4ef5813a89..e5339a0c6b 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs @@ -88,7 +88,7 @@ protected override void OnLoadFile(Conf configuration) var unsupportedMessage = $"Propagator '{propagatorName}' is not supported."; Logger.Error(unsupportedMessage); - if (string.Equals(configuration.LogLevel, "fail_fast", StringComparison.OrdinalIgnoreCase)) + if (configuration.FailFast == true) { throw new NotSupportedException(unsupportedMessage); } diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml index 7f735ab75f..5edab78475 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml @@ -1,6 +1,7 @@ file_format: "0.4" disabled: false log_level: info +fail_fast: true attribute_limits: attribute_value_length_limit: 4096 attribute_count_limit: 128 diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs index 07d11b3bb3..3f4186e49d 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs @@ -21,6 +21,7 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() Assert.Equal("0.4", config.FileFormat); Assert.False(config.Disabled); Assert.Equal("info", config.LogLevel); + Assert.True(config.FailFast); Assert.NotNull(config.AttributeLimits); Assert.Equal(4096, config.AttributeLimits.AttributeValueLengthLimit); From 206948a5a3a051c62dcf90605473fa0a6d781eea Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Fri, 1 Aug 2025 11:04:08 +0200 Subject: [PATCH 18/28] dosc --- docs/config.md | 363 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 363 insertions(+) diff --git a/docs/config.md b/docs/config.md index db21585e43..2312047fbc 100644 --- a/docs/config.md +++ b/docs/config.md @@ -45,6 +45,34 @@ with environment variables taking precedence over `App.config` or `Web.config` f `SiteName\VirtualPath` ex: `MySite\MyApp` - If that is not the case it will use the name of the application [entry Assembly](https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.getentryassembly?view=net-7.0). +4. File-based Configuration (Experimental) + + > **Status:** [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) + > For more information about the OpenTelemetry configuration specification, see: + > **[File-based configuration documentation](https://opentelemetry.io/docs/specs/otel/configuration/sdk/)** + + You can configure OpenTelemetry using a YAML file. This method is disabled + by default and must be explicitly enabled. + + To enable file-based configuration, set the following environment variable: + + ```bash + OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED=true + ``` + + By default, the value is false. + + You can also specify the configuration file path (default: config.yaml): + + ```bash + OTEL_EXPERIMENTAL_CONFIG_FILE=/path/to/config.yaml + ``` + + In your config file you can use environment variables in format: ${ENVIRONMENT_VARIABLE} + insted of "value" + + See [configuration examples](#configuration-examples) + By default we recommend using environment variables for configuration. However, if given setting supports it, then: @@ -503,3 +531,338 @@ instead. |----------------------------------|-------------------------------------------------------------------------|------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------| | `OTEL_DOTNET_AUTO_LOG_DIRECTORY` | Directory of the .NET Tracer logs. | *See the previous note on default paths* | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) | | `OTEL_LOG_LEVEL` | SDK log level. (supported values: `none`,`error`,`warn`,`info`,`debug`) | `info` | [Stable](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) | + +## Configuration Examples + +### Global Configuration + +``` yaml +# The file format version. +# The yaml format is documented at +# +file_format: "0.4" +# Configure if the SDK is disabled or not. +# If omitted or null, false is used +disabled: false +# Configure the log level of the internal logger used by the SDK. +# If omitted, info is used. +log_level: info +# Configure if the Fail Fast is enabled or not. +# If omitted or null, false is used +fail_fast: false +# Configure general attribute limits. See also tracer_provider.limits, logger_provider.limits. +attribute_limits: + # Configure max attribute value size. + # Value must be non-negative. + # If omitted or null, there is no limit. + attribute_value_length_limit: 4096 + # Configure max attribute count. + # Value must be non-negative. + # If omitted or null, 128 is used. + attribute_count_limit: 128 +``` + +### Propagator Configuration + +You can configure text map context propagators directly in YAML or via the +`OTEL_PROPAGATORS` environment variable. +For more details and updates, see: [Propagators list and documentation](https://opentelemetry.io/docs/zero-code/dotnet/configuration/#propagators) + +``` yaml +propagator: + # Composite propagators are evaluated together. + # Entries from .composite_list are appended here (duplicates are filtered out). + composite: + tracecontext: # W3C Trace Context propagator + baggage: # W3C Baggage propagator + b3: # B3 single-header propagator + b3multi: # Zipkin B3 multi-header propagator + # Alternatively, configure via a comma-separated list (same format as OTEL_PROPAGATORS). + composite_list: ${OTEL_PROPAGATORS} +``` + +### Resource Configuration + +You can configure text map context propagators directly in YAML or via the +`OTEL_RESOURCE_ATTRIBUTES` environment variable. + +``` yaml +resource: +# Configure resource attributes. Entries have higher priority than entries from .resource.attributes_list. +# Entries must contain .name and .value, and may optionally include .type. If an entry's .type omitted or null, string is used. +# The .value's type must match the .type. Values for .type include: string, bool, int, double, string_array, bool_array, int_array, double_array. + attributes: + - name: service.name + value: unknown_service + type: string + # Alternatively, configure via a comma-separated list (same format as OTEL_RESOURCE_ATTRIBUTES). + attributes_list: ${OTEL_RESOURCE_ATTRIBUTES} +``` + +### Resource Detectors Configuration + +For more details and updates, see: [Resource Detectors list and documentation](https://opentelemetry.io/docs/zero-code/dotnet/configuration/#resource-detectors) + +``` yaml +resource: + detection/development: + detectors: + azureappservice: # Detects Azure App Service resource information + container: # Detects container resource info (container.* attributes) [Core only] + host: # Detects host resource info (host.* attributes) + operatingsystem: # Detects OS-level attributes (os.*) + process: # Detects process-level attributes (process.*) + processruntime: # Detects process runtime attributes (process.runtime.*) + service: # Detects service.name and service.instance.id +``` + +### 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: +``` + +### Logger Provider Configuration + +``` yaml +logger_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/logs is used + endpoint: http://localhost:4318/v1/logs + # 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_LOGS_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. + # Add the console exporter to enable it. + console: +``` + +### Meter Provider Configuration + +``` yaml +meter_provider: + readers: + # Configure a periodic metric reader. + periodic: + # Configure delay interval (in milliseconds) between start of two consecutive exports. + # Value must be non-negative. + # If omitted or null, 60000 is used. + interval: 60000 + # 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. + timeout: 30000 + # 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/metrics is used + endpoint: http://localhost:4318/v1/metrics + # 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_METRICS_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. + # Add the console exporter to enable it. + console: + # Configure a pull based metric reader. + pull: + exporter: + # Add the prometheus exporter to enable it. + # Do NOT use in production. + # Prometheus exporter is intended for the inner dev loop. Production environments can use a combination of OTLP exporter with OpenTelemetry Collector having otlp receiver and prometheus exporter. + prometheus: +``` + +### Instrumentation Configuration + +You can configure traces, metrics, and logs instrumentations. +For more details and updates, see: [Instrumentation list and documentation](https://opentelemetry.io/docs/zero-code/dotnet/instrumentations/) + +``` yaml +instrumentation/development: + dotnet: + traces: + aspnet: # ASP.NET (.NET Framework) MVC/WebApi [Framework only] + aspnetcore: # ASP.NET Core [Core only] + azure: # Azure SDK [Core & Framework] + elasticsearch: # Elastic.Clients.Elasticsearch [Core & Framework] + elastictransport: # Elastic.Transport (>=0.4.16) [Core & Framework] + entityframeworkcore: # Entity Framework Core (>=6.0.12) [Core only] + graphql: # GraphQL (>=7.5.0) [Core only] + grpcnetclient: # Grpc.Net.Client (>=2.52.0 & <3.0.0) [Core only] + httpclient: # System.Net.Http.HttpClient [Core & Framework] + kafka: # Confluent.Kafka (>=1.4.0 & <3.0.0) [Core & Framework] + masstransit: # MassTransit (>=8.0.0) [Core only] + mongodb: # MongoDB.Driver (>=2.7.0 <4.0.0) [Core & Framework] + mysqlconnector: # MySqlConnector (>=2.0.0) [Core only] + mysqldata: # MySql.Data (>=8.1.0) [Core only] + npgsql: # Npgsql (>=6.0.0) [Core only] + nservicebus: # NServiceBus (>=8.0.0 & <10.0.0) [Core & Framework] + oraclemda: # Oracle.ManagedDataAccess (>=23.4.0) [Core only] + rabbitmq: # RabbitMQ.Client (>=6.0.0) [Core & Framework] + quartz: # Quartz (>=3.4.0, not supported < .NET Framework 4.7.2) + sqlclient: # Microsoft.Data.SqlClient & System.Data.SqlClient [Core & Framework] + stackexchangeredis: # StackExchange.Redis (>=2.6.122 & <3.0.0) [Core only] + wcfclient: # WCF Client [Core & Framework] + wcfservice: # WCF Service [Framework only] + metrics: + aspnetcore: # ASP.NET Core metrics [Core only] + httpclient: # HttpClient metrics [Core & Framework] + netruntime: # .NET Runtime metrics [Core only] + nservicebus: # NServiceBus metrics [Core & Framework] + process: # Process metrics [Core & Framework] + sqlclient: # SQL Client metrics [Core & Framework] + logs: + ilogger: # Microsoft.Extensions.Logging (>=9.0.0) [Core & Framework] + log4net: # log4net (>=2.0.13 && <4.0.0) [Core & Framework] +``` + +### Instrumentation options + +You can configure directly in YAML or via environment variables. + +``` yaml +instrumentation/development: + dotnet: + traces: + entityframeworkcore: + # Whether the Entity Framework Core instrumentation can pass SQL statements through the db.statement attribute. Queries might contain sensitive information. If set to false, db.statement is recorded only for executing stored procedures. + # Default is false + set_db_statement_for_text: false + graphql: + # Whether the GraphQL instrumentation can pass raw queries through the graphql.document attribute. Queries might contain sensitive information. + # Default is false + set_document: false + oraclemda: + # Whether the Oracle Client instrumentation can pass SQL statements through the db.statement attribute. Queries might contain sensitive information. If set to false, db.statement is recorded only for executing stored procedures. + # Default is false + set_db_statement_for_text: false + sqlclient: + # Whether the SQL Client instrumentation can pass SQL statements through the db.statement attribute. Queries might contain sensitive information. If set to false, db.statement is recorded only for executing stored procedures. + # Not supported on .NET Framework for System.Data.SqlClient. + # Default is false + set_db_statement_for_text: false + aspnet: + # A comma-separated list of HTTP header names. ASP.NET instrumentations will capture HTTP request header values for all configured header names. + capture_request_headers: "X-Key=Value" + # A comma-separated list of HTTP header names. ASP.NET instrumentations will capture HTTP response header values for all configured header names. + capture_response_headers: "X-Key=Value" + aspnetcore: + # A comma-separated list of HTTP header names. ASP.NET Core instrumentations will capture HTTP request header values for all configured header names. + capture_request_headers: "X-Key=Value" + # A comma-separated list of HTTP header names. ASP.NET Core instrumentations will capture HTTP response header values for all configured header names. + capture_response_headers: "X-Key=Value" + httpclient: + # A comma-separated list of HTTP header names. HTTP Client instrumentations will capture HTTP request header values for all configured header names. + capture_request_headers: "X-Key=Value" + # A comma-separated list of HTTP header names. HTTP Client instrumentations will capture HTTP response header values for all configured header names. + capture_response_headers: "X-Key=Value" + grpcnetclient: + # A comma-separated list of gRPC metadata names. Grpc.Net.Client instrumentations will capture gRPC request metadata values for all configured metadata names. + capture_request_metadata: "X-Key=Value" + # A comma-separated list of gRPC metadata names. Grpc.Net.Client instrumentations will capture gRPC response metadata values for all configured metadata names. + capture_response_metadata: "X-Key=Value" +``` From c7d1dced367cb2a766cbe485118fc89354f573d9 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Fri, 1 Aug 2025 11:04:24 +0200 Subject: [PATCH 19/28] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3934347c3b..0ac00ea260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ This component adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h - In install script, new function added: Register-AssembliesInGAC. It installs OpenTelemetry assemblies and dependencies in GAC. +- Support for [Declarative configuration](https://opentelemetry.io/docs/specs/otel/configuration/#declarative-configuration) + ### Changed - Musl-based (Alpine) libraries are compiled on Alpine v3.21. From 5ea0fcdbe6e8db3762ce809c1c4a328e4c3986f0 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Fri, 1 Aug 2025 11:21:56 +0200 Subject: [PATCH 20/28] fix --- docs/config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.md b/docs/config.md index 2312047fbc..056479868a 100644 --- a/docs/config.md +++ b/docs/config.md @@ -69,7 +69,7 @@ with environment variables taking precedence over `App.config` or `Web.config` f ``` In your config file you can use environment variables in format: ${ENVIRONMENT_VARIABLE} - insted of "value" + instead of "value" See [configuration examples](#configuration-examples) From 61d1538367812142c9319347dc58d303082ae459 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Fri, 1 Aug 2025 15:22:10 +0200 Subject: [PATCH 21/28] cleanup --- .../Configurations/Settings.cs | 1 - .../Configurations/FileBased/ParserTests.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs index 8d7b0407a7..d3a9110f95 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs @@ -20,7 +20,6 @@ public static T FromDefaultSources(bool failFast) { var configFile = Environment.GetEnvironmentVariable("OTEL_EXPERIMENTAL_CONFIG_FILE") ?? "config.yaml"; var config = Parser.ParseYaml(configFile); - Console.WriteLine("Parsed YAML configuration."); var settings = new T(); settings.LoadFile(config); return settings; diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs index 3f4186e49d..c86d14bae4 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs @@ -165,7 +165,7 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() string[] expectedMetrics = [ "aspnet", "httpclient", "netruntime", - "nservicebus", "process", "sqlclient" + "nservicebus", "process", "sqlclient" ]; #endif From 0a80dd0de46a60315ab468c76d4fe98017e7de8d Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Thu, 14 Aug 2025 15:31:39 +0200 Subject: [PATCH 22/28] fix tests --- test/IntegrationTests/FileBased/LogsTests.cs | 2 +- test/IntegrationTests/FileBased/MetricsTests.cs | 4 ++-- test/IntegrationTests/FileBased/TrasesTests.cs | 10 +--------- test/IntegrationTests/Helpers/TestHelper.cs | 6 ++++++ .../integrations/TestApplication.Http/config.yaml | 3 ++- .../integrations/TestApplication.Smoke/config.yaml | 1 + 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/test/IntegrationTests/FileBased/LogsTests.cs b/test/IntegrationTests/FileBased/LogsTests.cs index 4f748e1328..a9f51a4593 100644 --- a/test/IntegrationTests/FileBased/LogsTests.cs +++ b/test/IntegrationTests/FileBased/LogsTests.cs @@ -31,7 +31,7 @@ public void SubmitLogs() }); SetEnvironmentVariable("ASPNETCORE_HOSTINGSTARTUPASSEMBLIES", "OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper"); - SetEnvironmentVariable("OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED", "true"); + EnableFileBasedConfigWithDefaultPath(); RunTestApplication(); diff --git a/test/IntegrationTests/FileBased/MetricsTests.cs b/test/IntegrationTests/FileBased/MetricsTests.cs index f20528d052..8868bc0d2f 100644 --- a/test/IntegrationTests/FileBased/MetricsTests.cs +++ b/test/IntegrationTests/FileBased/MetricsTests.cs @@ -12,7 +12,6 @@ public MetricsTests(ITestOutputHelper output) : base("Smoke", output) { SetEnvironmentVariable("LONG_RUNNING", "true"); - SetEnvironmentVariable("OTEL_METRIC_EXPORT_INTERVAL", "100"); } [Fact] @@ -22,7 +21,8 @@ public void SubmitMetrics() using var collector = new MockMetricsCollector(Output, 4318); SetExporter(collector); collector.Expect("OpenTelemetry.Instrumentation.Process"); - SetEnvironmentVariable("OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED", "true"); + EnableFileBasedConfigWithDefaultPath(); + using var process = StartTestApplication(); try { diff --git a/test/IntegrationTests/FileBased/TrasesTests.cs b/test/IntegrationTests/FileBased/TrasesTests.cs index 70656c6cac..1f5bf6983a 100644 --- a/test/IntegrationTests/FileBased/TrasesTests.cs +++ b/test/IntegrationTests/FileBased/TrasesTests.cs @@ -35,14 +35,7 @@ public void SubmitTraces() return true; }); - Span? manualSpan = null; - collector.Expect("TestApplication.Http", span => - { - manualSpan = span; - return true; - }); - - SetEnvironmentVariable("OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED", "true"); + EnableFileBasedConfigWithDefaultPath(); RunTestApplication(); @@ -51,7 +44,6 @@ public void SubmitTraces() // testing context propagation via trace hierarchy Assert.True(clientSpan!.ParentSpanId.IsEmpty, "parent of client span should be empty"); Assert.Equal(clientSpan.SpanId, serverSpan!.ParentSpanId); - Assert.Equal(serverSpan.SpanId, manualSpan!.ParentSpanId); } } #endif diff --git a/test/IntegrationTests/Helpers/TestHelper.cs b/test/IntegrationTests/Helpers/TestHelper.cs index 3bd47eae18..e986e8ad81 100644 --- a/test/IntegrationTests/Helpers/TestHelper.cs +++ b/test/IntegrationTests/Helpers/TestHelper.cs @@ -90,6 +90,12 @@ public void EnableDefaultExporters() RemoveEnvironmentVariable("OTEL_LOGS_EXPORTER"); } + public void EnableFileBasedConfigWithDefaultPath() + { + SetEnvironmentVariable("OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED", "true"); + SetEnvironmentVariable("OTEL_EXPERIMENTAL_CONFIG_FILE", Path.Combine(EnvironmentHelper.GetTestApplicationApplicationOutputDirectory(), "config.yaml")); + } + public (string StandardOutput, string ErrorOutput, int ProcessId) RunTestApplication(TestSettings? testSettings = null) { // RunTestApplication starts the test application, wait up to DefaultProcessTimeout. diff --git a/test/test-applications/integrations/TestApplication.Http/config.yaml b/test/test-applications/integrations/TestApplication.Http/config.yaml index 98b5ef9e76..75dad17cff 100644 --- a/test/test-applications/integrations/TestApplication.Http/config.yaml +++ b/test/test-applications/integrations/TestApplication.Http/config.yaml @@ -8,4 +8,5 @@ tracer_provider: instrumentation/development: dotnet: traces: - httpclient: + aspnetcore: + httpclient: \ No newline at end of file diff --git a/test/test-applications/integrations/TestApplication.Smoke/config.yaml b/test/test-applications/integrations/TestApplication.Smoke/config.yaml index 7685c5e514..5199ddae69 100644 --- a/test/test-applications/integrations/TestApplication.Smoke/config.yaml +++ b/test/test-applications/integrations/TestApplication.Smoke/config.yaml @@ -1,6 +1,7 @@ meter_provider: readers: periodic: + interval: 100 exporter: otlp_http: endpoint: http://localhost:4318/v1/metrics From 93b1eaea23edfc060c737e35f119c2e8866c2a23 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Thu, 14 Aug 2025 15:34:39 +0200 Subject: [PATCH 23/28] vendor YamlDotNet --- src/Directory.Packages.props | 1 - .../netfx_assembly_redirection.h | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 18a61b1897..5146758e83 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -31,7 +31,6 @@ - diff --git a/src/OpenTelemetry.AutoInstrumentation.Native/netfx_assembly_redirection.h b/src/OpenTelemetry.AutoInstrumentation.Native/netfx_assembly_redirection.h index 9033bf3a0f..964699b068 100644 --- a/src/OpenTelemetry.AutoInstrumentation.Native/netfx_assembly_redirection.h +++ b/src/OpenTelemetry.AutoInstrumentation.Native/netfx_assembly_redirection.h @@ -159,8 +159,7 @@ void CorProfiler::InitNetFxAssemblyRedirectsMap() { L"System.Xml.XmlDocument", {4, 0, 3, 0} }, { L"System.Xml.XmlSerializer", {4, 0, 11, 0} }, { L"System.Xml.XPath", {4, 0, 3, 0} }, - { L"System.Xml.XPath.XDocument", {4, 1, 0, 0} }, - { L"YamlDotNet", {16, 0, 0, 0} } + { L"System.Xml.XPath.XDocument", {4, 1, 0, 0} } }); } } From 45079f2dc16759804b3405206afffc91005ca198 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Mon, 18 Aug 2025 09:09:21 +0200 Subject: [PATCH 24/28] fix dotnet format --- .../OpenTelemetry.AutoInstrumentation.csproj | 1 - .../Vendors/YamlDotNet/Core/Tokens/BlockMappingStart.cs | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj b/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj index bca305f3b2..11b865a9c1 100644 --- a/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj +++ b/src/OpenTelemetry.AutoInstrumentation/OpenTelemetry.AutoInstrumentation.csproj @@ -43,7 +43,6 @@ - diff --git a/src/OpenTelemetry.AutoInstrumentation/Vendors/YamlDotNet/Core/Tokens/BlockMappingStart.cs b/src/OpenTelemetry.AutoInstrumentation/Vendors/YamlDotNet/Core/Tokens/BlockMappingStart.cs index 85a2ad3860..c49a994ea8 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Vendors/YamlDotNet/Core/Tokens/BlockMappingStart.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Vendors/YamlDotNet/Core/Tokens/BlockMappingStart.cs @@ -1,4 +1,9 @@ -// This file is part of YamlDotNet - A .NET library for YAML. +//------------------------------------------------------------------------------ +// +// This comment is here to prevent StyleCop from analyzing a file originally from YamlDotNet. +//------------------------------------------------------------------------------ + +// This file is part of YamlDotNet - A .NET library for YAML. // Copyright (c) Antoine Aubry and contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy of From 1474b3c25f040150973eb5f3e328c9afe86799d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 28 Aug 2025 10:53:26 +0200 Subject: [PATCH 25/28] adjust vendored namespaces --- .../FileBasedConfiguration/AttributeLimits.cs | 2 +- .../FileBasedConfiguration/BatchProcessorConfig.cs | 2 +- .../FileBasedConfiguration/CaptureHeadersConfiguration.cs | 2 +- .../FileBasedConfiguration/CaptureMetadataConfiguration.cs | 2 +- .../Configurations/FileBasedConfiguration/Conf.cs | 2 +- .../FileBasedConfiguration/DetectionDevelopment.cs | 2 +- .../FileBasedConfiguration/DotNetDetectors.cs | 2 +- .../FileBasedConfiguration/DotNetInstrumentation.cs | 2 +- .../Configurations/FileBasedConfiguration/DotNetLogs.cs | 2 +- .../Configurations/FileBasedConfiguration/DotNetMetrics.cs | 2 +- .../Configurations/FileBasedConfiguration/DotNetTraces.cs | 2 +- .../FileBasedConfiguration/ExporterConfig.cs | 2 +- .../Configurations/FileBasedConfiguration/Header.cs | 2 +- .../FileBasedConfiguration/InstrumentationDevelopment.cs | 2 +- .../FileBasedConfiguration/LoggerProviderConfiguration.cs | 2 +- .../FileBasedConfiguration/MeterProviderConfiguration.cs | 2 +- .../FileBasedConfiguration/OtlpGrpcExporterConfig.cs | 2 +- .../FileBasedConfiguration/OtlpHttpExporterConfig.cs | 2 +- .../Parser/ConditionalDeserializer.cs | 7 +++---- .../FileBasedConfiguration/Parser/EnvVarTypeConverter.cs | 6 +++--- .../Configurations/FileBasedConfiguration/Parser/Parser.cs | 4 ++-- .../FileBasedConfiguration/PropagatorConfiguration.cs | 2 +- .../FileBasedConfiguration/ReaderConfiguration.cs | 2 +- .../FileBasedConfiguration/ResourceAttribute.cs | 2 +- .../FileBasedConfiguration/ResourceConfiguration.cs | 2 +- .../SetDbStatementForTextConfuguration.cs | 2 +- .../FileBasedConfiguration/SetDocumentConfiguration.cs | 2 +- .../FileBasedConfiguration/TracerProviderConfiguration.cs | 2 +- .../FileBasedConfiguration/ZipkinExporterConfig.cs | 2 +- .../Configurations/LogSettings.cs | 2 +- .../Configurations/FileBased/ParserTests.cs | 2 +- 31 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/AttributeLimits.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/AttributeLimits.cs index d75e9f014f..1aed0eadfc 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/AttributeLimits.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/AttributeLimits.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs index a6f303768b..0a0095e8db 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/BatchProcessorConfig.cs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using System.Diagnostics; -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs index f37fa0c878..2d261c844f 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureHeadersConfiguration.cs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs index 970a539423..5f0f32e2af 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/CaptureMetadataConfiguration.cs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs index a3f10312dc..d0ad01ef18 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DetectionDevelopment.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DetectionDevelopment.cs index e367dba566..0db7b77b1e 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DetectionDevelopment.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DetectionDevelopment.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetDetectors.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetDetectors.cs index ba8fb12964..c5ff335cee 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetDetectors.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetDetectors.cs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using System.Reflection; -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetInstrumentation.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetInstrumentation.cs index 3b6a4274dd..d0d99d6bdc 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetInstrumentation.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetInstrumentation.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs index 11eebd53cf..302cad8780 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetLogs.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetMetrics.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetMetrics.cs index cd2ca5968b..1872d08058 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetMetrics.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetMetrics.cs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using System.Reflection; -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs index 8ed7eda86a..fcd6b3c400 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/DotNetTraces.cs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using System.Reflection; -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs index 36a2e9aa9c..8954eea496 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ExporterConfig.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Header.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Header.cs index cf35439e0d..fcb10a6686 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Header.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Header.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/InstrumentationDevelopment.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/InstrumentationDevelopment.cs index a1254ca214..7768f51e0b 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/InstrumentationDevelopment.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/InstrumentationDevelopment.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/LoggerProviderConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/LoggerProviderConfiguration.cs index 689e4887e4..f58dcabfef 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/LoggerProviderConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/LoggerProviderConfiguration.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/MeterProviderConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/MeterProviderConfiguration.cs index 4b64f8e9a2..7475149378 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/MeterProviderConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/MeterProviderConfiguration.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs index 1692329ab5..c625f53bd6 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpGrpcExporterConfig.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +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 f3154ae035..db4515148d 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/OtlpHttpExporterConfig.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/ConditionalDeserializer.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/ConditionalDeserializer.cs index adc89854aa..89426149fe 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/ConditionalDeserializer.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/ConditionalDeserializer.cs @@ -1,10 +1,9 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using System.Reflection; -using YamlDotNet.Core; -using YamlDotNet.Core.Events; -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Core; +using Vendors.YamlDotNet.Core.Events; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EnvVarTypeConverter.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EnvVarTypeConverter.cs index 61884896af..05ac3a95ce 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EnvVarTypeConverter.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EnvVarTypeConverter.cs @@ -3,9 +3,9 @@ using System.Globalization; using System.Text.RegularExpressions; -using YamlDotNet.Core; -using YamlDotNet.Core.Events; -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Core; +using Vendors.YamlDotNet.Core.Events; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs index 5a1dc7ef80..7f10b0d13a 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs @@ -1,8 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; -using YamlDotNet.Serialization.NodeDeserializers; +using Vendors.YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization.NodeDeserializers; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/PropagatorConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/PropagatorConfiguration.cs index 7c43ec53ca..1414c0d5c0 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/PropagatorConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/PropagatorConfiguration.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs index 09f4d1534a..27f4d6bd1a 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ReaderConfiguration.cs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using OpenTelemetry.Metrics; -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceAttribute.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceAttribute.cs index fd6b788dcb..fae559405a 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceAttribute.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceAttribute.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs index 7199f091bf..b7b43b9229 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs index 235632a195..2d52867df5 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDbStatementForTextConfuguration.cs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs index 225cfc6fd1..b2baee5616 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/SetDocumentConfiguration.cs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs index 0de02e27b1..21be9eaef9 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/TracerProviderConfiguration.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs index a4ce8ab6e0..45fafd8429 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ZipkinExporterConfig.cs @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs index cda0e3f30c..df05805544 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs @@ -4,7 +4,7 @@ using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; using OpenTelemetry.AutoInstrumentation.Configurations.Otlp; using OpenTelemetry.AutoInstrumentation.Logging; -using YamlDotNet.Core.Tokens; +using Vendors.YamlDotNet.Core.Tokens; namespace OpenTelemetry.AutoInstrumentation.Configurations; diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs index c86d14bae4..b15b0e441a 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs @@ -3,8 +3,8 @@ using System.Reflection; using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; +using Vendors.YamlDotNet.Serialization; using Xunit; -using YamlDotNet.Serialization; namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; From 67be19d52e16b5d97066e92b1c277ddbecaa35aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 28 Aug 2025 10:58:18 +0200 Subject: [PATCH 26/28] Fix CHANGELOG --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ac00ea260..665ee11b9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This component adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h - Extend support for [RabbitMQ.Client](https://www.nuget.org/packages/RabbitMQ.Client/) traces instrumentation for versions `5.*`. +- Support for [file based configuration](./docs/config.md#configuration-examples) ### Changed @@ -37,8 +38,6 @@ This component adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h - In install script, new function added: Register-AssembliesInGAC. It installs OpenTelemetry assemblies and dependencies in GAC. -- Support for [Declarative configuration](https://opentelemetry.io/docs/specs/otel/configuration/#declarative-configuration) - ### Changed - Musl-based (Alpine) libraries are compiled on Alpine v3.21. From 2c2e2f7113e74bd0aadea728295bc3f623390c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Fri, 29 Aug 2025 10:24:46 +0200 Subject: [PATCH 27/28] Vendors - cleanup generator headers --- .../Vendors/YamlDotNet/Core/Tokens/BlockMappingStart.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Vendors/YamlDotNet/Core/Tokens/BlockMappingStart.cs b/src/OpenTelemetry.AutoInstrumentation/Vendors/YamlDotNet/Core/Tokens/BlockMappingStart.cs index c49a994ea8..f52242160c 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Vendors/YamlDotNet/Core/Tokens/BlockMappingStart.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Vendors/YamlDotNet/Core/Tokens/BlockMappingStart.cs @@ -1,8 +1,3 @@ -//------------------------------------------------------------------------------ -// -// This comment is here to prevent StyleCop from analyzing a file originally from YamlDotNet. -//------------------------------------------------------------------------------ - // This file is part of YamlDotNet - A .NET library for YAML. // Copyright (c) Antoine Aubry and contributors // From 018e49e1850b67a1151faa7dfffeee1c4492ac3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Fri, 29 Aug 2025 10:26:09 +0200 Subject: [PATCH 28/28] revert empty lines --- .../Loading/Initializers/GraphQLInitializer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/OpenTelemetry.AutoInstrumentation/Loading/Initializers/GraphQLInitializer.cs b/src/OpenTelemetry.AutoInstrumentation/Loading/Initializers/GraphQLInitializer.cs index 605c05f8d7..e59cf505a2 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Loading/Initializers/GraphQLInitializer.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Loading/Initializers/GraphQLInitializer.cs @@ -31,8 +31,10 @@ public override void Initialize(ILifespanManager lifespanManager) var optionsType = Type.GetType("GraphQL.Telemetry.GraphQLTelemetryOptions, GraphQL")!; var optionsInstance = Activator.CreateInstance(optionsType)!; + optionsType?.GetProperty("RecordDocument")? .SetValue(optionsInstance, _tracerSettings.InstrumentationOptions.GraphQLSetDocument); + _pluginManager.ConfigureTracesOptions(optionsInstance); initializerType.GetMethod("EnableAutoInstrumentation", BindingFlags.Public | BindingFlags.Static)!