Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 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
3 changes: 2 additions & 1 deletion .cspell/other.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ NETRUNTIME
Npgsql
NSERVICEBUS
omnisharp
OPAMP
OPENTRACING
OPERATINGSYSTEM
ORACLEMDA
Expand All @@ -58,9 +59,9 @@ protos
RABBITMQ
Serilog
spdlog
srcs
SQLCLIENT
sqlserver
srcs
STACKEXCHANGEREDIS
TMPDIR
tracesexporter
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ This component adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h

### Added

- Experimental support for OpAMP (by default the client is disabled).

### Changed

#### Dependency updates
Expand Down
14 changes: 11 additions & 3 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,10 @@ due to lack of stable semantic convention.

**Status**: [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md).

| ID | Instrumented library | Supported versions | Instrumentation type | Status |
|-----------|---------------------------------------------------------------------------------------------------------------------------------|--------------------|------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| ID | Instrumented library | Supported versions | Instrumentation type | Status |
|-----------|---------------------------------------------------------------------------------------------------------------------------------|--------------------|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `ILOGGER` | [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging) **Not supported on .NET Framework** | ≥9.0.0 | bytecode or source \[1\] | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `LOG4NET` | [log4net](https://www.nuget.org/packages/log4net) \[2\] | ≥2.0.13 && < 4.0.0 | bytecode | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `LOG4NET` | [log4net](https://www.nuget.org/packages/log4net) \[2\] | ≥2.0.13 && < 4.0.0 | bytecode | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |

\[1\]: For ASP.NET Core applications, the `LoggingBuilder` instrumentation
can be enabled without using the .NET CLR Profiler by setting
Expand Down Expand Up @@ -499,3 +499,11 @@ 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) |

## OpAMP Client

| Environment variable | Description | Default value | Status |
|------------------------------------------|--------------------------------------------|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `OTEL_DOTNET_AUTO_OPAMP_ENABLED` | Enables OpAMP client. | `false` | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `OTEL_DOTNET_AUTO_OPAMP_SERVER_URL` | OpAMP server url. | `https://localhost:4318/v1/opamp` | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
| `OTEL_DOTNET_AUTO_OPAMP_CONNECTION_TYPE` | OpAMP connection type (http or websocket). | `http` | [Experimental](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md) |
8 changes: 8 additions & 0 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.SqlClient" Version="1.12.0-beta.3" />
<PackageVersion Include="OpenTelemetry.Instrumentation.StackExchangeRedis" Version="1.12.0-beta.2" />
<PackageVersion Include="OpenTelemetry.OpAmp.Client" Version="0.1.0-alpha.1" />
<PackageVersion Include="OpenTelemetry.Shims.OpenTracing" Version="1.12.0-beta.1" />
<PackageVersion Include="OpenTelemetry.Resources.Azure" Version="1.12.0-beta.1" />
<PackageVersion Include="OpenTelemetry.Resources.Container" Version="1.12.0-beta.1" />
Expand All @@ -46,6 +47,7 @@
<PackageVersion Include="System.Windows.Extensions" Version="4.7.0" />
</ItemGroup>
<ItemGroup Label="Transient dependencies auto-generated by GenerateNetFxTransientDependencies">
<PackageVersion Include="Google.Protobuf" Version="3.31.1" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.8" />
Expand All @@ -60,12 +62,18 @@
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Primitives" Version="9.0.8" />
<PackageVersion Include="System.Buffers" Version="4.6.1" />
<PackageVersion Include="System.Collections.Immutable" Version="8.0.0" />
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="9.0.8" />
<PackageVersion Include="System.IO.Pipelines" Version="9.0.8" />
<PackageVersion Include="System.Memory" Version="4.6.3" />
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Numerics.Vectors" Version="4.6.1" />
<PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.2" />
<PackageVersion Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" />
<PackageVersion Include="System.Security.Cryptography.Algorithms" Version="4.3.0" />
<PackageVersion Include="System.Security.Cryptography.Encoding" Version="4.3.0" />
<PackageVersion Include="System.Security.Cryptography.Primitives" Version="4.3.0" />
<PackageVersion Include="System.Security.Cryptography.X509Certificates" Version="4.3.0" />
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.8" />
<PackageVersion Include="System.Text.Json" Version="9.0.8" />
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ void CorProfiler::InitNetFxAssemblyRedirectsMap()
const USHORT auto_major = atoi(AUTO_MAJOR);

assembly_version_redirect_map_.insert({
{ L"Google.Protobuf", {3, 31, 1, 0} },
{ L"Microsoft.Bcl.AsyncInterfaces", {9, 0, 0, 8} },
{ L"Microsoft.Extensions.Configuration", {9, 0, 0, 8} },
{ L"Microsoft.Extensions.Configuration.Abstractions", {9, 0, 0, 8} },
Expand Down Expand Up @@ -50,6 +51,7 @@ void CorProfiler::InitNetFxAssemblyRedirectsMap()
{ L"OpenTelemetry.Instrumentation.Runtime", {1, 12, 0, 496} },
{ L"OpenTelemetry.Instrumentation.SqlClient", {1, 12, 0, 667} },
{ L"OpenTelemetry.Instrumentation.Wcf", {1, 12, 0, 500} },
{ L"OpenTelemetry.OpAmp.Client", {0, 1, 0, 664} },
{ L"OpenTelemetry.Resources.Azure", {1, 12, 0, 501} },
{ L"OpenTelemetry.Resources.Host", {1, 12, 0, 503} },
{ L"OpenTelemetry.Resources.OperatingSystem", {1, 12, 0, 504} },
Expand All @@ -61,6 +63,7 @@ void CorProfiler::InitNetFxAssemblyRedirectsMap()
{ L"System.Buffers", {4, 0, 5, 0} },
{ L"System.Collections", {4, 0, 11, 0} },
{ L"System.Collections.Concurrent", {4, 0, 11, 0} },
{ L"System.Collections.Immutable", {8, 0, 0, 0} },
{ L"System.Collections.NonGeneric", {4, 0, 3, 0} },
{ L"System.Collections.Specialized", {4, 0, 3, 0} },
{ L"System.ComponentModel", {4, 0, 1, 0} },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,21 @@ internal partial class ConfigurationKeys
/// </summary>
public const string SetupSdk = "OTEL_DOTNET_AUTO_SETUP_SDK";

/// <summary>
/// Configuration key for enabling OpAmp client.
/// </summary>
public const string OpAmpEnabled = "OTEL_DOTNET_AUTO_OPAMP_ENABLED";

/// <summary>
/// Configuration key for OpAmp server url.
/// </summary>
public const string OpAmpServerUrl = "OTEL_DOTNET_AUTO_OPAMP_SERVER_URL";

/// <summary>
/// Configuration key for OpAmp server connection type.
/// </summary>
public const string OpAmpConnectionType = "OTEL_DOTNET_AUTO_OPAMP_CONNECTION_TYPE";

/// <summary>
/// Configuration key for enabling all instrumentations.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ internal class GeneralSettings : Settings
/// </summary>
public bool ProfilerEnabled { get; private set; }

/// <summary>
/// Gets a value indicating whether the OpAmp client is enabled.
/// </summary>
public bool OpAmpClientEnabled { get; private set; }

protected override void OnLoadEnvVar(Configuration configuration)
{
var providerPlugins = configuration.GetString(ConfigurationKeys.ProviderPlugins);
Expand All @@ -42,5 +47,6 @@ protected override void OnLoadEnvVar(Configuration configuration)
SetupSdk = configuration.GetBool(ConfigurationKeys.SetupSdk) ?? true;

ProfilerEnabled = configuration.GetString(ConfigurationKeys.ProfilingEnabled) == "1";
OpAmpClientEnabled = configuration.GetBool(ConfigurationKeys.OpAmpEnabled) ?? false;
}
}
10 changes: 10 additions & 0 deletions src/OpenTelemetry.AutoInstrumentation/Instrumentation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using OpenTelemetry.AutoInstrumentation.Loading;
using OpenTelemetry.AutoInstrumentation.Logging;
using OpenTelemetry.AutoInstrumentation.Plugins;
using OpenTelemetry.AutoInstrumentation.Util;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
Expand Down Expand Up @@ -207,6 +208,13 @@ public static void Initialize()
{
OpenTracingHelper.EnableOpenTracing(_tracerProvider);
}

if (GeneralSettings.Value.OpAmpClientEnabled)
{
var resources = ResourceHelper.AggregateResources(_tracerProvider, _meterProvider, LoggerProvider);

OpAmpHelper.EnableOpAmpClient(resources);
}
}

#if NET
Expand Down Expand Up @@ -525,6 +533,8 @@ private static void OnExit(object? sender, EventArgs e)

try
{
OpAmpHelper.StopOpAmpClientIfRunning();

#if NET
LazyInstrumentationLoader?.Dispose();
_sampleExporter?.Dispose();
Expand Down
160 changes: 160 additions & 0 deletions src/OpenTelemetry.AutoInstrumentation/OpAmpHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using System.Reflection;
using OpenTelemetry.AutoInstrumentation.Configurations;
using OpenTelemetry.AutoInstrumentation.Logging;
using OpenTelemetry.OpAmp.Client;
using OpenTelemetry.OpAmp.Client.Settings;
using OpenTelemetry.Resources;

namespace OpenTelemetry.AutoInstrumentation;

internal static class OpAmpHelper
{
private static readonly CancellationTokenSource _cts = new();
private static readonly IOtelLogger Logger = OtelLogging.GetLogger();

private static OpAmpClient? _client;
private static Task? _clientRunningTask;

public static bool IsRunning { get; private set; }

public static void EnableOpAmpClient(Resource resources)
{
try
{
_client = new OpAmpClient(settings => ConfigureClient(settings, resources));

_clientRunningTask = Task.Run(async () =>
{
try
{
await _client.StartAsync(_cts.Token);

IsRunning = true;
}
catch (Exception ex)
{
Logger.Warning(ex, "OpAmp client stopped unexpectedly.");

IsRunning = false;
}
});
}
catch (Exception ex)
{
Logger.Error(ex, "An error occurred while initializing the OpAmp client.");
}
}

public static void StopOpAmpClientIfRunning()
{
if (!IsRunning)
{
return;
}

try
{
_client?.StopAsync().GetAwaiter().GetResult();

if (_clientRunningTask != null)
{
_cts.Cancel();
_clientRunningTask.GetAwaiter().GetResult();
}

_client?.Dispose();
}
catch (Exception ex)
{
Logger.Error(ex, "An error occurred while stopping the OpAmp client.");
}
finally
{
IsRunning = false;
}
}

private static void ConfigureClient(OpAmpClientSettings settings, Resource resources)
{
// Configure connection type
var connectionType = GetConnectionType();
if (connectionType.HasValue)
{
settings.ConnectionType = connectionType.Value;
}

// Configure server URL
var serverUrl = GetServerUrl();
if (serverUrl != null)
{
settings.ServerUrl = serverUrl;
}

// Configure resource attributes for identification
foreach (var resourceAttribute in resources.Attributes)
{
if (resourceAttribute.Value == null)
{
continue;
}

var value = resourceAttribute.Value.ToString();
if (!string.IsNullOrWhiteSpace(value))
{
if (resourceAttribute.Key == "service.name")
{
settings.Identification.AddIdentifyingAttribute(resourceAttribute.Key, value);
}
else
{
settings.Identification.AddNonIdentifyingAttribute(resourceAttribute.Key, value);
}
}
}

settings.Identification.AddNonIdentifyingAttribute("opamp.version", GetOpAmpVersion());
}

private static Uri? GetServerUrl()
{
var url = Environment.GetEnvironmentVariable(ConfigurationKeys.OpAmpServerUrl);

if (string.IsNullOrWhiteSpace(url))
{
// indicates that the default value should be used
return null;
}

return new Uri(url);
}

private static ConnectionType? GetConnectionType()
{
var type = Environment.GetEnvironmentVariable(ConfigurationKeys.OpAmpConnectionType);

if (string.IsNullOrWhiteSpace(type))
{
// indicates that the default value should be used
return null;
}

return type.ToLower() switch
{
"websocket" => ConnectionType.WebSocket,
"http" => ConnectionType.Http,
_ => throw new InvalidOperationException($"{ConfigurationKeys.OpAmpConnectionType} environment variable has an invalid value. Valid values are 'websocket' and 'http'."),
};
}

private static string GetOpAmpVersion()
{
var assembly = typeof(OpAmpClient).Assembly;

return assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
.InformationalVersion?.Split(['+'], 2)[0] ?? "unknown";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
<PackageReference Include="OpenTelemetry.Instrumentation.Process" />
<PackageReference Include="OpenTelemetry.Instrumentation.SqlClient" />
<PackageReference Include="OpenTelemetry.OpAmp.Client" />
<PackageReference Include="OpenTelemetry.Resources.Azure" />
<PackageReference Include="OpenTelemetry.Resources.Host" />
<PackageReference Include="OpenTelemetry.Resources.OperatingSystem" />
Expand All @@ -60,6 +61,7 @@

<ItemGroup Label="Transient dependencies auto-generated by GenerateNetFxTransientDependencies" Condition=" '$(TargetFramework)' == 'net462' AND $(_IsPacking) != true ">
<!-- These dependencies are also not included in the NuGet package since the conflicts can be left to NuGet version resolution. -->
<PackageReference Include="Google.Protobuf" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
<PackageReference Include="Microsoft.Extensions.Configuration" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
Expand All @@ -74,12 +76,18 @@
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
<PackageReference Include="Microsoft.Extensions.Primitives" />
<PackageReference Include="System.Buffers" />
<PackageReference Include="System.Collections.Immutable" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" />
<PackageReference Include="System.IO.Pipelines" />
<PackageReference Include="System.Memory" />
<PackageReference Include="System.Net.Http" />
<PackageReference Include="System.Numerics.Vectors" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" />
<PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" />
<PackageReference Include="System.Security.Cryptography.Algorithms" />
<PackageReference Include="System.Security.Cryptography.Encoding" />
<PackageReference Include="System.Security.Cryptography.Primitives" />
<PackageReference Include="System.Security.Cryptography.X509Certificates" />
<PackageReference Include="System.Text.Encodings.Web" />
<PackageReference Include="System.Text.Json" />
<PackageReference Include="System.Threading.Tasks.Extensions" />
Expand Down
Loading
Loading