diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs
index d1ca2b0b6b..e04744ecdf 100644
--- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs
+++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ConfigurationKeys.cs
@@ -51,6 +51,33 @@ 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 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 the path to the configuration file.
+ /// Default is "config.yaml".
+ ///
+ public const string FileName = "OTEL_EXPERIMENTAL_CONFIG_FILE";
+ }
+
///
/// 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/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;
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;
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..fbdaf8eb17
--- /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 YamlConfiguration 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..886c906ced
--- /dev/null
+++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/ResourceConfiguration.cs
@@ -0,0 +1,63 @@
+// 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 resourceAttributesWithPriority = new Dictionary();
+
+ if (Attributes != null)
+ {
+ foreach (var attr in Attributes)
+ {
+ if (!resourceAttributesWithPriority.ContainsKey(attr.Name))
+ {
+ // TODO parse type and converting the value accordingly.
+ resourceAttributesWithPriority.Add(attr.Name, attr.Value);
+ }
+ }
+ }
+
+ if (AttributesList != null)
+ {
+ const char attributeListSplitter = ',';
+ char[] attributeKeyValueSplitter = ['='];
+
+ var rawAttributes = AttributesList.Split(attributeListSplitter);
+ foreach (var rawKeyValuePair in rawAttributes)
+ {
+ var keyValuePair = rawKeyValuePair.Split(attributeKeyValueSplitter, 2);
+ if (keyValuePair.Length != 2)
+ {
+ continue;
+ }
+
+ var key = keyValuePair[0].Trim();
+
+ if (!resourceAttributesWithPriority.ContainsKey(key))
+ {
+ resourceAttributesWithPriority.Add(key, keyValuePair[1].Trim());
+ }
+ }
+ }
+
+ return resourceAttributesWithPriority.ToList();
+ }
+}
diff --git a/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.cs
new file mode 100644
index 0000000000..8e0fbf259e
--- /dev/null
+++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/FileBasedConfiguration/YamlConfiguration.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 YamlConfiguration
+{
+ ///
+ /// 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/GeneralSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs
index 732af52102..3f54323096 100644
--- a/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs
+++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/GeneralSettings.cs
@@ -10,11 +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 a value indicating whether the event should trigger
/// the flushing of telemetry data.
@@ -32,7 +27,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,12 +38,6 @@ protected override void OnLoad(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;
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..381b1aaf54 100644
--- a/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs
+++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceConfigurator.cs
@@ -8,21 +8,24 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations;
internal static class ResourceConfigurator
{
- internal const string ServiceNameAttribute = "service.name";
-
- public static ResourceBuilder CreateResourceBuilder(IReadOnlyList enabledResourceDetectors)
+ public static ResourceBuilder CreateResourceBuilder(ResourceSettings resourceSettings)
{
var resourceBuilder = ResourceBuilder
- .CreateEmpty() // Don't use CreateDefault because it puts service name unknown by default.
- .AddEnvironmentVariableDetector()
- .AddTelemetrySdk()
- .AddAttributes(new KeyValuePair[]
- {
+ .CreateEmpty(); // Don't use CreateDefault because it puts service name unknown by default.
+
+ if (resourceSettings.EnvironmentalVariablesDetectorEnabled)
+ {
+ resourceBuilder.AddEnvironmentVariableDetector();
+ }
+
+ resourceBuilder.AddTelemetrySdk()
+ .AddAttributes([
new(Constants.DistributionAttributes.TelemetryDistroNameAttributeName, Constants.DistributionAttributes.TelemetryDistroNameAttributeValue),
new(Constants.DistributionAttributes.TelemetryDistroVersionAttributeName, AutoInstrumentationVersion.Version)
- });
+ ])
+ .AddAttributes(resourceSettings.Resources);
- foreach (var enabledResourceDetector in enabledResourceDetectors)
+ foreach (var enabledResourceDetector in resourceSettings.EnabledDetectors)
{
resourceBuilder = enabledResourceDetector switch
{
@@ -39,10 +42,10 @@ public static ResourceBuilder CreateResourceBuilder(IReadOnlyList kvp.Key == ServiceNameAttribute))
+ if (resource.Attributes.All(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/ResourceSettings.cs b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs
new file mode 100644
index 0000000000..1554a16757
--- /dev/null
+++ b/src/OpenTelemetry.AutoInstrumentation/Configurations/ResourceSettings.cs
@@ -0,0 +1,42 @@
+// 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 EnvironmentalVariablesDetectorEnabled { 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)
+ {
+ EnvironmentalVariablesDetectorEnabled = false;
+
+ Resources = configuration.Resource?.ParseAttributes() ?? [];
+
+ // TODO initialize EnabledDetectors from file configuration
+ }
+}
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..16991d34cd 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;
///
@@ -8,18 +11,35 @@ 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 configuration = new Configuration(failFast, new EnvironmentConfigurationSource(failFast));
- var settings = new T();
- settings.Load(configuration);
- return settings;
+ if (IsYamlConfigEnabled)
+ {
+ var settings = new T();
+ settings.LoadFile(YamlConfiguration.Value);
+ 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(YamlConfiguration configuration)
{
- OnLoad(configuration);
+ OnLoadFile(configuration);
}
///
@@ -27,5 +47,25 @@ 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(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;
+ }
}
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..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))
+ .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))
+ .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))
+ .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 57a5020e28..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));
+ options.SetResourceBuilder(ResourceConfigurator.CreateResourceBuilder(Instrumentation.ResourceSettings.Value));
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..52ab2d51be
--- /dev/null
+++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/FilebasedGeneralSettingsTests.cs
@@ -0,0 +1,100 @@
+// 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 YamlConfiguration { Resource = resource };
+ var settings = new ResourceSettings();
+
+ 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"]);
+ }
+
+ [Fact]
+ public void LoadFile_AttributesListOnly_IsParsedCorrectly()
+ {
+ var resource = new ResourceConfiguration
+ {
+ AttributesList = "key1=value1,key2=value2"
+ };
+
+ 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.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 YamlConfiguration { Resource = resource };
+ var settings = new ResourceSettings();
+
+ 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_AttributesListOverwrittenByAttributes()
+ {
+ var resource = new ResourceConfiguration
+ {
+ AttributesList = "key1=fromList",
+ Attributes =
+ [
+ new() { Name = "key1", Value = "fromAttributes" }
+ ]
+ };
+
+ 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.Equal("fromAttributes", result["key1"]);
+ }
+}
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..a6722a1859
--- /dev/null
+++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFile.yaml
@@ -0,0 +1,7 @@
+file_format: "1.0-rc.1"
+
+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..53b1031487
--- /dev/null
+++ b/test/OpenTelemetry.AutoInstrumentation.Tests/Configurations/FileBased/Files/TestFileEnvVars.yaml
@@ -0,0 +1,7 @@
+file_format: "1.0-rc.1"
+
+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..ddec15a763
--- /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("1.0-rc.1", 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("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);
+ }
+}
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..510ff3713f 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 ResourceSettings());
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(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..d7b6845017 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.EnvironmentalVariablesDetectorEnabled);
+ 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()
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
+
+
+