From 4bae3e9cf7edb58f00c3109cecc4ba8ea992b858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 11 Sep 2025 12:16:05 +0200 Subject: [PATCH 01/19] [File Based Config] Resources > Co-authored-by: Yevhenii Solomchenko --- .../Configurations/ConfigurationKeys.cs | 10 ++ .../Configurations/FailFastSettings.cs | 2 +- .../FileBasedConfiguration/Conf.cs | 25 +++ .../FileBasedConfiguration/Parser/Parser.cs | 23 +++ .../ResourceAttribute.cs | 27 +++ .../ResourceConfiguration.cs | 37 +++++ .../Configurations/GeneralSettings.cs | 104 +++++++++++- .../Configurations/LogSettings.cs | 2 +- .../Configurations/MetricSettings.cs | 2 +- .../Configurations/ResourceConfigurator.cs | 14 +- .../Configurations/SdkSettings.cs | 3 +- .../Configurations/Settings.cs | 44 ++++- .../Configurations/TracerSettings.cs | 2 +- .../Constants.cs | 5 + .../HeaderConfigurationExtensions.cs | 4 +- .../Instrumentation.cs | 6 +- .../Logger/LoggerInitializer.cs | 2 +- test/IntegrationTests/Helpers/TestHelper.cs | 6 + .../Configurations/AssemblyInfo.cs | 5 + .../FilebasedGeneralSettingsTests.cs | 154 ++++++++++++++++++ .../FileBased/Files/TestFile.yaml | 7 + .../FileBased/Files/TestFileEnvVars.yaml | 7 + .../Configurations/FileBased/ParserTests.cs | 47 ++++++ .../Configurations/PluginManagerTests.cs | 2 +- .../ServiceNameConfiguratorTests.cs | 5 +- ...Telemetry.AutoInstrumentation.Tests.csproj | 9 + 26 files changed, 521 insertions(+), 33 deletions(-) create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceAttribute.cs create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/AssemblyInfo.cs create mode 100644 test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.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/ConfigurationKeys.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs index d1ca2b0b6b..85e5f65e21 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/FailFastSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FailFastSettings.cs index 02bd7ee8bd..802a2a4e59 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FailFastSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FailFastSettings.cs @@ -7,7 +7,7 @@ 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; } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs new file mode 100644 index 0000000000..996fdd2959 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs @@ -0,0 +1,25 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.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 the resource configuration. + /// Configure resource for all signals. + /// If omitted, the default resource is used. + /// + [YamlMember(Alias = "resource")] + public ResourceConfiguration? Resource { get; set; } +} 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..7f10b0d13a --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs @@ -0,0 +1,23 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.YamlDotNet.Serialization; +using Vendors.YamlDotNet.Serialization.NodeDeserializers; + +namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; + +internal static class Parser +{ + public static Conf ParseYaml(string filePath) + { + var deserializer = new DeserializerBuilder() + .WithNodeDeserializer(existing => new ConditionalDeserializer(existing), s => s.InsteadOf()) + .WithTypeConverter(new EnvVarTypeConverter()) + .IgnoreUnmatchedProperties() + .Build(); + + var yaml = File.ReadAllText(filePath); + var config = deserializer.Deserialize(yaml); + return config; + } +} diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceAttribute.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceAttribute.cs new file mode 100644 index 0000000000..fae559405a --- /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 Vendors.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..149a380273 --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs @@ -0,0 +1,37 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using Vendors.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; } + + 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 732af52102..28bbeda6b3 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 @@ -15,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. @@ -32,7 +39,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) @@ -43,6 +50,35 @@ protected override void OnLoad(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( @@ -54,4 +90,70 @@ protected override void OnLoad(Configuration configuration) ProfilerEnabled = configuration.GetString(ConfigurationKeys.ProfilingEnabled) == "1"; } + + protected override void OnLoadFile(Conf configuration) + { + 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(); + } + + 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/LogSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs index 7d98e346e2..0b15291aa5 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/LogSettings.cs @@ -43,7 +43,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); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs index a3a54e2c6e..ed5dd28906 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/MetricSettings.cs @@ -38,7 +38,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)) 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/Configurations/SdkSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs index c0c0b14725..98fdb8c10c 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/SdkSettings.cs @@ -1,7 +1,6 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using System.Diagnostics.CodeAnalysis; using OpenTelemetry.AutoInstrumentation.Logging; namespace OpenTelemetry.AutoInstrumentation.Configurations; @@ -18,7 +17,7 @@ internal class SdkSettings : Settings /// public IList Propagators { get; private set; } = new List(); - protected override void OnLoad(Configuration configuration) + protected override void OnLoadEnvVar(Configuration configuration) { Propagators = ParsePropagator(configuration); } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs index eece253424..83a21f9537 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,33 @@ 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_FILE_BASED_CONFIGURATION_ENABLED") == "true"; + + if (isConfigFileEnabled) + { + var configFile = Environment.GetEnvironmentVariable("OTEL_EXPERIMENTAL_CONFIG_FILE") ?? "config.yaml"; + var config = Parser.ParseYaml(configFile); + 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 +48,14 @@ 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 virtual void OnLoadFile(Conf configuration) + { + } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs index 69e21d9e07..78732e0da8 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/TracerSettings.cs @@ -53,7 +53,7 @@ internal class TracerSettings : Settings /// public OtlpSettings? OtlpSettings { get; private set; } - protected override void OnLoad(Configuration configuration) + protected override void OnLoadEnvVar(Configuration configuration) { TracesExporters = ParseTracesExporter(configuration); if (TracesExporters.Contains(TracesExporter.Otlp)) 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/HeadersCapture/HeaderConfigurationExtensions.cs b/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/HeaderConfigurationExtensions.cs index 38e90be5b3..ff7aea146f 100644 --- a/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/HeaderConfigurationExtensions.cs +++ b/src/OpenTelemetry.AutoInstrumentation/HeadersCapture/HeaderConfigurationExtensions.cs @@ -9,11 +9,11 @@ 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(); diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentation.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentation.cs index 2cbea65037..ba0df40c47 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/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; 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/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 new file mode 100644 index 0000000000..9f60dc4bd9 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs @@ -0,0 +1,154 @@ +// 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)); + } +} 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..f9b60d227a --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml @@ -0,0 +1,7 @@ +file_format: "0.4" + +resource: + attributes: + - name: service.name + value: unknown_service + attributes_list: 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..2566ca6c08 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml @@ -0,0 +1,7 @@ +file_format: "0.4" + +resource: + attributes: + - name: service.name + value: ${OTEL_SERVICE_NAME} + attributes_list: ${OTEL_RESOURCE_ATTRIBUTES} 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..538e3142b4 --- /dev/null +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs @@ -0,0 +1,47 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; +using Xunit; + +namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased; + +[Collection("Non-Parallel Collection")] +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.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); + } + + [Fact] + public void Parse_EnvVarYaml_ShouldPopulateModelCompletely() + { + Environment.SetEnvironmentVariable("OTEL_SDK_DISABLED", "true"); + Environment.SetEnvironmentVariable("OTEL_SERVICE_NAME", "my‑service"); + Environment.SetEnvironmentVariable("OTEL_RESOURCE_ATTRIBUTES", "key=value"); + + var config = Parser.ParseYaml("Configurations/FileBased/Files/TestFileEnvVars.yaml"); + + Assert.Equal("0.4", config.FileFormat); + var serviceAttr = config.Resource?.Attributes?.First(a => a.Name == "service.name"); + Assert.NotNull(serviceAttr); + Assert.Equal("my‑service", serviceAttr.Value); + } +} 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..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"; @@ -14,7 +15,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 +30,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/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 46b1e4b22c62439552f947d7e896e5bf410df5ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 11 Sep 2025 12:49:50 +0200 Subject: [PATCH 02/19] Update File Format to 1.0-rc.1 --- .../Configurations/FileBased/Files/TestFile.yaml | 2 +- .../Configurations/FileBased/Files/TestFileEnvVars.yaml | 2 +- .../Configurations/FileBased/ParserTests.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml index f9b60d227a..a6722a1859 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml @@ -1,4 +1,4 @@ -file_format: "0.4" +file_format: "1.0-rc.1" resource: attributes: diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml index 2566ca6c08..53b1031487 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml @@ -1,4 +1,4 @@ -file_format: "0.4" +file_format: "1.0-rc.1" resource: attributes: diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs index 538e3142b4..ddec15a763 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/ParserTests.cs @@ -16,7 +16,7 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly() Assert.NotNull(config); - Assert.Equal("0.4", config.FileFormat); + Assert.Equal("1.0-rc.1", config.FileFormat); Assert.NotNull(config.Resource); Assert.NotNull(config.Resource.Attributes); @@ -39,7 +39,7 @@ public void Parse_EnvVarYaml_ShouldPopulateModelCompletely() var config = Parser.ParseYaml("Configurations/FileBased/Files/TestFileEnvVars.yaml"); - Assert.Equal("0.4", config.FileFormat); + Assert.Equal("1.0-rc.1", config.FileFormat); var serviceAttr = config.Resource?.Attributes?.First(a => a.Name == "service.name"); Assert.NotNull(serviceAttr); Assert.Equal("my‑service", serviceAttr.Value); From e5fbafcdd22e883f31186d79ede2f8192848aa02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 11 Sep 2025 12:59:58 +0200 Subject: [PATCH 03/19] Extract file based config env vars --- .../Configurations/ConfigurationKeys.cs | 17 +++++++++++++++++ .../Configurations/Settings.cs | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs index 85e5f65e21..9c9c2acad2 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs @@ -61,6 +61,23 @@ internal partial class ConfigurationKeys /// public const string ServiceName = "OTEL_SERVICE_NAME"; + /// + /// Configuration keys for file based configuration. + /// + public static class FileBasedConfiguration + { + /// + /// Configuration key for enabling file based configuration. + /// + public const string Enabled = "OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED"; + + /// + /// Configuration key for enabling file based configuration. + /// Default is "config.yaml". + /// + public const string FileName = "OTEL_EXPERIMENTAL_CONFIG_FILE"; + } + /// /// Configuration keys for traces. /// diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs index 83a21f9537..5fc2bc7011 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs @@ -14,11 +14,11 @@ internal abstract class Settings public static T FromDefaultSources(bool failFast) where T : Settings, new() { - var isConfigFileEnabled = Environment.GetEnvironmentVariable("OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED") == "true"; + var isConfigFileEnabled = Environment.GetEnvironmentVariable(ConfigurationKeys.FileBasedConfiguration.Enabled) == "true"; if (isConfigFileEnabled) { - var configFile = Environment.GetEnvironmentVariable("OTEL_EXPERIMENTAL_CONFIG_FILE") ?? "config.yaml"; + var configFile = Environment.GetEnvironmentVariable(ConfigurationKeys.FileBasedConfiguration.FileName) ?? "config.yaml"; var config = Parser.ParseYaml(configFile); var settings = new T(); settings.LoadFile(config); From 3cf040939a3136a8e61552ef54043eeb64553788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 11 Sep 2025 13:05:41 +0200 Subject: [PATCH 04/19] remove redundant null check --- .../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 28bbeda6b3..21fd969985 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs @@ -64,7 +64,7 @@ protected override void OnLoadEnvVar(Configuration configuration) } var resourceAttributes = ParseResourceAttributes(configuration.GetString(ConfigurationKeys.ResourceAttributes)); - if (resourceAttributes != null && resourceAttributes.Count > 0) + if (resourceAttributes.Count > 0) { foreach (var attr in resourceAttributes) { From 4ae4d9bd4aedcad1b0fb9b7f3408aa6ad11da9aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 11 Sep 2025 13:24:09 +0200 Subject: [PATCH 05/19] bring back telemetrydistro resources to resource configurator --- .../Configurations/GeneralSettings.cs | 16 +--------------- .../Configurations/ResourceConfigurator.cs | 4 ++++ .../FileBased/FilebasedGeneralSettingsTests.cs | 3 --- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs index 21fd969985..085a23c560 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs @@ -50,11 +50,7 @@ protected override void OnLoadEnvVar(Configuration configuration) } } - var baseResources = new List> - { - new(Constants.DistributionAttributes.TelemetryDistroNameAttributeName, Constants.DistributionAttributes.TelemetryDistroNameAttributeValue), - new(Constants.DistributionAttributes.TelemetryDistroVersionAttributeName, AutoInstrumentationVersion.Version) - }; + var baseResources = new List>(1); var serviceName = configuration.GetString(ConfigurationKeys.ServiceName); @@ -93,21 +89,11 @@ protected override void OnLoadEnvVar(Configuration configuration) protected override void OnLoadFile(Conf configuration) { - 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) { diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs index 97cff12973..34072bf03a 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs @@ -14,6 +14,10 @@ public static ResourceBuilder CreateResourceBuilder(IReadOnlyList Date: Thu, 11 Sep 2025 13:24:36 +0200 Subject: [PATCH 06/19] remove redundant null check --- .../Configurations/GeneralSettings.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs index 085a23c560..633e9f80f3 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs @@ -103,14 +103,11 @@ protected override void OnLoadFile(Conf configuration) } } - if (resourceAttributes != null) + foreach (var kv in resourceAttributes) { - foreach (var kv in resourceAttributes) + if (!merged.ContainsKey(kv.Key)) { - if (!merged.ContainsKey(kv.Key)) - { - merged[kv.Key] = kv.Value; - } + merged[kv.Key] = kv.Value; } } From 6c13e3d4427ad6d34e474f707c56ce2e891380ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 11 Sep 2025 13:31:30 +0200 Subject: [PATCH 07/19] ignore resources when reading from env. vars. it is correctly handled by OTel SDK --- .../Configurations/GeneralSettings.cs | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs index 633e9f80f3..6b28a18627 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs @@ -50,31 +50,6 @@ protected override void OnLoadEnvVar(Configuration configuration) } } - var baseResources = new List>(1); - - 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.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( From 3d5c5732e1c90ed9ab269c2e7c2622146a85d442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Tue, 16 Sep 2025 10:49:47 +0200 Subject: [PATCH 08/19] TODO validate file and file version --- .../Configurations/Settings.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs index 5fc2bc7011..2bdc9a5e99 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs @@ -19,7 +19,12 @@ public static T FromDefaultSources(bool failFast) if (isConfigFileEnabled) { var configFile = Environment.GetEnvironmentVariable(ConfigurationKeys.FileBasedConfiguration.FileName) ?? "config.yaml"; + // TODO validate file existence + var config = Parser.ParseYaml(configFile); + + // TODO validate file format version https://github.com/open-telemetry/opentelemetry-configuration/blob/4f185c07eaaffc18c9ad34a46085e7ad6625fca0/README.md#file-format + var settings = new T(); settings.LoadFile(config); return settings; From 338f6277885584cf6d66c0d349ef9eac77d15716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Tue, 16 Sep 2025 11:30:01 +0200 Subject: [PATCH 09/19] Refactor resource settings to separate class + add EnvVarDetector switch --- .../FileBasedConfiguration/Parser/Parser.cs | 4 +- .../{Conf.cs => YamlConfiguration.cs} | 2 +- .../Configurations/GeneralSettings.cs | 71 --------------- .../Configurations/ResourceConfigurator.cs | 19 ++-- .../Configurations/ResourceSettings.cs | 90 +++++++++++++++++++ .../Configurations/Settings.cs | 8 +- .../Instrumentation.cs | 8 +- .../Logger/LoggerInitializer.cs | 2 +- .../FilebasedGeneralSettingsTests.cs | 28 +++--- .../ServiceNameConfiguratorTests.cs | 4 +- .../Configurations/SettingsTests.cs | 17 +++- 11 files changed, 144 insertions(+), 109 deletions(-) rename src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/{Conf.cs => YamlConfiguration.cs} (95%) create mode 100644 src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs index 7f10b0d13a..fbdaf8eb17 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/Parser.cs @@ -8,7 +8,7 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguratio internal static class Parser { - public static Conf ParseYaml(string filePath) + public static YamlConfiguration ParseYaml(string filePath) { var deserializer = new DeserializerBuilder() .WithNodeDeserializer(existing => new ConditionalDeserializer(existing), s => s.InsteadOf()) @@ -17,7 +17,7 @@ public static Conf ParseYaml(string filePath) .Build(); var yaml = File.ReadAllText(filePath); - var config = deserializer.Deserialize(yaml); + var config = deserializer.Deserialize(yaml); return config; } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs similarity index 95% rename from src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs rename to src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs index 996fdd2959..8e0fbf259e 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Conf.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs @@ -5,7 +5,7 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; -internal class Conf +internal class YamlConfiguration { /// /// Gets or sets the file format version. diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs index 6b28a18627..3f54323096 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs @@ -1,8 +1,6 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; - namespace OpenTelemetry.AutoInstrumentation.Configurations; internal class GeneralSettings : Settings @@ -12,16 +10,6 @@ internal class GeneralSettings : Settings /// public IList Plugins { get; } = new List(); - /// - /// Gets the list of enabled resource detectors. - /// - 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. @@ -50,68 +38,9 @@ protected override void OnLoadEnvVar(Configuration configuration) } } - var resourceDetectorsEnabledByDefault = configuration.GetBool(ConfigurationKeys.ResourceDetectorEnabled) ?? true; - - EnabledResourceDetectors = configuration.ParseEnabledEnumList( - enabledByDefault: resourceDetectorsEnabledByDefault, - enabledConfigurationTemplate: ConfigurationKeys.EnabledResourceDetectorTemplate); - FlushOnUnhandledException = configuration.GetBool(ConfigurationKeys.FlushOnUnhandledException) ?? false; SetupSdk = configuration.GetBool(ConfigurationKeys.SetupSdk) ?? true; ProfilerEnabled = configuration.GetString(ConfigurationKeys.ProfilingEnabled) == "1"; } - - protected override void OnLoadFile(Conf configuration) - { - var resourceAttributesWithPriority = configuration.Resource?.ParseAttributes() ?? []; - - var resourceAttributes = ParseResourceAttributes(configuration.Resource?.AttributesList); - - var merged = new Dictionary(); - - foreach (var kv in resourceAttributesWithPriority) - { - if (!merged.ContainsKey(kv.Key)) - { - merged[kv.Key] = kv.Value; - } - } - - foreach (var kv in resourceAttributes) - { - if (!merged.ContainsKey(kv.Key)) - { - merged[kv.Key] = kv.Value; - } - } - - Resources = merged.ToList(); - } - - 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 34072bf03a..76ca84f6b8 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs @@ -8,19 +8,24 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations; internal static class ResourceConfigurator { - public static ResourceBuilder CreateResourceBuilder(IReadOnlyList enabledResourceDetectors, IReadOnlyList> resources) + public static ResourceBuilder CreateResourceBuilder(ResourceSettings resourceSettings) { var resourceBuilder = ResourceBuilder - .CreateEmpty() // Don't use CreateDefault because it puts service name unknown by default. - .AddEnvironmentVariableDetector() - .AddTelemetrySdk() + .CreateEmpty(); // Don't use CreateDefault because it puts service name unknown by default. + + if (resourceSettings.EnabledEnvironmentalVariablesDetector) + { + resourceBuilder.AddEnvironmentVariableDetector(); + } + + resourceBuilder.AddTelemetrySdk() .AddAttributes([ new(Constants.DistributionAttributes.TelemetryDistroNameAttributeName, Constants.DistributionAttributes.TelemetryDistroNameAttributeValue), new(Constants.DistributionAttributes.TelemetryDistroVersionAttributeName, AutoInstrumentationVersion.Version) ]) - .AddAttributes(resources); + .AddAttributes(resourceSettings.Resources); - foreach (var enabledResourceDetector in enabledResourceDetectors) + foreach (var enabledResourceDetector in resourceSettings.EnabledDetectors) { resourceBuilder = enabledResourceDetector switch { @@ -37,7 +42,7 @@ public static ResourceBuilder CreateResourceBuilder(IReadOnlyList kvp.Key == Constants.ResourceAttributes.AttributeServiceName)) + if (resource.Attributes.All(kvp => kvp.Key != Constants.ResourceAttributes.AttributeServiceName)) { // service.name was not configured yet use the fallback. resourceBuilder.AddAttributes([new(Constants.ResourceAttributes.AttributeServiceName, ServiceNameConfigurator.GetFallbackServiceName())]); diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs new file mode 100644 index 0000000000..4f7530f88a --- /dev/null +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs @@ -0,0 +1,90 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration; + +namespace OpenTelemetry.AutoInstrumentation.Configurations; + +internal class ResourceSettings : Settings +{ + /// + /// Gets or sets the list of enabled resource detectors. + /// + public IReadOnlyList EnabledDetectors { get; set; } = []; + + /// + /// Gets or sets the list of enabled resources. + /// + public IReadOnlyList> Resources { get; set; } = []; + + /// + /// Gets or sets a value indicating whether environmental variables resource detector is enabled. + /// + public bool EnabledEnvironmentalVariablesDetector { get; set; } = true; + + protected override void OnLoadEnvVar(Configuration configuration) + { + var resourceDetectorsEnabledByDefault = configuration.GetBool(ConfigurationKeys.ResourceDetectorEnabled) ?? true; + + EnabledDetectors = configuration.ParseEnabledEnumList( + enabledByDefault: resourceDetectorsEnabledByDefault, + enabledConfigurationTemplate: ConfigurationKeys.EnabledResourceDetectorTemplate); + } + + protected override void OnLoadFile(YamlConfiguration configuration) + { + EnabledEnvironmentalVariablesDetector = false; + + var resourceAttributesWithPriority = configuration.Resource?.ParseAttributes() ?? []; + + var additionalResources = ParseResourceAttributes(configuration.Resource?.AttributesList); + + var merged = new Dictionary(); + + foreach (var kv in resourceAttributesWithPriority) + { + if (!merged.ContainsKey(kv.Key)) + { + merged[kv.Key] = kv.Value; + } + } + + foreach (var kv in additionalResources) + { + if (!merged.ContainsKey(kv.Key)) + { + merged[kv.Key] = kv.Value; + } + } + + Resources = merged.ToList(); + + // TODO initialize EnabledDetectors from file configuration + } + + 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/Settings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs index 2bdc9a5e99..60e20ca5e6 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs @@ -43,7 +43,7 @@ public void LoadEnvVar(Configuration configuration) OnLoadEnvVar(configuration); } - public void LoadFile(Conf configuration) + public void LoadFile(YamlConfiguration configuration) { OnLoadFile(configuration); } @@ -57,10 +57,10 @@ public void LoadFile(Conf configuration) /// /// Initializes a new instance of the class - /// using the specified to initialize values. + /// using the specified to initialize values. /// - /// The to use when retrieving configuration values. - protected virtual void OnLoadFile(Conf configuration) + /// The to use when retrieving configuration values. + protected virtual void OnLoadFile(YamlConfiguration configuration) { } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentation.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentation.cs index ba0df40c47..5177a6d691 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentation.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentation.cs @@ -56,6 +56,8 @@ internal static LoggerProvider? LoggerProvider internal static Lazy GeneralSettings { get; } = new(() => Settings.FromDefaultSources(FailFastSettings.Value.FailFast)); + internal static Lazy ResourceSettings { get; } = new(() => Settings.FromDefaultSources(FailFastSettings.Value.FailFast)); + internal static Lazy TracerSettings { get; } = new(() => Settings.FromDefaultSources(FailFastSettings.Value.FailFast)); internal static Lazy MetricSettings { get; } = new(() => Settings.FromDefaultSources(FailFastSettings.Value.FailFast)); @@ -134,7 +136,7 @@ public static void Initialize() var builder = Sdk .CreateTracerProviderBuilder() .InvokePluginsBefore(_pluginManager) - .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(GeneralSettings.Value.EnabledResourceDetectors, GeneralSettings.Value.Resources)) + .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(ResourceSettings.Value)) .UseEnvironmentVariables(LazyInstrumentationLoader, TracerSettings.Value, _pluginManager) .InvokePluginsAfter(_pluginManager); @@ -156,7 +158,7 @@ public static void Initialize() var builder = Sdk .CreateMeterProviderBuilder() .InvokePluginsBefore(_pluginManager) - .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(GeneralSettings.Value.EnabledResourceDetectors, GeneralSettings.Value.Resources)) + .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(ResourceSettings.Value)) .UseEnvironmentVariables(LazyInstrumentationLoader, MetricSettings.Value, _pluginManager) .InvokePluginsAfter(_pluginManager); @@ -355,7 +357,7 @@ private static void InitializeBufferProcessing(TimeSpan exportInterval, TimeSpan // TODO: plugins support var loggerProvider = loggerProviderBuilder! - .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(GeneralSettings.Value.EnabledResourceDetectors, GeneralSettings.Value.Resources)) + .SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(ResourceSettings.Value)) .UseEnvironmentVariables(LazyInstrumentationLoader, LogSettings.Value, _pluginManager!) .Build(); Logger.Information("OpenTelemetry logger provider initialized."); diff --git a/src/OpenTelemetry.AutoInstrumentation/Logger/LoggerInitializer.cs b/src/OpenTelemetry.AutoInstrumentation/Logger/LoggerInitializer.cs index 17fc623f22..e358ff2b16 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, Instrumentation.GeneralSettings.Value.Resources)); + options.SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(Instrumentation.ResourceSettings.Value)); options.IncludeFormattedMessage = settings.IncludeFormattedMessage; diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs index 2e8b3a29cd..0c15d88a1f 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs @@ -22,8 +22,8 @@ public void LoadFile_MergesBaseAndCustomResourceAttributes() ] }; - var conf = new Conf { Resource = resource }; - var settings = new GeneralSettings(); + var conf = new YamlConfiguration { Resource = resource }; + var settings = new ResourceSettings(); settings.LoadFile(conf); @@ -42,8 +42,8 @@ public void LoadFile_AttributesListOnly_IsParsedCorrectly() AttributesList = "key1=value1,key2=value2" }; - var conf = new Conf { Resource = resource }; - var settings = new GeneralSettings(); + var conf = new YamlConfiguration { Resource = resource }; + var settings = new ResourceSettings(); settings.LoadFile(conf); @@ -65,8 +65,8 @@ public void LoadFile_AttributesOnly_IsParsedCorrectly() ] }; - var conf = new Conf { Resource = resource }; - var settings = new GeneralSettings(); + var conf = new YamlConfiguration { Resource = resource }; + var settings = new ResourceSettings(); settings.LoadFile(conf); @@ -79,8 +79,8 @@ public void LoadFile_AttributesOnly_IsParsedCorrectly() [Fact] public void LoadFile_BaseAttributes_AreAlwaysIncluded() { - var settings = new GeneralSettings(); - settings.LoadFile(new Conf()); + var settings = new ResourceSettings(); + settings.LoadFile(new YamlConfiguration()); var result = settings.Resources.ToDictionary(kv => kv.Key, kv => kv.Value); @@ -100,8 +100,8 @@ public void LoadFile_AttributesListOverwrittenByAttributes() ] }; - var conf = new Conf { Resource = resource }; - var settings = new GeneralSettings(); + var conf = new YamlConfiguration { Resource = resource }; + var settings = new ResourceSettings(); settings.LoadFile(conf); @@ -119,8 +119,8 @@ public void LoadFile_NullAttributesHandledGracefully() Attributes = null }; - var conf = new Conf { Resource = resource }; - var settings = new GeneralSettings(); + var conf = new YamlConfiguration { Resource = resource }; + var settings = new ResourceSettings(); settings.LoadFile(conf); @@ -138,8 +138,8 @@ public void LoadFile_EmptyAttributesList_StillIncludesBaseAttributes() AttributesList = string.Empty }; - var conf = new Conf { Resource = resource }; - var settings = new GeneralSettings(); + var conf = new YamlConfiguration { Resource = resource }; + var settings = new ResourceSettings(); settings.LoadFile(conf); diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ServiceNameConfiguratorTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ServiceNameConfiguratorTests.cs index da07b98ed3..510ff3713f 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ServiceNameConfiguratorTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/ServiceNameConfiguratorTests.cs @@ -15,7 +15,7 @@ public class ServiceNameConfiguratorTests [Fact] public void GetFallbackServiceName() { - var resourceBuilder = ResourceConfigurator.CreateResourceBuilder(new List(), []); + var resourceBuilder = ResourceConfigurator.CreateResourceBuilder(new ResourceSettings()); var resource = resourceBuilder.Build(); var serviceName = resource.Attributes.FirstOrDefault(a => a.Key == ServiceName).Value as string; @@ -30,7 +30,7 @@ public void ServiceName_Retained_EnvVarSet() { Environment.SetEnvironmentVariable(OtelServiceVariable, setServiceName); - var resourceBuilder = ResourceConfigurator.CreateResourceBuilder(Array.Empty(), []); + var resourceBuilder = ResourceConfigurator.CreateResourceBuilder(new ResourceSettings()); 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 5a6d530e09..0b8e3efbb1 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs @@ -31,10 +31,19 @@ internal void GeneralSettings_DefaultValues() var settings = Settings.FromDefaultSources(false); Assert.Empty(settings.Plugins); - Assert.NotEmpty(settings.EnabledResourceDetectors); Assert.False(settings.FlushOnUnhandledException); } + [Fact] + internal void ResourceSettings_DefaultValues() + { + var settings = Settings.FromDefaultSources(false); + + Assert.NotEmpty(settings.EnabledDetectors); + Assert.True(settings.EnabledEnvironmentalVariablesDetector); + Assert.Empty(settings.Resources); + } + [Fact] internal void TracerSettings_DefaultValues() { @@ -401,14 +410,14 @@ internal void FlushOnUnhandledException_DependsOnCorrespondingEnvVariable(string [InlineData("PROCESS", ResourceDetector.Process)] [InlineData("OPERATINGSYSTEM", ResourceDetector.OperatingSystem)] [InlineData("HOST", ResourceDetector.Host)] - internal void GeneralSettings_Instrumentations_SupportedValues(string resourceDetector, ResourceDetector expectedResourceDetector) + internal void ResourceSettings_ResourceDetectors_SupportedValues(string resourceDetector, ResourceDetector expectedResourceDetector) { Environment.SetEnvironmentVariable(ConfigurationKeys.ResourceDetectorEnabled, "false"); Environment.SetEnvironmentVariable(string.Format(ConfigurationKeys.EnabledResourceDetectorTemplate, resourceDetector), "true"); - var settings = Settings.FromDefaultSources(false); + var settings = Settings.FromDefaultSources(false); - Assert.Equal([expectedResourceDetector], settings.EnabledResourceDetectors); + Assert.Equal([expectedResourceDetector], settings.EnabledDetectors); } private static void ClearEnvVars() From 91d64bbecba47be6ae6534d5ea37905e2a7def39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Tue, 16 Sep 2025 11:47:06 +0200 Subject: [PATCH 10/19] TODO for the types --- .../FileBasedConfiguration/ResourceConfiguration.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs index 149a380273..3429724fb0 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs @@ -29,6 +29,8 @@ public List> ParseAttributes() foreach (var attr in Attributes) { + // TODO parse type and converting the value accordingly. + result.Add(new KeyValuePair(attr.Name, attr.Value)); } From ec1d51cfbf15fcaee6dbb1960f6f435ae8f38437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Tue, 16 Sep 2025 12:51:53 +0200 Subject: [PATCH 11/19] Cache yaml configuration to avoid multiple time parsing --- .../Configurations/Settings.cs | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs index 60e20ca5e6..16991d34cd 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/Settings.cs @@ -11,22 +11,16 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations; /// internal abstract class Settings { + private static readonly bool IsYamlConfigEnabled = Environment.GetEnvironmentVariable(ConfigurationKeys.FileBasedConfiguration.Enabled) == "true"; + private static readonly Lazy YamlConfiguration = new(ReadYamlConfiguration); + public static T FromDefaultSources(bool failFast) where T : Settings, new() { - var isConfigFileEnabled = Environment.GetEnvironmentVariable(ConfigurationKeys.FileBasedConfiguration.Enabled) == "true"; - - if (isConfigFileEnabled) + if (IsYamlConfigEnabled) { - var configFile = Environment.GetEnvironmentVariable(ConfigurationKeys.FileBasedConfiguration.FileName) ?? "config.yaml"; - // TODO validate file existence - - var config = Parser.ParseYaml(configFile); - - // TODO validate file format version https://github.com/open-telemetry/opentelemetry-configuration/blob/4f185c07eaaffc18c9ad34a46085e7ad6625fca0/README.md#file-format - var settings = new T(); - settings.LoadFile(config); + settings.LoadFile(YamlConfiguration.Value); return settings; } else @@ -63,4 +57,15 @@ public void LoadFile(YamlConfiguration configuration) protected virtual void OnLoadFile(YamlConfiguration configuration) { } + + private static YamlConfiguration ReadYamlConfiguration() + { + var configFile = Environment.GetEnvironmentVariable(ConfigurationKeys.FileBasedConfiguration.FileName) ?? "config.yaml"; + // TODO validate file existence + + var config = Parser.ParseYaml(configFile); + + // TODO validate file format version https://github.com/open-telemetry/opentelemetry-configuration/blob/4f185c07eaaffc18c9ad34a46085e7ad6625fca0/README.md#file-format + return config; + } } From 0c9ca472eee2e7fb7b76ec9718370c8b211fba1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Tue, 16 Sep 2025 13:25:05 +0200 Subject: [PATCH 12/19] remove wrong tests detection of these attributes was moved to resourceconfigurator --- .../FilebasedGeneralSettingsTests.cs | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs index 0c15d88a1f..52ab2d51be 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs @@ -76,18 +76,6 @@ public void LoadFile_AttributesOnly_IsParsedCorrectly() Assert.Equal("2", result["b"]); } - [Fact] - public void LoadFile_BaseAttributes_AreAlwaysIncluded() - { - var settings = new ResourceSettings(); - settings.LoadFile(new YamlConfiguration()); - - 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() { @@ -109,43 +97,4 @@ public void LoadFile_AttributesListOverwrittenByAttributes() Assert.Equal("fromAttributes", result["key1"]); } - - [Fact] - public void LoadFile_NullAttributesHandledGracefully() - { - var resource = new ResourceConfiguration - { - AttributesList = null, - Attributes = null - }; - - var conf = new YamlConfiguration { Resource = resource }; - var settings = new ResourceSettings(); - - 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 YamlConfiguration { Resource = resource }; - var settings = new ResourceSettings(); - - 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)); - } } From 3fda793fea8966ec07f366c648bfa63b29674da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Wed, 17 Sep 2025 07:03:19 +0200 Subject: [PATCH 13/19] const chars --- .../Configurations/ResourceSettings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs index 4f7530f88a..0b29790735 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs @@ -69,8 +69,8 @@ private static List> ParseResourceAttributes(string return []; } - var attributeListSplitter = ','; - var attributeKeyValueSplitter = '='; + const char attributeListSplitter = ','; + const char attributeKeyValueSplitter = '='; var attributes = new List>(); var rawAttributes = resourceAttributes!.Split(attributeListSplitter); From f75734a974231052a72388f446709aca6137b87d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Wed, 17 Sep 2025 07:03:34 +0200 Subject: [PATCH 14/19] drop redundant using --- .../FileBasedConfiguration/Parser/ConditionalDeserializer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/ConditionalDeserializer.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/ConditionalDeserializer.cs index a69463520a..89426149fe 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/ConditionalDeserializer.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/ConditionalDeserializer.cs @@ -1,7 +1,6 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using System.Reflection; using Vendors.YamlDotNet.Core; using Vendors.YamlDotNet.Core.Events; using Vendors.YamlDotNet.Serialization; From 70abe4eafce2739ce6e91bcf7b2d0081d290e24e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Wed, 17 Sep 2025 07:03:44 +0200 Subject: [PATCH 15/19] drop empty body --- .../Parser/EmptyObjectOnEmptyYamlAttribute.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EmptyObjectOnEmptyYamlAttribute.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EmptyObjectOnEmptyYamlAttribute.cs index 9863a486b3..22c7e91aed 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EmptyObjectOnEmptyYamlAttribute.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/Parser/EmptyObjectOnEmptyYamlAttribute.cs @@ -4,6 +4,4 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser; [AttributeUsage(AttributeTargets.Class)] -internal sealed class EmptyObjectOnEmptyYamlAttribute : Attribute -{ -} +internal sealed class EmptyObjectOnEmptyYamlAttribute : Attribute; From 5aff60873d5218b88936d66a17f010853516a115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Wed, 17 Sep 2025 07:33:08 +0200 Subject: [PATCH 16/19] PR feedback - refactor parse attributes --- .../ResourceConfiguration.cs | 40 ++++++++++++--- .../Configurations/ResourceSettings.cs | 50 +------------------ 2 files changed, 33 insertions(+), 57 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs index 3429724fb0..7611042e8f 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs @@ -21,19 +21,43 @@ internal class ResourceConfiguration public List> ParseAttributes() { - var result = new List>(); - if (Attributes == null) + var resourceAttributesWithPriority = new Dictionary(); + + if (Attributes != null) { - return result; + foreach (var attr in Attributes) + { + if (!resourceAttributesWithPriority.ContainsKey(attr.Name)) + { + // TODO parse type and converting the value accordingly. + resourceAttributesWithPriority.Add(attr.Name, attr.Value); + } + } } - foreach (var attr in Attributes) + if (AttributesList != null) { - // TODO parse type and converting the value accordingly. - - result.Add(new KeyValuePair(attr.Name, attr.Value)); + const char attributeListSplitter = ','; + const char attributeKeyValueSplitter = '='; + + var rawAttributes = AttributesList.Split(attributeListSplitter); + foreach (var rawKeyValuePair in rawAttributes) + { + var keyValuePair = rawKeyValuePair.Split(attributeKeyValueSplitter); + if (keyValuePair.Length != 2) + { + continue; + } + + var key = keyValuePair[0].Trim(); + + if (!resourceAttributesWithPriority.ContainsKey(key)) + { + resourceAttributesWithPriority.Add(key, keyValuePair[1].Trim()); + } + } } - return result; + return resourceAttributesWithPriority.ToList(); } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs index 0b29790735..8980880a2f 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs @@ -35,56 +35,8 @@ protected override void OnLoadFile(YamlConfiguration configuration) { EnabledEnvironmentalVariablesDetector = false; - var resourceAttributesWithPriority = configuration.Resource?.ParseAttributes() ?? []; - - var additionalResources = ParseResourceAttributes(configuration.Resource?.AttributesList); - - var merged = new Dictionary(); - - foreach (var kv in resourceAttributesWithPriority) - { - if (!merged.ContainsKey(kv.Key)) - { - merged[kv.Key] = kv.Value; - } - } - - foreach (var kv in additionalResources) - { - if (!merged.ContainsKey(kv.Key)) - { - merged[kv.Key] = kv.Value; - } - } - - Resources = merged.ToList(); + Resources = configuration.Resource?.ParseAttributes() ?? []; // TODO initialize EnabledDetectors from file configuration } - - private static List> ParseResourceAttributes(string? resourceAttributes) - { - if (string.IsNullOrEmpty(resourceAttributes)) - { - return []; - } - - const char attributeListSplitter = ','; - const char 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; - } } From 8138c241559dfbff7023d95d18f8a6623071d629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Wed, 17 Sep 2025 07:37:04 +0200 Subject: [PATCH 17/19] Rename EnabledEnvironmentalVariablesDetector to EnvironmentalVariablesDetectorEnabled --- .../Configurations/ResourceConfigurator.cs | 2 +- .../Configurations/ResourceSettings.cs | 4 ++-- .../Configurations/SettingsTests.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs index 76ca84f6b8..381b1aaf54 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs @@ -13,7 +13,7 @@ public static ResourceBuilder CreateResourceBuilder(ResourceSettings resourceSet var resourceBuilder = ResourceBuilder .CreateEmpty(); // Don't use CreateDefault because it puts service name unknown by default. - if (resourceSettings.EnabledEnvironmentalVariablesDetector) + if (resourceSettings.EnvironmentalVariablesDetectorEnabled) { resourceBuilder.AddEnvironmentVariableDetector(); } diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs index 8980880a2f..1554a16757 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs @@ -20,7 +20,7 @@ internal class ResourceSettings : Settings /// /// Gets or sets a value indicating whether environmental variables resource detector is enabled. /// - public bool EnabledEnvironmentalVariablesDetector { get; set; } = true; + public bool EnvironmentalVariablesDetectorEnabled { get; set; } = true; protected override void OnLoadEnvVar(Configuration configuration) { @@ -33,7 +33,7 @@ protected override void OnLoadEnvVar(Configuration configuration) protected override void OnLoadFile(YamlConfiguration configuration) { - EnabledEnvironmentalVariablesDetector = false; + EnvironmentalVariablesDetectorEnabled = false; Resources = configuration.Resource?.ParseAttributes() ?? []; diff --git a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs index 0b8e3efbb1..d7b6845017 100644 --- a/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs +++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/SettingsTests.cs @@ -40,7 +40,7 @@ internal void ResourceSettings_DefaultValues() var settings = Settings.FromDefaultSources(false); Assert.NotEmpty(settings.EnabledDetectors); - Assert.True(settings.EnabledEnvironmentalVariablesDetector); + Assert.True(settings.EnvironmentalVariablesDetectorEnabled); Assert.Empty(settings.Resources); } From 2cefa3f1f1ede47c12674b4e1c1807d5a46c97cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Wed, 17 Sep 2025 13:12:02 +0200 Subject: [PATCH 18/19] PR feedback, split only by first equal sign --- .../FileBasedConfiguration/ResourceConfiguration.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs index 7611042e8f..886c906ced 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs @@ -38,12 +38,12 @@ public List> ParseAttributes() if (AttributesList != null) { const char attributeListSplitter = ','; - const char attributeKeyValueSplitter = '='; + char[] attributeKeyValueSplitter = ['=']; var rawAttributes = AttributesList.Split(attributeListSplitter); foreach (var rawKeyValuePair in rawAttributes) { - var keyValuePair = rawKeyValuePair.Split(attributeKeyValueSplitter); + var keyValuePair = rawKeyValuePair.Split(attributeKeyValueSplitter, 2); if (keyValuePair.Length != 2) { continue; From 680314a76a40291e308894ceb300c994790161fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Kie=C5=82kowicz?= Date: Thu, 18 Sep 2025 09:46:59 +0200 Subject: [PATCH 19/19] fix docs comment Co-authored-by: Yevhenii Solomchenko --- .../Configurations/ConfigurationKeys.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs index 9c9c2acad2..e04744ecdf 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs @@ -72,7 +72,7 @@ public static class FileBasedConfiguration public const string Enabled = "OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED"; /// - /// Configuration key for enabling file based configuration. + /// Configuration key for the path to the configuration file. /// Default is "config.yaml". /// public const string FileName = "OTEL_EXPERIMENTAL_CONFIG_FILE";