Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,37 @@ with environment variables taking precedence over `App.config` or `Web.config` f
`SiteName\VirtualPath` ex: `MySite\MyApp`
- If that is not the case it will use the name of the application [entry Assembly](https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.getentryassembly?view=net-7.0).

4. File-based Configuration (Experimental)

> **Status:** [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md)
> For more information about the OpenTelemetry configuration specification, see:
> **[File-based configuration documentation](https://opentelemetry.io/docs/specs/otel/configuration/sdk/)**

You can configure OpenTelemetry using a YAML file. This method is disabled
by default and must be explicitly enabled.

To enable file-based configuration, set the following environment variable:

```bash
OTEL_EXPERIMENTAL_FILE_BASED_CONFIGURATION_ENABLED=true
```

By default, the value is false.

You can also specify the configuration file path (default: config.yaml):

```bash
OTEL_EXPERIMENTAL_CONFIG_FILE=/path/to/config.yaml
```

In your config file you can use environment variables in the format `${ENVIRONMENT_VARIABLE}`
instead of a fixed value.

You can also use `${ENVIRONMENT_VARIABLE:-value}`, where `value` is the fallback if the
environment variable is empty or not set.

See [configuration examples](#configuration-examples)

By default we recommend using environment variables for configuration.
However, if given setting supports it, then:

Expand Down Expand Up @@ -503,3 +534,40 @@ instead.
|----------------------------------|-------------------------------------------------------------------------|------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `OTEL_DOTNET_AUTO_LOG_DIRECTORY` | Directory of the .NET Tracer logs. | *See the previous note on default paths* | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `OTEL_LOG_LEVEL` | SDK log level. (supported values: `none`,`error`,`warn`,`info`,`debug`) | `info` | [Stable](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |

## Configuration Examples

### Resource Configuration

You can configure resource attributes directly in YAML or via the
`OTEL_RESOURCE_ATTRIBUTES` environment variable.

``` yaml
resource:
# Configure resource attributes. Entries have higher priority than entries from .resource.attributes_list.
# Entries must contain .name and .value, and may optionally include .type. If an entry's .type omitted or null, string is used.
# The .value's type must match the .type. Values for .type include: string, bool, int, double, string_array, bool_array, int_array, double_array.
attributes:
- name: service.name
value: unknown_service
type: string
# Alternatively, configure via a comma-separated list (same format as OTEL_RESOURCE_ATTRIBUTES).
attributes_list: ${OTEL_RESOURCE_ATTRIBUTES}
```

### Resource Detectors Configuration

For more details and updates, see: [Resource Detectors list and documentation](https://opentelemetry.io/docs/zero-code/dotnet/configuration/#resource-detectors)

``` yaml
resource:
detection/development:
detectors:
azureappservice: # Detects Azure App Service resource information
container: # Detects container resource info (container.* attributes) [Core only]
host: # Detects host resource info (host.* attributes)
operatingsystem: # Detects OS-level attributes (os.*)
process: # Detects process-level attributes (process.*)
processruntime: # Detects process runtime attributes (process.runtime.*)
service: # Detects service.name and service.instance.id
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using Vendors.YamlDotNet.Serialization;

namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration;

internal class DetectionDevelopment
{
/// <summary>
/// Gets or sets the configuration for resource detectors.
/// If omitted or null, no resource detectors are enabled.
/// </summary>
[YamlMember(Alias = "detectors")]
public DotNetDetectors? Detectors { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using System.Reflection;
using Vendors.YamlDotNet.Serialization;

namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration;

internal class DotNetDetectors
{
/// <summary>
/// Gets or sets the Azure App Service detector configuration.
/// </summary>
[YamlMember(Alias = "azureappservice")]
public object? AzureAppService { get; set; }

#if NET
/// <summary>
/// Gets or sets the container detector configuration.
/// </summary>
[YamlMember(Alias = "container")]
public object? Container { get; set; }
#endif

/// <summary>
/// Gets or sets the host detector configuration.
/// </summary>
[YamlMember(Alias = "host")]
public object? Host { get; set; }

/// <summary>
/// Gets or sets the operating system detector configuration.
/// </summary>
[YamlMember(Alias = "operatingsystem")]
public object? OperatingSystem { get; set; }

/// <summary>
/// Gets or sets the process detector configuration.
/// </summary>
[YamlMember(Alias = "process")]
public object? Process { get; set; }

/// <summary>
/// Gets or sets the process runtime detector configuration.
/// </summary>
[YamlMember(Alias = "processruntime")]
public object? ProcessRuntime { get; set; }

/// <summary>
/// Returns the list of enabled resource detectors.
/// </summary>
public IReadOnlyList<ResourceDetector> GetEnabledResourceDetectors()
{
var enabled = new List<ResourceDetector>();
var properties = typeof(DotNetDetectors).GetProperties(BindingFlags.Instance | BindingFlags.Public);

foreach (var prop in properties)
{
var value = prop.GetValue(this);
if (value != null)
{
if (Enum.TryParse<ResourceDetector>(prop.Name, out var resourceDetector))
{
enabled.Add(resourceDetector);
}
}
}

return enabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ internal class ResourceConfiguration
[YamlMember(Alias = "attributes_list")]
public string? AttributesList { get; set; }

/// <summary>
/// Gets or sets the detection development configuration.
/// </summary>
[YamlMember(Alias = "detection/development")]
public DetectionDevelopment? DetectionDevelopment { get; set; }

public List<KeyValuePair<string, object>> ParseAttributes()
{
var resourceAttributesWithPriority = new Dictionary<string, object>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@ protected override void OnLoadFile(YamlConfiguration configuration)

Resources = configuration.Resource?.ParseAttributes() ?? [];

// TODO initialize EnabledDetectors from file configuration
EnabledDetectors = configuration.Resource?.DetectionDevelopment?.Detectors?.GetEnabledResourceDetectors() ?? [];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using System.Reflection;
using Vendors.YamlDotNet.Core;
using Vendors.YamlDotNet.Serialization;
using Xunit;

namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased;

internal static class FileBasedTestHelper
{
public static void MoveParserToScalar(IParser parser)
{
parser.MoveNext(); // StreamStart
parser.MoveNext(); // DocumentStart
parser.MoveNext(); // Scalar
}

public static void AssertAliasPropertyExists<T>(T obj, string alias)
{
Assert.NotNull(obj);

var prop = typeof(T).GetProperties()
.FirstOrDefault(p => p.GetCustomAttribute<YamlMemberAttribute>()?.Alias == alias);

Assert.NotNull(prop);

var value = prop.GetValue(obj);
Assert.NotNull(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased;

public class FilebasedGeneralSettingsTests
public class FilebasedResourceSettingsTests
{
[Fact]
public void LoadFile_MergesBaseAndCustomResourceAttributes()
Expand Down Expand Up @@ -97,4 +97,40 @@ public void LoadFile_AttributesListOverwrittenByAttributes()

Assert.Equal("fromAttributes", result["key1"]);
}

[Fact]
public void GetEnabledResourceDetector_ReturnsCorrectEnabledDetectors()
{
var detectors = new DotNetDetectors
{
AzureAppService = new object(),
Host = new object(),
OperatingSystem = null,
Process = new object(),
ProcessRuntime = null
};

#if NET
detectors.Container = new object();
#endif

var result = detectors.GetEnabledResourceDetectors();

var expected = new List<ResourceDetector>
{
ResourceDetector.AzureAppService,
ResourceDetector.Host,
ResourceDetector.Process
};

#if NET
expected.Add(ResourceDetector.Container);
#endif

Assert.Equal(expected.Count, result.Count);
foreach (var detector in expected)
{
Assert.Contains(detector, result);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,12 @@ resource:
- name: service.name
value: unknown_service
attributes_list:
detection/development:
detectors:
azureappservice:
container:
host:
operatingsystem:
process:
processruntime:

Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
// SPDX-License-Identifier: Apache-2.0

using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser;
using OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased;
using Vendors.YamlDotNet.Core;
using Vendors.YamlDotNet.Serialization;
using Xunit;
using YamlParser = Vendors.YamlDotNet.Core.Parser;

namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBasedConfiguration.Parser;
namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased.Parser;

public class ConditionalDeserializerTests
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using Xunit;
using YamlParser = Vendors.YamlDotNet.Core.Parser;

namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBasedConfiguration.Parser;
namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased.Parser;

public class EnvVarTypeConverterTests
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser;
using Xunit;
using YamlParser = OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration.Parser.Parser;

namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased;
namespace OpenTelemetry.AutoInstrumentation.Tests.Configurations.FileBased.Parser;

[Collection("Non-Parallel Collection")]
public class ParserTests
{
[Fact]
public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly()
{
var config = Parser.ParseYaml("Configurations/FileBased/Files/TestFile.yaml");
var config = YamlParser.ParseYaml("Configurations/FileBased/Files/TestFile.yaml");

Assert.NotNull(config);

Expand All @@ -28,6 +28,26 @@ public void Parse_FullConfigYaml_ShouldPopulateModelCorrectly()

Assert.NotNull(config.Resource.AttributesList);
Assert.Empty(config.Resource.AttributesList);
Assert.NotNull(config.Resource.DetectionDevelopment);

#if NET
string[] expectedDetecors = [
"azureappservice", "container", "host", "operatingsystem", "process", "processruntime"
];
#endif
#if NETFRAMEWORK
string[] expectedDetecors = [
"azureappservice", "host", "operatingsystem", "process", "processruntime"
];
#endif

var detectors = config.Resource.DetectionDevelopment.Detectors;
Assert.NotNull(detectors);

foreach (var alias in expectedDetecors)
{
FileBasedTestHelper.AssertAliasPropertyExists(detectors, alias);
}
}

[Fact]
Expand All @@ -37,7 +57,7 @@ public void Parse_EnvVarYaml_ShouldPopulateModelCompletely()
Environment.SetEnvironmentVariable("OTEL_SERVICE_NAME", "my‑service");
Environment.SetEnvironmentVariable("OTEL_RESOURCE_ATTRIBUTES", "key=value");

var config = Parser.ParseYaml("Configurations/FileBased/Files/TestFileEnvVars.yaml");
var config = YamlParser.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");
Expand Down

This file was deleted.

Loading