Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
19 changes: 18 additions & 1 deletion docs/file-based-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,21 @@ resource:
operatingsystem: # Detects OS-level attributes (os.*)
process: # Detects process-level attributes (process.*)
processruntime: # Detects process runtime attributes (process.runtime.*)
```
```

### Plugins Configuration

For more details and updates about Plugins Configuration, see:
[Plugins documentation](plugins.md)

``` yaml
plugins/development:
# Configure plugins. Entries have higher priority than entries from .plugins_list.
# List of plugins to load. Each entry is the full type name, followed by the assembly name.
# For example: MyNamespace.MyPlugin, MyAssembly, Version=1.0.0, Culture=neutral, PublicKeyToken=null
plugins:
- Test1.Plugins.Plugin, Test1.Plugins, Version=1.0.0, Culture=neutral, PublicKeyToken=null
- Test2.Plugins.Plugin, Test2.Plugins
# Alternatively, configure via a colon-separated list (same format as OTEL_DOTNET_AUTO_PLUGINS).
plugins_list: ${OTEL_DOTNET_AUTO_PLUGINS}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using Vendors.YamlDotNet.Serialization;

namespace OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration;

internal class PluginsConfiguration
{
/// <summary>
/// Gets or sets the list of plugins.
/// </summary>
[YamlMember(Alias = "plugins")]
public List<string>? Plugins { get; set; }

/// <summary>
/// Gets or sets the plugins list.
/// </summary>
[YamlMember(Alias = "plugins_list")]
public string? PluginsList { get; set; }

public List<string> ParsePlugins()
{
var uniquePlugins = new HashSet<string>();

if (Plugins != null)
{
foreach (var plugin in Plugins)
{
if (!string.IsNullOrWhiteSpace(plugin))
{
uniquePlugins.Add(plugin.Trim());
}
}
}

if (!string.IsNullOrWhiteSpace(PluginsList))
{
foreach (var plugin in PluginsList!.Split(Constants.ConfigurationValues.DotNetQualifiedNameSeparator))
{
uniquePlugins.Add(plugin.Trim());
}
}

return uniquePlugins.ToList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,10 @@ internal class YamlConfiguration
/// </summary>
[YamlMember(Alias = "no_code/development")]
public NoCodeConfiguration? NoCode { get; set; }

/// <summary>
/// Gets or sets the plugins configuration.
/// </summary>
[YamlMember(Alias = "plugins/development")]
public PluginsConfiguration? Plugins { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ namespace OpenTelemetry.AutoInstrumentation.Configurations;

internal class GeneralSettings : Settings
{
/// <summary>
/// Gets the list of plugins represented by <see cref="Type.AssemblyQualifiedName"/>.
/// </summary>
public IList<string> Plugins { get; } = [];

/// <summary>
/// Gets a value indicating whether the <see cref="AppDomain.UnhandledException"/> event should trigger
/// the flushing of telemetry data.
Expand All @@ -32,15 +27,6 @@ internal class GeneralSettings : Settings

protected override void OnLoadEnvVar(Configuration configuration)
{
var providerPlugins = configuration.GetString(ConfigurationKeys.ProviderPlugins);
if (providerPlugins != null)
{
foreach (var pluginAssemblyQualifiedName in providerPlugins.Split(Constants.ConfigurationValues.DotNetQualifiedNameSeparator))
{
Plugins.Add(pluginAssemblyQualifiedName);
}
}

FlushOnUnhandledException = configuration.GetBool(ConfigurationKeys.FlushOnUnhandledException) ?? false;
SetupSdk = configuration.GetBool(ConfigurationKeys.SetupSdk) ?? true;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using OpenTelemetry.AutoInstrumentation.Configurations.FileBasedConfiguration;

namespace OpenTelemetry.AutoInstrumentation.Configurations;

internal class PluginsSettings : Settings
{
/// <summary>
/// Gets the list of plugins represented by <see cref="Type.AssemblyQualifiedName"/>.
/// </summary>
public IList<string> Plugins { get; private set; } = [];

protected override void OnLoadEnvVar(Configuration configuration)
{
var providerPlugins = configuration.GetString(ConfigurationKeys.ProviderPlugins);
if (providerPlugins != null)
{
foreach (var pluginAssemblyQualifiedName in providerPlugins.Split(Constants.ConfigurationValues.DotNetQualifiedNameSeparator))
{
Plugins.Add(pluginAssemblyQualifiedName);
}
}
}

protected override void OnLoadFile(YamlConfiguration configuration)
{
Plugins = configuration.Plugins?.ParsePlugins() ?? [];
}
}
4 changes: 3 additions & 1 deletion src/OpenTelemetry.AutoInstrumentation/Instrumentation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ internal static LoggerProvider? LoggerProvider

internal static Lazy<NoCodeSettings> NoCodeSettings { get; } = new(() => Settings.FromDefaultSources<NoCodeSettings>(FailFastSettings.Value.FailFast));

internal static Lazy<PluginsSettings> PluginsSettings { get; } = new(() => Settings.FromDefaultSources<PluginsSettings>(FailFastSettings.Value.FailFast));

/// <summary>
/// Initialize the OpenTelemetry SDK with a pre-defined set of exporters, shims, and
/// instrumentations.
Expand Down Expand Up @@ -102,7 +104,7 @@ public static void Initialize()
// Initialize SdkSelfDiagnosticsEventListener to create an EventListener for the OpenTelemetry SDK
_sdkEventListener = new(Logger);

_pluginManager = new PluginManager(GeneralSettings.Value);
_pluginManager = new PluginManager(PluginsSettings.Value);
_pluginManager.Initializing();

// Register to shutdown events
Expand Down
14 changes: 4 additions & 10 deletions src/OpenTelemetry.AutoInstrumentation/Plugins/PluginManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ internal partial class PluginManager
{
private readonly IReadOnlyList<(Type Type, object Instance)> _plugins;

public PluginManager(GeneralSettings settings)
public PluginManager(PluginsSettings settings)
{
var plugins = new List<(Type, object)>();

Expand Down Expand Up @@ -131,22 +131,16 @@ private void CallPlugins(string methodName)
foreach (var plugin in _plugins)
{
var mi = plugin.Type.GetMethod(methodName, Type.EmptyTypes);
if (mi is not null)
{
mi.Invoke(plugin.Instance, null);
}
mi?.Invoke(plugin.Instance, null);
}
}

private void CallPlugins(string methodName, (Type Type, object Value) arg)
{
foreach (var plugin in _plugins)
{
var mi = plugin.Type.GetMethod(methodName, new[] { arg.Type });
if (mi is not null)
{
mi.Invoke(plugin.Instance, new object[] { arg.Value });
}
var mi = plugin.Type.GetMethod(methodName, [arg.Type]);
mi?.Invoke(plugin.Instance, [arg.Value]);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// 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 FilebasedPluginsSettingsTests
{
[Fact]
public void LoadFile_PluginsSettings()
{
var conf = new YamlConfiguration
{
Plugins = new PluginsConfiguration
{
Plugins = ["Test.Plugins.Plugin, Test.Plugins"]
}
};

var settings = new PluginsSettings();

settings.LoadFile(conf);

Assert.Single(settings.Plugins);
Assert.Contains("Test.Plugins.Plugin, Test.Plugins", settings.Plugins);
}

[Fact]
public void LoadFile_PluginsListSettings()
{
var conf = new YamlConfiguration
{
Plugins = new PluginsConfiguration
{
PluginsList = "Test.Plugins.Plugin, Test.Plugins"
}
};

var settings = new PluginsSettings();

settings.LoadFile(conf);
Assert.Single(settings.Plugins);
Assert.Contains("Test.Plugins.Plugin, Test.Plugins", settings.Plugins);
}

[Fact]
public void LoadFile_MergePluginsSettings()
{
var conf = new YamlConfiguration
{
Plugins = new PluginsConfiguration
{
Plugins = ["Test1.Plugins.Plugin, Test1.Plugins", "Test2.Plugins.Plugin, Test2.Plugins"],
PluginsList = "Test2.Plugins.Plugin, Test2.Plugins:Test3.Plugins.Plugin, Test3.Plugins"
}
};

var settings = new PluginsSettings();

settings.LoadFile(conf);

Assert.Equal(3, settings.Plugins.Count);
Assert.Contains("Test1.Plugins.Plugin, Test1.Plugins", settings.Plugins);
Assert.Contains("Test2.Plugins.Plugin, Test2.Plugins", settings.Plugins);
Assert.Contains("Test3.Plugins.Plugin, Test3.Plugins", settings.Plugins);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
file_format: "1.0-rc.1"
plugins/development:
plugins:
- Test1.Plugins.Plugin, Test1.Plugins
- Test2.Plugins.Plugin, Test2.Plugins
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
file_format: "1.0-rc.1"
plugins/development:
plugins_list: ${OTEL_DOTNET_AUTO_PLUGINS}

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

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

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

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

Assert.NotNull(config);

Assert.NotNull(config.Plugins);
Assert.NotNull(config.Plugins.Plugins);
Assert.Null(config.Plugins.PluginsList);
Assert.Equal(2, config.Plugins.Plugins.Count);
Assert.Equal("Test1.Plugins.Plugin, Test1.Plugins", config.Plugins.Plugins[0]);
Assert.Equal("Test2.Plugins.Plugin, Test2.Plugins", config.Plugins.Plugins[1]);
}

[Fact]
public void Parse_EnvVarYaml_ShouldPopulateModelCompletely()
{
Environment.SetEnvironmentVariable("OTEL_DOTNET_AUTO_PLUGINS", "Test.Plugins.Plugin, Test.Plugins");

var config = YamlParser.ParseYaml("Configurations/FileBased/Files/TestPluginsFileEnvVars.yaml");

Assert.NotNull(config);

Assert.NotNull(config.Plugins);
Assert.Null(config.Plugins.Plugins);
Assert.NotNull(config.Plugins.PluginsList);

Assert.Equal("Test.Plugins.Plugin, Test.Plugins", config.Plugins.PluginsList);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,14 @@ public void ConfigureResourceSuccess()
Assert.Equal("value", resource.Attributes.First().Value);
}

private static GeneralSettings GetSettings(string assemblyQualifiedName)
private static PluginsSettings GetSettings(string assemblyQualifiedName)
{
var config = new Configuration(false, new NameValueConfigurationSource(false, new NameValueCollection()
{
{ ConfigurationKeys.ProviderPlugins, assemblyQualifiedName }
}));

var settings = new GeneralSettings();
var settings = new PluginsSettings();
settings.LoadEnvVar(config);
return settings;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,17 @@ internal void GeneralSettings_DefaultValues()
{
var settings = Settings.FromDefaultSources<GeneralSettings>(false);

Assert.Empty(settings.Plugins);
Assert.False(settings.FlushOnUnhandledException);
}

[Fact]
internal void PluginsSettings_DefaultValues()
{
var settings = Settings.FromDefaultSources<PluginsSettings>(false);

Assert.Empty(settings.Plugins);
}

[Fact]
internal void ResourceSettings_DefaultValues()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" />
Expand All @@ -15,9 +15,15 @@
<None Update="Configurations\FileBased\Files\NoCodeFile.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Configurations\FileBased\Files\TestPluginsFile.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Configurations\FileBased\Files\TestGeneralFile.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Configurations\FileBased\Files\TestPluginsFileEnvVars.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Configurations\FileBased\Files\TestResourceFile.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
Expand Down
Loading