Skip to content
Draft
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
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