Custom sdk support (#2069)

This commit is contained in:
Mateusz Łach 2023-01-26 12:06:13 +01:00 committed by GitHub
parent 0778bbd057
commit 3bcb488a92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 424 additions and 34 deletions

View File

@ -18,6 +18,7 @@ This beta release is built on top of [OpenTelemetry .NET](https://github.com/ope
- Support configuring `OTEL_*` settings using `App.config` and `Web.config`.
- Add support for Quartz traces instrumentation.
- Add support for EntityFrameworkCore traces instrumentations.
- Add support for custom OpenTelemetry .NET SDK through `OTEL_DOTNET_AUTO_SETUP_SDK`.
### Changed

View File

@ -5,6 +5,8 @@
<ItemGroup>
<PackageVersion Include="OpenTelemetry" Version="1.4.0-rc.2" />
<PackageVersion Include="OpenTelemetry.Api" Version="1.4.0-rc.2" />
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.4.0-rc.2" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.4.0-rc.2" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc9.11" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Wcf" Version="1.0.0-rc.8" />

View File

@ -151,6 +151,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.AspNet.NetF
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApplication.MultipleAppDomains.NetFramework", "test\test-applications\integrations\TestApplication.MultipleAppDomains.NetFramework\TestApplication.MultipleAppDomains.NetFramework.csproj", "{A0338846-2AF8-4D96-ADA7-EBD4F010D08F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.CustomSdk", "test\test-applications\integrations\TestApplication.CustomSdk\TestApplication.CustomSdk.csproj", "{7B363F47-1DB8-44CF-8388-A41F9366C9DE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApplication.Quartz", "test\test-applications\integrations\TestApplication.Quartz\TestApplication.Quartz.csproj", "{B48780CE-8AAB-44D3-9CD1-8491584352B5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "test\Benchmarks\Benchmarks.csproj", "{B1E71654-E784-4A39-BE45-8671E027B6D7}"
@ -713,6 +715,18 @@ Global
{A0338846-2AF8-4D96-ADA7-EBD4F010D08F}.Release|x64.Build.0 = Release|x64
{A0338846-2AF8-4D96-ADA7-EBD4F010D08F}.Release|x86.ActiveCfg = Release|x86
{A0338846-2AF8-4D96-ADA7-EBD4F010D08F}.Release|x86.Build.0 = Release|x86
{7B363F47-1DB8-44CF-8388-A41F9366C9DE}.Debug|Any CPU.ActiveCfg = Debug|x64
{7B363F47-1DB8-44CF-8388-A41F9366C9DE}.Debug|Any CPU.Build.0 = Debug|x64
{7B363F47-1DB8-44CF-8388-A41F9366C9DE}.Debug|x64.ActiveCfg = Debug|x64
{7B363F47-1DB8-44CF-8388-A41F9366C9DE}.Debug|x64.Build.0 = Debug|x64
{7B363F47-1DB8-44CF-8388-A41F9366C9DE}.Debug|x86.ActiveCfg = Debug|x86
{7B363F47-1DB8-44CF-8388-A41F9366C9DE}.Debug|x86.Build.0 = Debug|x86
{7B363F47-1DB8-44CF-8388-A41F9366C9DE}.Release|Any CPU.ActiveCfg = Release|x64
{7B363F47-1DB8-44CF-8388-A41F9366C9DE}.Release|Any CPU.Build.0 = Release|x64
{7B363F47-1DB8-44CF-8388-A41F9366C9DE}.Release|x64.ActiveCfg = Release|x64
{7B363F47-1DB8-44CF-8388-A41F9366C9DE}.Release|x64.Build.0 = Release|x64
{7B363F47-1DB8-44CF-8388-A41F9366C9DE}.Release|x86.ActiveCfg = Release|x86
{7B363F47-1DB8-44CF-8388-A41F9366C9DE}.Release|x86.Build.0 = Release|x86
{B48780CE-8AAB-44D3-9CD1-8491584352B5}.Debug|Any CPU.ActiveCfg = Debug|x64
{B48780CE-8AAB-44D3-9CD1-8491584352B5}.Debug|Any CPU.Build.0 = Debug|x64
{B48780CE-8AAB-44D3-9CD1-8491584352B5}.Debug|x64.ActiveCfg = Debug|x64
@ -804,6 +818,7 @@ Global
{E1E55FB4-FCFF-4231-9CE7-C6671A3F5421} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{5FDB5603-21D3-446A-8B50-36DACCF7C2FF} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{A0338846-2AF8-4D96-ADA7-EBD4F010D08F} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{7B363F47-1DB8-44CF-8388-A41F9366C9DE} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{B48780CE-8AAB-44D3-9CD1-8491584352B5} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{B1E71654-E784-4A39-BE45-8671E027B6D7} = {5C915382-C886-457D-8641-9E766D8E5A17}
{036A56A4-4EEF-42E3-9857-B9B00D302BF9} = {E409ADD3-9574-465C-AB09-4324D205CC7C}

View File

@ -42,6 +42,7 @@ with environment variables taking precedence over `App.config` or `Web.config` f
|--------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
| `OTEL_DOTNET_AUTO_HOME` | Installation location. | |
| `OTEL_DOTNET_AUTO_EXCLUDE_PROCESSES` | Names of the executable files that the profiler cannot instrument. Supports multiple comma-separated values, for example: `ReservedProcess.exe,powershell.exe`. If unset, the profiler attaches to all processes by default. | |
| `OTEL_DOTNET_AUTO_SETUP_SDK` | Controls whether auto-instrumentation should set up OpenTelemetry .NET SDK at startup. | `true` |
## Resources

View File

@ -9,8 +9,6 @@
<!-- Versions from OpenTelemetry.AutoInstrumentation.csproj -->
<ItemGroup>
<PackageVersion Include="OpenTelemetry.Api" Version="1.4.0-rc.2" />
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.4.0-rc.2" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs" Version="1.4.0-rc.2" />
<PackageVersion Include="OpenTelemetry.Exporter.Prometheus.HttpListener" Version="1.4.0-rc.2" />
<PackageVersion Include="OpenTelemetry.Exporter.Zipkin" Version="1.4.0-rc.2" />

View File

@ -50,6 +50,11 @@ internal static class ConfigurationKeys
/// </summary>
public const string ProviderPlugins = "OTEL_DOTNET_AUTO_PLUGINS";
/// <summary>
/// Configuration key for setting up OpenTelemetry .NET SDK.
/// </summary>
public const string SetupSdk = "OTEL_DOTNET_AUTO_SETUP_SDK";
/// <summary>
/// Configuration keys for traces.
/// </summary>

View File

@ -0,0 +1,101 @@
// <copyright file="DelayedInitialization.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using System.Runtime.CompilerServices;
using OpenTelemetry.AutoInstrumentation.Loading;
using OpenTelemetry.AutoInstrumentation.Loading.Initializers;
using OpenTelemetry.AutoInstrumentation.Plugins;
namespace OpenTelemetry.AutoInstrumentation.Configurations;
internal static class DelayedInitialization
{
internal static class Traces
{
[MethodImpl(MethodImplOptions.NoInlining)]
public static void AddAspNet(LazyInstrumentationLoader lazyInstrumentationLoader, PluginManager pluginManager)
{
#if NET462
new AspNetInitializer(lazyInstrumentationLoader, pluginManager);
#elif NET6_0_OR_GREATER
lazyInstrumentationLoader.Add(new AspNetCoreInitializer(pluginManager));
#endif
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void AddHttpClient(LazyInstrumentationLoader lazyInstrumentationLoader, PluginManager pluginManager)
{
new HttpClientInitializer(lazyInstrumentationLoader, pluginManager);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void AddGrpcClient(LazyInstrumentationLoader lazyInstrumentationLoader, PluginManager pluginManager)
{
lazyInstrumentationLoader.Add(new GrpcClientInitializer(pluginManager));
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void AddSqlClient(LazyInstrumentationLoader lazyInstrumentationLoader, PluginManager pluginManager)
{
new SqlClientInitializer(lazyInstrumentationLoader, pluginManager);
}
#if NET6_0_OR_GREATER
[MethodImpl(MethodImplOptions.NoInlining)]
public static void AddMySqlClient(LazyInstrumentationLoader lazyInstrumentationLoader, PluginManager pluginManager)
{
lazyInstrumentationLoader.Add(new MySqlDataInitializer(pluginManager));
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void AddEntityFrameworkCore(LazyInstrumentationLoader lazyInstrumentationLoader, PluginManager pluginManager)
{
lazyInstrumentationLoader.Add(new EntityFrameworkCoreInitializer(pluginManager));
}
#endif
[MethodImpl(MethodImplOptions.NoInlining)]
public static void AddWcf(LazyInstrumentationLoader lazyInstrumentationLoader, PluginManager pluginManager)
{
lazyInstrumentationLoader.Add(new WcfInitializer(pluginManager));
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void AddQuartz(LazyInstrumentationLoader lazyInstrumentationLoader, PluginManager pluginManager)
{
lazyInstrumentationLoader.Add(new QuartzInitializer(pluginManager));
}
}
internal static class Metrics
{
[MethodImpl(MethodImplOptions.NoInlining)]
public static void AddAspNet(LazyInstrumentationLoader lazyInstrumentationLoader)
{
#if NET462
new AspNetMetricsInitializer(lazyInstrumentationLoader);
#elif NET6_0_OR_GREATER
lazyInstrumentationLoader.Add(new AspNetCoreMetricsInitializer());
#endif
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void AddHttpClient(LazyInstrumentationLoader lazyInstrumentationLoader)
{
new HttpClientMetricsInitializer(lazyInstrumentationLoader);
}
}
}

View File

@ -82,23 +82,19 @@ internal static class EnvironmentConfigurationMetricHelper
[MethodImpl(MethodImplOptions.NoInlining)]
public static MeterProviderBuilder AddAspNetInstrumentation(MeterProviderBuilder builder, LazyInstrumentationLoader lazyInstrumentationLoader)
{
DelayedInitialization.Metrics.AddAspNet(lazyInstrumentationLoader);
#if NET462
new AspNetMetricsInitializer(lazyInstrumentationLoader);
builder.AddMeter("OpenTelemetry.Instrumentation.AspNet");
#elif NET6_0_OR_GREATER
lazyInstrumentationLoader.Add(new AspNetCoreMetricsInitializer());
builder.AddMeter("OpenTelemetry.Instrumentation.AspNetCore");
#endif
return builder;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static MeterProviderBuilder AddHttpClientInstrumentation(MeterProviderBuilder builder, LazyInstrumentationLoader lazyInstrumentationLoader)
{
new HttpClientMetricsInitializer(lazyInstrumentationLoader);
DelayedInitialization.Metrics.AddHttpClient(lazyInstrumentationLoader);
return builder.AddMeter("OpenTelemetry.Instrumentation.Http");
}

View File

@ -113,7 +113,7 @@ internal static class EnvironmentConfigurationTracerHelper
[MethodImpl(MethodImplOptions.NoInlining)]
public static TracerProviderBuilder AddWcfInstrumentation(TracerProviderBuilder builder, PluginManager pluginManager, LazyInstrumentationLoader lazyInstrumentationLoader)
{
lazyInstrumentationLoader.Add(new WcfInitializer(pluginManager));
DelayedInitialization.Traces.AddWcf(lazyInstrumentationLoader, pluginManager);
return builder.AddSource("OpenTelemetry.Instrumentation.Wcf");
}
@ -121,7 +121,7 @@ internal static class EnvironmentConfigurationTracerHelper
[MethodImpl(MethodImplOptions.NoInlining)]
public static TracerProviderBuilder AddHttpClientInstrumentation(TracerProviderBuilder builder, PluginManager pluginManager, LazyInstrumentationLoader lazyInstrumentationLoader)
{
new HttpClientInitializer(lazyInstrumentationLoader, pluginManager);
DelayedInitialization.Traces.AddHttpClient(lazyInstrumentationLoader, pluginManager);
#if NETFRAMEWORK
builder.AddSource("OpenTelemetry.Instrumentation.Http.HttpWebRequest");
@ -137,17 +137,13 @@ internal static class EnvironmentConfigurationTracerHelper
[MethodImpl(MethodImplOptions.NoInlining)]
public static TracerProviderBuilder AddAspNetInstrumentation(TracerProviderBuilder builder, PluginManager pluginManager, LazyInstrumentationLoader lazyInstrumentationLoader)
{
DelayedInitialization.Traces.AddAspNet(lazyInstrumentationLoader, pluginManager);
#if NET462
new AspNetInitializer(lazyInstrumentationLoader, pluginManager);
builder.AddSource(OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule.AspNetSourceName);
#elif NET6_0_OR_GREATER
lazyInstrumentationLoader.Add(new AspNetCoreInitializer(pluginManager));
builder.AddSource("OpenTelemetry.Instrumentation.AspNetCore");
builder.AddLegacySource("Microsoft.AspNetCore.Hosting.HttpRequestIn");
#endif
return builder;
}
@ -155,7 +151,7 @@ internal static class EnvironmentConfigurationTracerHelper
[MethodImpl(MethodImplOptions.NoInlining)]
public static TracerProviderBuilder AddMySqlClientInstrumentation(TracerProviderBuilder builder, PluginManager pluginManager, LazyInstrumentationLoader lazyInstrumentationLoader)
{
lazyInstrumentationLoader.Add(new MySqlDataInitializer(pluginManager));
DelayedInitialization.Traces.AddMySqlClient(lazyInstrumentationLoader, pluginManager);
return builder.AddSource("OpenTelemetry.Instrumentation.MySqlData");
}
@ -164,7 +160,7 @@ internal static class EnvironmentConfigurationTracerHelper
[MethodImpl(MethodImplOptions.NoInlining)]
public static TracerProviderBuilder AddSqlClientInstrumentation(TracerProviderBuilder builder, PluginManager pluginManager, LazyInstrumentationLoader lazyInstrumentationLoader)
{
new SqlClientInitializer(lazyInstrumentationLoader, pluginManager);
DelayedInitialization.Traces.AddSqlClient(lazyInstrumentationLoader, pluginManager);
return builder.AddSource("OpenTelemetry.Instrumentation.SqlClient");
}
@ -172,7 +168,7 @@ internal static class EnvironmentConfigurationTracerHelper
[MethodImpl(MethodImplOptions.NoInlining)]
public static TracerProviderBuilder AddGrpcClientInstrumentation(TracerProviderBuilder builder, PluginManager pluginManager, LazyInstrumentationLoader lazyInstrumentationLoader)
{
lazyInstrumentationLoader.Add(new GrpcClientInitializer(pluginManager));
DelayedInitialization.Traces.AddGrpcClient(lazyInstrumentationLoader, pluginManager);
builder.AddSource("OpenTelemetry.Instrumentation.GrpcNetClient");
builder.AddLegacySource("Grpc.Net.Client.GrpcOut");
@ -183,7 +179,7 @@ internal static class EnvironmentConfigurationTracerHelper
[MethodImpl(MethodImplOptions.NoInlining)]
public static TracerProviderBuilder AddQuartzInstrumentation(TracerProviderBuilder builder, PluginManager pluginManager, LazyInstrumentationLoader lazyInstrumentationLoader)
{
lazyInstrumentationLoader.Add(new QuartzInitializer(pluginManager));
DelayedInitialization.Traces.AddQuartz(lazyInstrumentationLoader, pluginManager);
return builder.AddSource("OpenTelemetry.Instrumentation.Quartz")
.AddLegacySource("Quartz.Job.Execute")
@ -194,7 +190,7 @@ internal static class EnvironmentConfigurationTracerHelper
[MethodImpl(MethodImplOptions.NoInlining)]
public static TracerProviderBuilder AddEntityFrameworkCoreInstrumentation(TracerProviderBuilder builder, PluginManager pluginManager, LazyInstrumentationLoader lazyInstrumentationLoader)
{
lazyInstrumentationLoader.Add(new EntityFrameworkCoreInitializer(pluginManager));
DelayedInitialization.Traces.AddEntityFrameworkCore(lazyInstrumentationLoader, pluginManager);
return builder.AddSource("OpenTelemetry.Instrumentation.EntityFrameworkCore");
}

View File

@ -30,6 +30,11 @@ internal class GeneralSettings : Settings
/// </summary>
public bool FlushOnUnhandledException { get; private set; }
/// <summary>
/// Gets a value indicating whether OpenTelemetry .NET SDK should be set up.
/// </summary>
public bool SetupSdk { get; private set; }
protected override void OnLoad(Configuration configuration)
{
var providerPlugins = configuration.GetString(ConfigurationKeys.ProviderPlugins);
@ -42,5 +47,6 @@ internal class GeneralSettings : Settings
}
FlushOnUnhandledException = configuration.GetBool(ConfigurationKeys.FlushOnUnhandledException) ?? false;
SetupSdk = configuration.GetBool(ConfigurationKeys.SetupSdk) ?? true;
}
}

View File

@ -130,6 +130,8 @@ internal static class Instrumentation
}
if (TracerSettings.Value.TracesEnabled)
{
if (GeneralSettings.Value.SetupSdk)
{
var builder = Sdk
.CreateTracerProviderBuilder()
@ -140,8 +142,16 @@ internal static class Instrumentation
_tracerProvider = builder.Build();
Logger.Information("OpenTelemetry tracer initialized.");
}
else
{
AddLazilyLoadedTraceInstrumentations(LazyInstrumentationLoader, _pluginManager, TracerSettings.Value.EnabledInstrumentations);
Logger.Information("Initialized lazily-loaded trace instrumentations without initializing sdk.");
}
}
if (MetricSettings.Value.MetricsEnabled)
{
if (GeneralSettings.Value.SetupSdk)
{
var builder = Sdk
.CreateMeterProviderBuilder()
@ -152,6 +162,13 @@ internal static class Instrumentation
_meterProvider = builder.Build();
Logger.Information("OpenTelemetry meter initialized.");
}
else
{
AddLazilyLoadedMetricInstrumentations(LazyInstrumentationLoader, MetricSettings.Value.EnabledInstrumentations);
Logger.Information("Initialized lazily-loaded metric instrumentations without initializing sdk.");
}
}
}
catch (Exception ex)
{
@ -165,6 +182,84 @@ internal static class Instrumentation
}
}
private static void AddLazilyLoadedMetricInstrumentations(LazyInstrumentationLoader lazyInstrumentationLoader, IList<MetricInstrumentation> enabledInstrumentations)
{
foreach (var instrumentation in enabledInstrumentations)
{
switch (instrumentation)
{
case MetricInstrumentation.AspNet:
DelayedInitialization.Metrics.AddAspNet(lazyInstrumentationLoader);
break;
case MetricInstrumentation.HttpClient:
DelayedInitialization.Metrics.AddHttpClient(lazyInstrumentationLoader);
break;
case MetricInstrumentation.NetRuntime:
break;
case MetricInstrumentation.Process:
break;
case MetricInstrumentation.NServiceBus:
break;
default:
Logger.Warning($"Configured metric intrumentation type is not supported: {instrumentation}");
break;
}
}
}
private static void AddLazilyLoadedTraceInstrumentations(LazyInstrumentationLoader lazyInstrumentationLoader, PluginManager pluginManager, IList<TracerInstrumentation> enabledInstrumentations)
{
foreach (var instrumentation in enabledInstrumentations)
{
switch (instrumentation)
{
case TracerInstrumentation.AspNet:
DelayedInitialization.Traces.AddAspNet(lazyInstrumentationLoader, pluginManager);
break;
case TracerInstrumentation.HttpClient:
DelayedInitialization.Traces.AddHttpClient(lazyInstrumentationLoader, pluginManager);
break;
case TracerInstrumentation.GrpcNetClient:
DelayedInitialization.Traces.AddGrpcClient(lazyInstrumentationLoader, pluginManager);
break;
case TracerInstrumentation.SqlClient:
DelayedInitialization.Traces.AddSqlClient(lazyInstrumentationLoader, pluginManager);
break;
case TracerInstrumentation.Wcf:
DelayedInitialization.Traces.AddWcf(lazyInstrumentationLoader, pluginManager);
break;
case TracerInstrumentation.Quartz:
DelayedInitialization.Traces.AddQuartz(lazyInstrumentationLoader, pluginManager);
break;
#if NET6_0_OR_GREATER
case TracerInstrumentation.MySqlData:
DelayedInitialization.Traces.AddMySqlClient(LazyInstrumentationLoader, pluginManager);
break;
case TracerInstrumentation.EntityFrameworkCore:
DelayedInitialization.Traces.AddEntityFrameworkCore(LazyInstrumentationLoader, pluginManager);
break;
case TracerInstrumentation.MongoDB:
break;
case TracerInstrumentation.StackExchangeRedis:
break;
case TracerInstrumentation.MassTransit:
break;
#endif
case TracerInstrumentation.GraphQL:
break;
case TracerInstrumentation.Npgsql:
break;
case TracerInstrumentation.NServiceBus:
break;
case TracerInstrumentation.Elasticsearch:
break;
default:
Logger.Warning($"Configured trace intrumentation type is not supported: {instrumentation}");
break;
}
}
}
private static void OnExit(object? sender, EventArgs e)
{
if (Interlocked.Exchange(ref _isExiting, value: 1) != 0)

View File

@ -0,0 +1,73 @@
// <copyright file="CustomSdkTests.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
#if NET6_0_OR_GREATER
using Google.Protobuf;
using IntegrationTests.Helpers;
using OpenTelemetry.Proto.Trace.V1;
using Xunit.Abstractions;
namespace IntegrationTests;
[Collection(RedisCollection.Name)]
public class CustomSdkTests : TestHelper
{
private readonly RedisFixture _redis;
public CustomSdkTests(ITestOutputHelper output, RedisFixture redis)
: base("CustomSdk", output)
{
_redis = redis;
}
[Fact]
[Trait("Category", "EndToEnd")]
[Trait("Containers", "Linux")]
public void SubmitsTraces_CustomSdk()
{
using var collector = new MockSpansCollector(Output);
SetExporter(collector);
// ensure spans are exported by custom sdk with custom resource
collector.ResourceExpector.Expect("test_attr", "added_manually");
collector.Expect("OpenTelemetry.Instrumentation.StackExchangeRedis", span => !IsTopLevel(span));
#if NET7_0_OR_GREATER
collector.Expect("System.Net.Http", span => !IsTopLevel(span));
#else
collector.Expect("OpenTelemetry.Instrumentation.Http.HttpClient", span => !IsTopLevel(span));
#endif
collector.Expect("TestApplication.CustomSdk", span => IsTopLevel(span));
EnableBytecodeInstrumentation();
SetEnvironmentVariable("OTEL_DOTNET_AUTO_SETUP_SDK", "false");
SetEnvironmentVariable("OTEL_EXPORTER_OTLP_PROTOCOL", "http/protobuf");
RunTestApplication(new()
{
Arguments = $"--redis {_redis.Port}"
});
collector.AssertExpectations();
collector.ResourceExpector.AssertExpectations();
}
private static bool IsTopLevel(Span span)
{
return span.ParentSpanId == ByteString.Empty;
}
}
#endif

View File

@ -0,0 +1,84 @@
// <copyright file="Program.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using System.Diagnostics;
using System.Net.Http;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using StackExchange.Redis;
using TestApplication.Shared;
namespace TestApplication.CustomSdk;
public static class Program
{
private static readonly ActivitySource ActivitySource = new(
"TestApplication.CustomSdk");
public static async Task Main(string[] args)
{
ConsoleHelper.WriteSplashScreen(args);
// if auto-instrumentation is not injecting sdk
// then it's client's code responsibility
// to subscribe to all activity sources
using var tracerProvider = Sdk
.CreateTracerProviderBuilder()
// bytecode instrumentation
.AddSource("OpenTelemetry.Instrumentation.StackExchangeRedis")
// lazily-loaded instrumentation
.AddSource("OpenTelemetry.Instrumentation.Http.HttpClient")
.AddSource("System.Net.Http") // This works only System.Net.Http >= 7.0.0
.AddLegacySource("System.Net.Http.HttpRequestOut")
// custom activity source
.AddSource("TestApplication.CustomSdk")
.ConfigureResource(builder =>
builder.AddAttributes(new[] { new KeyValuePair<string, object>("test_attr", "added_manually") }))
.AddOtlpExporter()
.AddConsoleExporter()
.Build();
var redisPort = GetRedisPort(args);
var connectionString = $@"127.0.0.1:{redisPort}";
using (var activity = ActivitySource.StartActivity("Manual"))
{
using (var connection = await ConnectionMultiplexer.ConnectAsync(connectionString))
{
var db = connection.GetDatabase();
db.Ping();
}
using var client = new HttpClient();
await client.GetStringAsync("https://www.bing.com");
}
Thread.Sleep(TimeSpan.FromSeconds(10));
}
private static string GetRedisPort(string[] args)
{
if (args.Length > 1)
{
return args[1];
}
return "6379";
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTelemetry" />
<PackageReference Include="OpenTelemetry.Api" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
<PackageReference Include="OpenTelemetry.Exporter.Console" />
<PackageReference Include="StackExchange.Redis"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\dependency-libs\TestApplication.Shared\TestApplication.Shared.csproj" />
</ItemGroup>
</Project>