diff --git a/.github/workflows/bootstrap/action.yml b/.github/workflows/bootstrap/action.yml
index a70b672..6ceef31 100644
--- a/.github/workflows/bootstrap/action.yml
+++ b/.github/workflows/bootstrap/action.yml
@@ -38,6 +38,9 @@ runs:
uses: actions/setup-dotnet@v4
with:
global-json-file: ./global.json
+ # 7.x is required for the dotnet-project-licenses tool.
+ dotnet-version: |
+ 7.x
- id: dotnet
shell: bash
diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml
index 631600c..cbd8535 100644
--- a/.github/workflows/ci-docs.yml
+++ b/.github/workflows/ci-docs.yml
@@ -27,7 +27,13 @@ jobs:
- run: 'echo "Not required for docs"'
# dummy steps that allow to bypass those mandatory checks for tests
- build:
+ test-linux:
+ runs-on: ubuntu-latest
+ steps:
+ - run: 'echo "Not required for docs"'
+
+ # dummy steps that allow to bypass those mandatory checks for tests
+ release-build:
runs-on: ubuntu-latest
steps:
- run: 'echo "Not required for docs"'
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 31da39d..563088b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -28,6 +28,7 @@ env:
# update ci-docs.yml
jobs:
test-windows:
+ name: Windows Tests
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
@@ -36,11 +37,12 @@ jobs:
id: bootstrap
uses: ./.github/workflows/bootstrap
- - name: Test
- run: build.bat test --test-suite=skip-e2e
+ - name: Unit Tests
+ run: build.bat test --test-suite=unit
shell: cmd
- build:
+ test-linux:
+ name: Linux Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -49,9 +51,19 @@ jobs:
id: bootstrap
uses: ./.github/workflows/bootstrap
- - name: Test
- run: ./build.sh test --test-suite=skip-e2e
+ - name: Unit Tests
+ run: ./build.sh test --test-suite=unit # For now, we limit to unit tests only, until we have a better way to run integration tests only for autoinstrumentation builds
+
+ # We still run the full release build on pull-requests this ensures packages are validated ahead of time
+ release-build:
+ name: Release Build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Bootstrap Action Workspace
+ id: bootstrap
+ uses: ./.github/workflows/bootstrap
- # We still run the full release build on pull-requests this ensures packages are validated ahead of time
- name: Release
run: ./build.sh release -c
\ No newline at end of file
diff --git a/build/build.fsproj b/build/build.fsproj
index 41c071b..271f9db 100644
--- a/build/build.fsproj
+++ b/build/build.fsproj
@@ -1,35 +1,37 @@
+
net9.0
Exe
$(NoWarn);NU1701
false
+
-
-
+
+
-
-
-
-
+
+
+
+
-
+
-
-
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/build/scripts/CommandLine.fs b/build/scripts/CommandLine.fs
index 4be8fd7..7b0ac5a 100644
--- a/build/scripts/CommandLine.fs
+++ b/build/scripts/CommandLine.fs
@@ -75,7 +75,6 @@ with
| Skip_Dirty_Check -> "Skip the clean checkout check that guards the release/publish targets"
| Test_Suite _ -> "Specify the test suite to run, defaults to all"
-
member this.StepName =
match FSharpValue.GetUnionFields(this, typeof) with
| case, _ -> case.Name.ToLowerInvariant()
diff --git a/examples/Example.AspNetCore.Mvc/Example.AspNetCore.Mvc.csproj b/examples/Example.AspNetCore.Mvc/Example.AspNetCore.Mvc.csproj
index 837362b..0ff4122 100644
--- a/examples/Example.AspNetCore.Mvc/Example.AspNetCore.Mvc.csproj
+++ b/examples/Example.AspNetCore.Mvc/Example.AspNetCore.Mvc.csproj
@@ -1,10 +1,11 @@
-
+
- net8.0
+ net9.0
enable
enable
Linux
+ 1efafe93-6112-431d-b30f-786205a20ebe
@@ -13,7 +14,7 @@
-
+
diff --git a/examples/Example.AspNetCore.Mvc/Program.cs b/examples/Example.AspNetCore.Mvc/Program.cs
index 035d661..48dc787 100644
--- a/examples/Example.AspNetCore.Mvc/Program.cs
+++ b/examples/Example.AspNetCore.Mvc/Program.cs
@@ -2,18 +2,29 @@
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
-using Example.AspNetCore.Mvc.Controllers;
using OpenTelemetry;
+using OpenTelemetry.Resources;
var builder = WebApplication.CreateBuilder(args);
-builder.AddServiceDefaults();
+using var loggerFactory = LoggerFactory.Create(loggingBuilder => loggingBuilder
+ .SetMinimumLevel(LogLevel.Trace)
+ .AddConsole());
+
+var logger = loggerFactory.CreateLogger("OpenTelemetry");
// Add services to the container.
builder.Services
.AddHttpClient()
.AddOpenTelemetry()
- .WithTracing(t => t.AddSource(HomeController.ActivitySourceName));
+ .ConfigureResource(r => r.AddService("MyNewService1"))
+ .WithElasticDefaults(builder.Configuration);
+
+builder.Services.AddOpenTelemetry()
+ .ConfigureResource(r => r.AddService("MyNewService2"))
+ .WithElasticDefaults(builder.Configuration);
+
+//OpenTelemetrySdk.Create(b => b.WithElasticDefaults(builder.Configuration));
builder.Services
.AddControllersWithViews();
diff --git a/examples/Example.AspNetCore.Mvc/Properties/launchSettings.json b/examples/Example.AspNetCore.Mvc/Properties/launchSettings.json
index 8e18550..69ae136 100644
--- a/examples/Example.AspNetCore.Mvc/Properties/launchSettings.json
+++ b/examples/Example.AspNetCore.Mvc/Properties/launchSettings.json
@@ -9,6 +9,9 @@
"https": {
"commandName": "Project",
"launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7295;http://localhost:5247"
},
diff --git a/examples/Example.AspNetCore.Mvc/appsettings.json b/examples/Example.AspNetCore.Mvc/appsettings.json
index 5033b13..0ff52be 100644
--- a/examples/Example.AspNetCore.Mvc/appsettings.json
+++ b/examples/Example.AspNetCore.Mvc/appsettings.json
@@ -2,8 +2,7 @@
"Logging": {
"LogLevel": {
"Default": "Information",
- "Microsoft.AspNetCore": "Warning",
- "Elastic.OpenTelemetry": "Information"
+ "Microsoft.AspNetCore": "Warning"
},
"OpenTelemetry": {
"IncludeFormattedMessage": true,
@@ -11,5 +10,11 @@
"ParseStateValues": true
}
},
- "AllowedHosts": "*"
+ "AllowedHosts": "*",
+ "Elastic": {
+ "OpenTelemetry": {
+ "LogLevel": "Trace",
+ "LogDirectory": "C:\\Logs\\BrandNewLogs"
+ }
+ }
}
diff --git a/examples/Example.AutoInstrumentation/Example.AutoInstrumentation.csproj b/examples/Example.AutoInstrumentation/Example.AutoInstrumentation.csproj
index 2a040bd..e8c41ec 100644
--- a/examples/Example.AutoInstrumentation/Example.AutoInstrumentation.csproj
+++ b/examples/Example.AutoInstrumentation/Example.AutoInstrumentation.csproj
@@ -2,7 +2,7 @@
Exe
- net8.0
+ net9.0
enable
enable
Linux
diff --git a/examples/Example.Console/Example.Console.csproj b/examples/Example.Console/Example.Console.csproj
index e1e708b..f0eae0e 100644
--- a/examples/Example.Console/Example.Console.csproj
+++ b/examples/Example.Console/Example.Console.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/examples/Example.Console/Usage.cs b/examples/Example.Console/Usage.cs
index 7877e5f..ca01ff3 100644
--- a/examples/Example.Console/Usage.cs
+++ b/examples/Example.Console/Usage.cs
@@ -3,8 +3,6 @@
// See the LICENSE file in the project root for more information
using System.Diagnostics;
-using Elastic.OpenTelemetry;
-using Elastic.OpenTelemetry.Extensions;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
@@ -21,45 +19,50 @@ public static async Task BasicBuilderUsageAsync()
{
// NOTE: This sample assumes ENV VARs have been set to configure the Endpoint and Authorization header.
- // Build an instrumentation session by creating an ElasticOpenTelemetryBuilder.
- // The application will be instrumented until the session is disposed.
- await using var session = new ElasticOpenTelemetryBuilder()
- .WithTracing(b => b.AddSource(ActivitySourceName))
- .Build();
+ //// Build an instrumentation session by creating an ElasticOpenTelemetryBuilder.
+ //// The application will be instrumented until the session is disposed.
+ //await using var session = new ElasticOpenTelemetryBuilder()
+ // .WithTracing(b => b.AddSource(ActivitySourceName))
+ // .Build();
- await using var session2 = new ElasticOpenTelemetryBuilder().Build();
+ //await using var session2 = new ElasticOpenTelemetryBuilder().Build();
- // This example adds the application activity source and fully customises the resource
- await using var session3 = new ElasticOpenTelemetryBuilder()
- .WithTracing(b => b
- .AddSource(ActivitySourceName)
- .ConfigureResource(r => r.Clear().AddService("CustomServiceName", serviceVersion: "2.2.2")))
- .Build();
+ //// This example adds the application activity source and fully customises the resource
+ //await using var session3 = new ElasticOpenTelemetryBuilder()
+ // .WithTracing(b => b
+ // .AddSource(ActivitySourceName)
+ // .ConfigureResource(r => r.Clear().AddService("CustomServiceName", serviceVersion: "2.2.2")))
+ // .Build();
- await using var session4 = new ElasticOpenTelemetryBuilder()
- .WithTracing(t => t
- .ConfigureResource(rb => rb.AddService("TracerProviderBuilder", "3.3.3"))
- .AddRedisInstrumentation() // This can currently only be achieved using this overload or adding Elastic processors to the TPB (as below)
- .AddSource(ActivitySourceName)
- .AddConsoleExporter()
- )
- .WithTracing(tpb => tpb
- .ConfigureResource(rb => rb.AddService("TracerProviderBuilder", "3.3.3"))
- .AddRedisInstrumentation() // This can currently only be achieved using this overload or adding Elastic processors to the TPB (as below)
- .AddSource(ActivitySourceName)
- .AddConsoleExporter())
- .Build();
+ //await using var session4 = new ElasticOpenTelemetryBuilder()
+ // .WithTracing(t => t
+ // .ConfigureResource(rb => rb.AddService("TracerProviderBuilder", "3.3.3"))
+ // .AddRedisInstrumentation() // This can currently only be achieved using this overload or adding Elastic processors to the TPB (as below)
+ // .AddSource(ActivitySourceName)
+ // .AddConsoleExporter()
+ // )
+ // .WithTracing(tpb => tpb
+ // .ConfigureResource(rb => rb.AddService("TracerProviderBuilder", "3.3.3"))
+ // .AddRedisInstrumentation() // This can currently only be achieved using this overload or adding Elastic processors to the TPB (as below)
+ // .AddSource(ActivitySourceName)
+ // .AddConsoleExporter())
+ // .Build();
- //This is the most flexible approach for a consumer as they can include our processor(s) and exporter(s)
- using var tracerProvider = Sdk.CreateTracerProviderBuilder()
- .AddSource(ActivitySourceName)
- .ConfigureResource(resource =>
- resource.AddService(
- serviceName: "OtelSdkApp",
- serviceVersion: "1.0.0"))
- .AddConsoleExporter()
- .AddElasticProcessors()
- .Build();
+ using var sdk = OpenTelemetrySdk.Create(builder => builder
+ .WithElasticMetrics()
+ .WithElasticMetrics()
+ .ConfigureResource(resource => resource.AddService("MyCustomServiceName")));
+
+ //This is the most flexible approach for a consumer as they can include our processor(s)
+ //using var tracerProvider = Sdk.CreateTracerProviderBuilder()
+ // .AddSource(ActivitySourceName)
+ // .ConfigureResource(resource =>
+ // resource.AddService(
+ // serviceName: "OtelSdkApp",
+ // serviceVersion: "1.0.0"))
+ // .AddConsoleExporter()
+ // .AddElasticProcessors()
+ // .Build();
await DoStuffAsync();
diff --git a/examples/Example.MinimalApi/Example.MinimalApi.csproj b/examples/Example.MinimalApi/Example.MinimalApi.csproj
index d48e6b0..e322683 100644
--- a/examples/Example.MinimalApi/Example.MinimalApi.csproj
+++ b/examples/Example.MinimalApi/Example.MinimalApi.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/examples/Example.MinimalApi/Program.cs b/examples/Example.MinimalApi/Program.cs
index 7489ac0..46215a7 100644
--- a/examples/Example.MinimalApi/Program.cs
+++ b/examples/Example.MinimalApi/Program.cs
@@ -8,12 +8,14 @@
var builder = WebApplication.CreateBuilder(args);
+//builder.AddElasticOpenTelemetry();
+
// This will add the OpenTelemetry services using Elastic defaults
builder.AddServiceDefaults();
builder.Services
.AddHttpClient() // Adds IHttpClientFactory
- .AddOpenTelemetry() // Adds app specific tracing
+ .AddElasticOpenTelemetry() // Adds app specific tracing
.WithTracing(t => t.AddSource(Api.ActivitySourceName));
var app = builder.Build();
diff --git a/examples/Example.MinimalApi/Properties/launchSettings.json b/examples/Example.MinimalApi/Properties/launchSettings.json
index cb647e9..dc8153d 100644
--- a/examples/Example.MinimalApi/Properties/launchSettings.json
+++ b/examples/Example.MinimalApi/Properties/launchSettings.json
@@ -28,7 +28,9 @@
"applicationUrl": "https://localhost:7140;http://localhost:5146",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
- "OTEL_RESOURCE_ATTRIBUTES": "service.name=minimal-api-example"
+ "OTEL_RESOURCE_ATTRIBUTES": "service.name=minimal-api-example",
+ "OTEL_EXPORTER_OTLP_ENDPOINT": "https://opentelemetry-playground-adbd73.apm.eu-west-1.aws.elastic.cloud:443",
+ "OTEL_EXPORTER_OTLP_HEADERS": "Authorization=ApiKey cVY3d3NKTUJXcWZFRWJwb2xURjA6bmNrZ0JiQ29SRWlEdUM1dzVORGYwZw=="
}
},
"IIS Express": {
diff --git a/examples/Example.MinimalApi/appsettings.Development.json b/examples/Example.MinimalApi/appsettings.Development.json
index 0c208ae..b06e135 100644
--- a/examples/Example.MinimalApi/appsettings.Development.json
+++ b/examples/Example.MinimalApi/appsettings.Development.json
@@ -2,7 +2,8 @@
"Logging": {
"LogLevel": {
"Default": "Information",
- "Microsoft.AspNetCore": "Warning"
+ "Microsoft.AspNetCore": "Warning",
+ "Elastic.OpenTelemetry": "Trace"
}
}
}
diff --git a/examples/Example.WorkerService/Example.WorkerService.csproj b/examples/Example.WorkerService/Example.WorkerService.csproj
index e0aefbd..481bfc2 100644
--- a/examples/Example.WorkerService/Example.WorkerService.csproj
+++ b/examples/Example.WorkerService/Example.WorkerService.csproj
@@ -8,8 +8,8 @@
-
-
+
+
diff --git a/examples/Example.WorkerService/Program.cs b/examples/Example.WorkerService/Program.cs
index cc417be..6596be7 100644
--- a/examples/Example.WorkerService/Program.cs
+++ b/examples/Example.WorkerService/Program.cs
@@ -10,7 +10,7 @@
var builder = Host.CreateApplicationBuilder(args);
-builder.Services.AddOpenTelemetry()
+builder.Services.AddElasticOpenTelemetry()
.ConfigureResource(r => r.AddService(serviceName: "MyService"))
.WithTracing(t => t.AddSource(Worker.ActivitySourceName).AddConsoleExporter())
.WithMetrics(m => m.AddMeter(Worker.MeterName).AddConsoleExporter());
diff --git a/examples/ServiceDefaults/Extensions.cs b/examples/ServiceDefaults/Extensions.cs
index a142d88..36f184f 100644
--- a/examples/ServiceDefaults/Extensions.cs
+++ b/examples/ServiceDefaults/Extensions.cs
@@ -6,9 +6,7 @@
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
-using Microsoft.Extensions.Logging;
using OpenTelemetry;
-using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
// ReSharper disable once CheckNamespace
@@ -38,20 +36,8 @@ public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBu
public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder)
{
- builder.Logging.AddOpenTelemetry(logging =>
- {
- logging.IncludeFormattedMessage = true;
- logging.IncludeScopes = true;
- });
-
builder.Services.AddElasticOpenTelemetry(builder.Configuration)
- .WithMetrics(metrics =>
- {
- metrics.AddAspNetCoreInstrumentation()
- .AddHttpClientInstrumentation()
- .AddProcessInstrumentation()
- .AddRuntimeInstrumentation();
- })
+ .WithMetrics()
.WithTracing(tracing =>
{
if (builder.Environment.IsDevelopment())
@@ -59,10 +45,6 @@ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicati
// We want to view all traces in development
tracing.SetSampler(new AlwaysOnSampler());
}
-
- tracing.AddAspNetCoreInstrumentation()
- .AddGrpcClientInstrumentation()
- .AddHttpClientInstrumentation();
});
builder.AddOpenTelemetryExporters();
@@ -86,8 +68,8 @@ private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostAppli
// Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
//if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
//{
- // builder.Services.AddOpenTelemetry()
- // .UseAzureMonitor();
+ //builder.Services.AddOpenTelemetry()
+ // .UseAzureMonitor();
//}
builder;
diff --git a/examples/ServiceDefaults/ServiceDefaults.csproj b/examples/ServiceDefaults/ServiceDefaults.csproj
index 2d20800..b1c2cad 100644
--- a/examples/ServiceDefaults/ServiceDefaults.csproj
+++ b/examples/ServiceDefaults/ServiceDefaults.csproj
@@ -10,15 +10,15 @@
-
+
-
-
+
+
-
-
-
-
+
+
+
+
diff --git a/src/Elastic.OpenTelemetry/AutoInstrumentationPlugin.cs b/src/Elastic.OpenTelemetry/AutoInstrumentationPlugin.cs
deleted file mode 100644
index 6bec4b5..0000000
--- a/src/Elastic.OpenTelemetry/AutoInstrumentationPlugin.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-// Licensed to Elasticsearch B.V under one or more agreements.
-// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
-// See the LICENSE file in the project root for more information
-
-using System.Diagnostics.Tracing;
-using Elastic.OpenTelemetry.Configuration;
-using Elastic.OpenTelemetry.Extensions;
-using Microsoft.Extensions.Logging;
-using OpenTelemetry.Logs;
-using OpenTelemetry.Metrics;
-using OpenTelemetry.Resources;
-using OpenTelemetry.Trace;
-
-namespace Elastic.OpenTelemetry;
-
-///
-/// Elastic Distribution of OpenTelemetry .NET plugin for Auto Instrumentation.
-/// Ensures all signals are rich enough to report to Elastic
-///
-// ReSharper disable once UnusedType.Global
-public class AutoInstrumentationPlugin
-{
- private readonly ILogger _logger;
- private readonly EventListener _eventListener;
-
- private readonly bool _skipOtlp;
-
- ///
- public AutoInstrumentationPlugin()
- {
- var options = new ElasticOpenTelemetryBuilderOptions();
- var (eventListener, logger) = ElasticOpenTelemetryBuilder.Bootstrap(options);
-
- _logger = logger;
- _eventListener = eventListener;
-
- var skipOtlpString = Environment.GetEnvironmentVariable("ELASTIC_OTEL_SKIP_OTLP_EXPORTER");
-
- if (skipOtlpString is not null && bool.TryParse(skipOtlpString, out var skipOtlp))
- _skipOtlp = skipOtlp;
- }
-
- /// To access TracerProvider right after TracerProviderBuilder.Build() is executed.
- public void TracerProviderInitialized(TracerProvider tracerProvider)
- {
- }
-
- /// To access MeterProvider right after MeterProviderBuilder.Build() is executed.
- public void MeterProviderInitialized(MeterProvider meterProvider)
- {
- }
-
- /// To configure tracing SDK before Auto Instrumentation configured SDK
- public TracerProviderBuilder BeforeConfigureTracerProvider(TracerProviderBuilder builder) =>
- builder.UseAutoInstrumentationElasticDefaults(_skipOtlp, _logger);
-
- /// To configure tracing SDK after Auto Instrumentation configured SDK
- public TracerProviderBuilder AfterConfigureTracerProvider(TracerProviderBuilder builder) =>
- builder;
-
- /// To configure metrics SDK before Auto Instrumentation configured SDK
- public MeterProviderBuilder BeforeConfigureMeterProvider(MeterProviderBuilder builder) =>
- builder.UseElasticDefaults(_skipOtlp, _logger);
-
- /// To configure metrics SDK after Auto Instrumentation configured SDK
- public MeterProviderBuilder AfterConfigureMeterProvider(MeterProviderBuilder builder) =>
- builder;
-
- /// To configure logs SDK (the method name is the same as for other logs options)
- public void ConfigureLogsOptions(OpenTelemetryLoggerOptions options) =>
- options.UseElasticDefaults(_logger);
-
- /// To configure Resource
- public ResourceBuilder ConfigureResource(ResourceBuilder builder) =>
- builder.UseElasticDefaults(_logger);
-}
diff --git a/src/Elastic.OpenTelemetry/Configuration/CompositeElasticOpenTelemetryOptions.cs b/src/Elastic.OpenTelemetry/Configuration/CompositeElasticOpenTelemetryOptions.cs
new file mode 100644
index 0000000..29f67d3
--- /dev/null
+++ b/src/Elastic.OpenTelemetry/Configuration/CompositeElasticOpenTelemetryOptions.cs
@@ -0,0 +1,302 @@
+// Licensed to Elasticsearch B.V under one or more agreements.
+// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information
+
+using System.Collections;
+using System.Diagnostics.Tracing;
+using System.Runtime.InteropServices;
+using Elastic.OpenTelemetry.Configuration.Instrumentations;
+using Elastic.OpenTelemetry.Configuration.Parsers;
+using Elastic.OpenTelemetry.Diagnostics;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using static System.Environment;
+using static System.Runtime.InteropServices.RuntimeInformation;
+using static Elastic.OpenTelemetry.Configuration.EnvironmentVariables;
+using static Elastic.OpenTelemetry.Configuration.Parsers.SharedParsers;
+
+namespace Elastic.OpenTelemetry.Configuration;
+
+///
+/// Defines advanced options which can be used to finely-tune the behaviour of the Elastic
+/// distribution of OpenTelemetry.
+///
+///
+/// Options are bound from the following sources:
+///
+/// - Environment variables
+/// - An instance
+///
+/// Options initialised via property initializers take precedence over bound values.
+/// Environment variables take precedence over values.
+///
+internal sealed class CompositeElasticOpenTelemetryOptions
+{
+ private readonly EventLevel _eventLevel = EventLevel.Informational;
+
+ private readonly ConfigCell _logDirectory = new(nameof(LogDirectory), null);
+ private readonly ConfigCell _logTargets = new(nameof(LogTargets), null);
+
+ private readonly ConfigCell _logLevel = new(nameof(LogLevel), LogLevel.Warning);
+ private readonly ConfigCell _skipOtlpExporter = new(nameof(SkipOtlpExporter), false);
+ private readonly ConfigCell _runningInContainer = new(nameof(_runningInContainer), false);
+
+ private readonly ConfigCell _signals = new(nameof(Signals), Signals.All);
+ private readonly ConfigCell _tracing = new(nameof(Tracing), TraceInstrumentations.All);
+ private readonly ConfigCell _metrics = new(nameof(Metrics), MetricInstrumentations.All);
+ private readonly ConfigCell _logging = new(nameof(Logging), LogInstrumentations.All);
+
+ private readonly IDictionary _environmentVariables;
+
+ internal static CompositeElasticOpenTelemetryOptions DefaultOptions = new();
+ internal static CompositeElasticOpenTelemetryOptions SkipOtlpOptions = new() { SkipOtlpExporter = true };
+
+ ///
+ /// Creates a new instance of with properties
+ /// bound from environment variables.
+ ///
+ internal CompositeElasticOpenTelemetryOptions() : this((IDictionary?)null)
+ {
+ }
+
+ internal CompositeElasticOpenTelemetryOptions(IDictionary? environmentVariables)
+ {
+ LogDirectoryDefault = GetDefaultLogDirectory();
+ _environmentVariables = environmentVariables ?? GetEnvironmentVariables();
+
+ SetFromEnvironment(DOTNET_RUNNING_IN_CONTAINER, _runningInContainer, BoolParser);
+ SetFromEnvironment(OTEL_DOTNET_AUTO_LOG_DIRECTORY, _logDirectory, StringParser);
+ SetFromEnvironment(OTEL_LOG_LEVEL, _logLevel, LogLevelParser);
+ SetFromEnvironment(ELASTIC_OTEL_LOG_TARGETS, _logTargets, LogTargetsParser);
+ SetFromEnvironment(ELASTIC_OTEL_SKIP_OTLP_EXPORTER, _skipOtlpExporter, BoolParser);
+
+ var parser = new EnvironmentParser(_environmentVariables);
+ parser.ParseInstrumentationVariables(_signals, _tracing, _metrics, _logging);
+ }
+
+ internal CompositeElasticOpenTelemetryOptions(IConfiguration? configuration, IDictionary? environmentVariables = null)
+ : this(environmentVariables)
+ {
+ if (configuration is null)
+ return;
+
+ var parser = new ConfigurationParser(configuration);
+
+ parser.ParseLogDirectory(_logDirectory);
+ parser.ParseLogTargets(_logTargets);
+ parser.ParseLogLevel(_logLevel, ref _eventLevel);
+ parser.ParseSkipOtlpExporter(_skipOtlpExporter);
+ }
+
+ internal CompositeElasticOpenTelemetryOptions(ElasticOpenTelemetryOptions options)
+ : this((IDictionary?)null)
+ {
+ if (options is null)
+ return;
+
+ // Having configured the base settings from env vars, we now override anything that was
+ // explicitly configured in the user provided options.
+
+ if (options.SkipOtlpExporter.HasValue)
+ _skipOtlpExporter.Assign(options.SkipOtlpExporter.Value, ConfigSource.Options);
+
+ if (!string.IsNullOrEmpty(options.LogDirectory))
+ _logDirectory.Assign(options.LogDirectory, ConfigSource.Options);
+
+ if (options.LogLevel.HasValue)
+ _logLevel.Assign(options.LogLevel.Value, ConfigSource.Options);
+
+ if (options.LogTargets.HasValue)
+ _logTargets.Assign(options.LogTargets.Value, ConfigSource.Options);
+
+ AdditionalLogger = options.AdditionalLogger ?? options.AdditionalLoggerFactory?.CreateElasticLogger();
+ }
+
+ internal CompositeElasticOpenTelemetryOptions(IConfiguration configuration, ILoggerFactory loggerFactory) :
+ this(configuration) => AdditionalLogger = loggerFactory?.CreateElasticLogger();
+
+ ///
+ /// Calculates whether global logging is enabled based on
+ /// , and
+ ///
+ internal bool GlobalLogEnabled
+ {
+ get
+ {
+ var level = _logLevel.Value;
+ var targets = _logTargets.Value;
+ var isActive = level is <= LogLevel.Debug || !string.IsNullOrWhiteSpace(_logDirectory.Value) || targets.HasValue;
+ if (!isActive)
+ return isActive;
+
+ if (level is LogLevel.None)
+ isActive = false;
+ else if (targets is LogTargets.None)
+ isActive = false;
+ return isActive;
+ }
+ }
+
+ private static string GetDefaultLogDirectory()
+ {
+ var applicationMoniker = "elastic-otel-dotnet";
+ if (IsOSPlatform(OSPlatform.Windows))
+ return Path.Combine(GetFolderPath(SpecialFolder.ApplicationData), "elastic", applicationMoniker);
+ if (IsOSPlatform(OSPlatform.OSX))
+ return Path.Combine(GetFolderPath(SpecialFolder.LocalApplicationData), "elastic", applicationMoniker);
+
+ return $"/var/log/elastic/{applicationMoniker}";
+ }
+
+ ///
+ /// The default log directory if file logging was enabled but non was specified
+ /// Defaults to:
+ /// - %PROGRAMDATA%\elastic\apm-agent-dotnet (on Windows)
+ /// - /var/log/elastic/apm-agent-dotnet (on Linux)
+ /// - ~/Library/Application_Support/elastic/apm-agent-dotnet (on OSX)
+ ///
+ internal string LogDirectoryDefault { get; }
+
+ ///
+ public string LogDirectory
+ {
+ get => _logDirectory.Value ?? LogDirectoryDefault;
+ init => _logDirectory.Assign(value, ConfigSource.Property);
+ }
+
+ ///
+ /// Used by to determine the appropiate event level to subscribe to
+ ///
+ internal EventLevel EventLogLevel => _eventLevel;
+
+ ///
+ public LogLevel LogLevel
+ {
+ get => _logLevel.Value ?? LogLevel.Warning;
+ init => _logLevel.Assign(value, ConfigSource.Property);
+ }
+
+ ///
+ public LogTargets LogTargets
+ {
+ get => _logTargets.Value ?? (GlobalLogEnabled
+ ? _runningInContainer.Value.HasValue && _runningInContainer.Value.Value ? LogTargets.StdOut : LogTargets.File
+ : LogTargets.None);
+ init => _logTargets.Assign(value, ConfigSource.Property);
+ }
+
+ ///
+ public bool SkipOtlpExporter
+ {
+ get => _skipOtlpExporter.Value ?? false;
+ init => _skipOtlpExporter.Assign(value, ConfigSource.Property);
+ }
+
+ public ILogger? AdditionalLogger { get; internal set; }
+
+ ///
+ /// Control which signals will be automatically enabled by the Elastic Distribution of OpenTelemetry .NET.
+ ///
+ /// This configuration respects the open telemetry environment configuration out of the box:
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Setting this propery in code or configuration will take precedence over environment variables.
+ ///
+ public Signals Signals
+ {
+ get => _signals.Value ?? Signals.All;
+ init => _signals.Assign(value, ConfigSource.Property);
+ }
+
+ ///
+ /// Enabled trace instrumentations.
+ ///
+ public TraceInstrumentations Tracing
+ {
+ get => _tracing.Value ?? TraceInstrumentations.All;
+ init => _tracing.Assign(value, ConfigSource.Property);
+ }
+
+ ///
+ /// Enabled trace instrumentations.
+ ///
+ public MetricInstrumentations Metrics
+ {
+ get => _metrics.Value ?? MetricInstrumentations.All;
+ init => _metrics.Assign(value, ConfigSource.Property);
+ }
+
+ ///
+ /// Enabled trace instrumentations.
+ ///
+ public LogInstrumentations Logging
+ {
+ get => _logging.Value ?? LogInstrumentations.All;
+ init => _logging.Assign(value, ConfigSource.Property);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (obj is not CompositeElasticOpenTelemetryOptions other)
+ return false;
+
+ return LogDirectory == other.LogDirectory &&
+ LogLevel == other.LogLevel &&
+ LogTargets == other.LogTargets &&
+ SkipOtlpExporter == other.SkipOtlpExporter &&
+ Signals == other.Signals &&
+ Tracing.SetEquals(other.Tracing) &&
+ Metrics.SetEquals(other.Metrics) &&
+ Logging.SetEquals(other.Logging) &&
+ ReferenceEquals(AdditionalLogger, other.AdditionalLogger);
+ }
+
+ public override int GetHashCode()
+ {
+#if NET462 || NETSTANDARD2_0
+ return LogDirectory.GetHashCode()
+ ^ LogLevel.GetHashCode()
+ ^ LogTargets.GetHashCode()
+ ^ SkipOtlpExporter.GetHashCode()
+ ^ Signals.GetHashCode()
+ ^ Tracing.GetHashCode()
+ ^ Metrics.GetHashCode()
+ ^ Logging.GetHashCode()
+ ^ (AdditionalLogger?.GetHashCode() ?? 0);
+#else
+ var hash1 = HashCode.Combine(LogDirectory, LogLevel, LogTargets, SkipOtlpExporter);
+ var hash2 = HashCode.Combine(Signals, Tracing, Metrics, Logging, AdditionalLogger);
+ return HashCode.Combine(hash1, hash2);
+#endif
+ }
+
+ private void SetFromEnvironment(string key, ConfigCell field, Func parser)
+ {
+ var value = parser(GetSafeEnvironmentVariable(key));
+ if (value is null)
+ return;
+
+ field.Assign(value, ConfigSource.Environment);
+ }
+
+ private string GetSafeEnvironmentVariable(string key)
+ {
+ var value = _environmentVariables.Contains(key) ? _environmentVariables[key]?.ToString() : null;
+ return value ?? string.Empty;
+ }
+
+ internal void LogConfigSources(ILogger logger)
+ {
+ logger.LogInformation("Configured value for {Configuration}", _logDirectory);
+ logger.LogInformation("Configured value for {Configuration}", _logLevel);
+ logger.LogInformation("Configured value for {Configuration}", _skipOtlpExporter);
+ logger.LogInformation("Configured value for {Configuration}", _signals);
+ logger.LogInformation("Configured value for {Configuration}", _tracing);
+ logger.LogInformation("Configured value for {Configuration}", _metrics);
+ logger.LogInformation("Configured value for {Configuration}", _logging);
+ }
+}
diff --git a/src/Elastic.OpenTelemetry/Configuration/ConfigCell.cs b/src/Elastic.OpenTelemetry/Configuration/ConfigCell.cs
index f140cfd..159f6fc 100644
--- a/src/Elastic.OpenTelemetry/Configuration/ConfigCell.cs
+++ b/src/Elastic.OpenTelemetry/Configuration/ConfigCell.cs
@@ -18,11 +18,3 @@ public void Assign(T value, ConfigSource source)
public override string ToString() => $"{Key}: '{Value}' from [{Source}]";
}
-internal enum ConfigSource
-{
- Default, // Default value assigned within this class
- Environment, // Loaded from an environment variable
- // ReSharper disable once InconsistentNaming
- IConfiguration, // Bound from an IConfiguration instance
- Property // Set via property initializer
-}
diff --git a/src/Elastic.OpenTelemetry/Configuration/ConfigSource.cs b/src/Elastic.OpenTelemetry/Configuration/ConfigSource.cs
new file mode 100644
index 0000000..aecbcd8
--- /dev/null
+++ b/src/Elastic.OpenTelemetry/Configuration/ConfigSource.cs
@@ -0,0 +1,15 @@
+// Licensed to Elasticsearch B.V under one or more agreements.
+// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information
+
+namespace Elastic.OpenTelemetry.Configuration;
+
+internal enum ConfigSource
+{
+ Default, // Default value assigned within this class
+ Environment, // Loaded from an environment variable
+ // ReSharper disable once InconsistentNaming
+ IConfiguration, // Bound from an IConfiguration instance
+ Property, // Set via property initializer
+ Options // Set via user provided ElasticOpenTelemetryOptions
+}
diff --git a/src/Elastic.OpenTelemetry/Configuration/ElasticDefaults.cs b/src/Elastic.OpenTelemetry/Configuration/ElasticDefaults.cs
deleted file mode 100644
index 3bc90f9..0000000
--- a/src/Elastic.OpenTelemetry/Configuration/ElasticDefaults.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Licensed to Elasticsearch B.V under one or more agreements.
-// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
-// See the LICENSE file in the project root for more information
-
-namespace Elastic.OpenTelemetry.Configuration;
-
-///
-/// Control which elastic defaults you want to include.
-/// NOTE: this is an expert level option only use this if you want to take full control of the OTEL configuration
-/// defaults to
-///
-[Flags]
-public enum ElasticDefaults
-{
- /// No Elastic defaults will be included, acting effectively as a vanilla OpenTelemetry
- None,
-
- /// Include Elastic Distribution of OpenTelemetry .NET tracing defaults
- Traces = 1 << 0, //1
-
- /// Include Elastic Distribution of OpenTelemetry .NET metrics defaults
- Metrics = 1 << 1, //2
-
- /// Include Elastic Distribution of OpenTelemetry .NET logging defaults
- Logs = 1 << 2, //4
-
- /// (default) Include all Elastic Distribution of OpenTelemetry .NET logging defaults
- All = ~0
-}
diff --git a/src/Elastic.OpenTelemetry/Configuration/ElasticOpenTelemetryBuilderOptions.cs b/src/Elastic.OpenTelemetry/Configuration/ElasticOpenTelemetryBuilderOptions.cs
deleted file mode 100644
index 50a547b..0000000
--- a/src/Elastic.OpenTelemetry/Configuration/ElasticOpenTelemetryBuilderOptions.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Licensed to Elasticsearch B.V under one or more agreements.
-// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
-// See the LICENSE file in the project root for more information
-
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
-
-namespace Elastic.OpenTelemetry.Configuration;
-
-///
-/// Expert options to provide to to control its initial OpenTelemetry registration.
-///
-public record ElasticOpenTelemetryBuilderOptions
-{
- private ElasticOpenTelemetryOptions? _elasticOpenTelemetryOptions;
-
- ///
- /// Provide an additional logger to the internal file logger.
- ///
- /// The distribution will always log to file if a path is provided using the ELASTIC_OTEL_LOG_DIRECTORY.
- /// environment variable.
- ///
- public ILogger? Logger { get; init; }
-
- ///
- /// Provides an to register the into.
- /// If null, a new local instance will be used.
- ///
- internal IServiceCollection? Services { get; init; }
-
- private static readonly ElasticOpenTelemetryOptions DefaultDistroOptions = new();
- ///
- /// Advanced options which can be used to finely-tune the behaviour of the Elastic
- /// distribution of OpenTelemetry.
- ///
- public ElasticOpenTelemetryOptions DistroOptions
- {
- get => _elasticOpenTelemetryOptions ?? DefaultDistroOptions;
- init => _elasticOpenTelemetryOptions = value;
- }
-}
diff --git a/src/Elastic.OpenTelemetry/Configuration/ElasticOpenTelemetryOptions.cs b/src/Elastic.OpenTelemetry/Configuration/ElasticOpenTelemetryOptions.cs
index 57ec5a4..8706d85 100644
--- a/src/Elastic.OpenTelemetry/Configuration/ElasticOpenTelemetryOptions.cs
+++ b/src/Elastic.OpenTelemetry/Configuration/ElasticOpenTelemetryOptions.cs
@@ -2,137 +2,19 @@
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
-using System.Collections;
-using System.Diagnostics.Tracing;
-using System.Runtime.InteropServices;
-using Elastic.OpenTelemetry.Configuration.Instrumentations;
-using Elastic.OpenTelemetry.Configuration.Parsers;
-using Elastic.OpenTelemetry.Diagnostics;
-using Microsoft.Extensions.Configuration;
+using Elastic.OpenTelemetry.Configuration;
using Microsoft.Extensions.Logging;
-using static System.Environment;
-using static System.Runtime.InteropServices.RuntimeInformation;
-using static Elastic.OpenTelemetry.Configuration.EnvironmentVariables;
-using static Elastic.OpenTelemetry.Configuration.Parsers.SharedParsers;
-namespace Elastic.OpenTelemetry.Configuration;
+#pragma warning disable IDE0130 // Namespace does not match folder structure
+namespace Elastic.OpenTelemetry;
+#pragma warning restore IDE0130 // Namespace does not match folder structure
///
-/// Defines advanced options which can be used to finely-tune the behaviour of the Elastic
+/// Defines options which can be used to finely-tune the behaviour of the Elastic
/// distribution of OpenTelemetry.
///
-///
-/// Options are bound from the following sources:
-///
-/// - Environment variables
-/// - An instance
-///
-/// Options initialised via property initializers take precedence over bound values.
-/// Environment variables take precedence over values.
-///
public class ElasticOpenTelemetryOptions
{
- private readonly ConfigCell _logDirectory = new(nameof(LogDirectory), null);
- private readonly ConfigCell _logTargets = new(nameof(LogTargets), null);
-
- private readonly EventLevel _eventLevel = EventLevel.Informational;
- private readonly ConfigCell _logLevel = new(nameof(LogLevel), LogLevel.Warning);
- private readonly ConfigCell _skipOtlpExporter = new(nameof(SkipOtlpExporter), false);
- private readonly ConfigCell _enabledDefaults = new(nameof(ElasticDefaults), ElasticDefaults.All);
- private readonly ConfigCell _runningInContainer = new(nameof(_runningInContainer), false);
- private readonly ConfigCell _signals = new(nameof(Signals), Signals.All);
-
- private readonly ConfigCell _tracing = new(nameof(Tracing), TraceInstrumentations.All);
- private readonly ConfigCell _metrics = new(nameof(Metrics), MetricInstrumentations.All);
- private readonly ConfigCell _logging = new(nameof(Logging), LogInstrumentations.All);
-
- private readonly IDictionary _environmentVariables;
-
- ///
- /// Creates a new instance of with properties
- /// bound from environment variables.
- ///
- public ElasticOpenTelemetryOptions(IDictionary? environmentVariables = null)
- {
- LogDirectoryDefault = GetDefaultLogDirectory();
- _environmentVariables = environmentVariables ?? GetEnvironmentVariables();
- SetFromEnvironment(DOTNET_RUNNING_IN_CONTAINER, _runningInContainer, BoolParser);
-
- SetFromEnvironment(OTEL_DOTNET_AUTO_LOG_DIRECTORY, _logDirectory, StringParser);
- SetFromEnvironment(OTEL_LOG_LEVEL, _logLevel, LogLevelParser);
- SetFromEnvironment(ELASTIC_OTEL_LOG_TARGETS, _logTargets, LogTargetsParser);
- SetFromEnvironment(ELASTIC_OTEL_SKIP_OTLP_EXPORTER, _skipOtlpExporter, BoolParser);
- SetFromEnvironment(ELASTIC_OTEL_DEFAULTS_ENABLED, _enabledDefaults, ElasticDefaultsParser);
-
- var parser = new EnvironmentParser(_environmentVariables);
- parser.ParseInstrumentationVariables(_signals, _tracing, _metrics, _logging);
-
- }
-
- ///
- /// Creates a new instance of with properties
- /// bound from environment variables and an instance.
- ///
- internal ElasticOpenTelemetryOptions(IConfiguration? configuration, IDictionary? environmentVariables = null)
- : this(environmentVariables)
- {
- if (configuration is null)
- return;
-
- var parser = new ConfigurationParser(configuration);
- parser.ParseLogDirectory(_logDirectory);
- parser.ParseLogTargets(_logTargets);
- parser.ParseLogLevel(_logLevel, ref _eventLevel);
- parser.ParseSkipOtlpExporter(_skipOtlpExporter);
- parser.ParseElasticDefaults(_enabledDefaults);
- parser.ParseSignals(_signals);
-
- parser.ParseInstrumentations(_tracing, _metrics, _logging);
-
- }
-
- ///
- /// Calculates whether global logging is enabled based on
- /// , and
- ///
- public bool GlobalLogEnabled
- {
- get
- {
- var level = _logLevel.Value;
- var targets = _logTargets.Value;
- var isActive = level is <= LogLevel.Debug || !string.IsNullOrWhiteSpace(_logDirectory.Value) || targets.HasValue;
- if (!isActive)
- return isActive;
-
- if (level is LogLevel.None)
- isActive = false;
- else if (targets is LogTargets.None)
- isActive = false;
- return isActive;
- }
- }
-
- private static string GetDefaultLogDirectory()
- {
- var applicationMoniker = "elastic-otel-dotnet";
- if (IsOSPlatform(OSPlatform.Windows))
- return Path.Combine(GetFolderPath(SpecialFolder.ApplicationData), "elastic", applicationMoniker);
- if (IsOSPlatform(OSPlatform.OSX))
- return Path.Combine(GetFolderPath(SpecialFolder.LocalApplicationData), "elastic", applicationMoniker);
-
- return $"/var/log/elastic/{applicationMoniker}";
- }
-
- ///
- /// The default log directory if file logging was enabled but non was specified
- /// Defaults to:
- /// - %PROGRAMDATA%\elastic\apm-agent-dotnet (on Windows)
- /// - /var/log/elastic/apm-agent-dotnet (on Linux)
- /// - ~/Library/Application_Support/elastic/apm-agent-dotnet (on OSX)
- ///
- public string LogDirectoryDefault { get; }
-
///
/// The output directory where the Elastic Distribution of OpenTelemetry .NET will write log files.
///
@@ -141,16 +23,7 @@ private static string GetDefaultLogDirectory()
/// {ProcessName}_{UtcUnixTimeMilliseconds}_{ProcessId}.instrumentation.log.
/// This log file includes log messages from the OpenTelemetry SDK and the Elastic distribution.
///
- public string LogDirectory
- {
- get => _logDirectory.Value ?? LogDirectoryDefault;
- init => _logDirectory.Assign(value, ConfigSource.Property);
- }
-
- ///
- /// Used by to determine the appropiate event level to subscribe to
- ///
- internal EventLevel EventLogLevel => _eventLevel;
+ public string? LogDirectory { get; init; }
///
/// The log level to use when writing log files.
@@ -167,115 +40,26 @@ public string LogDirectory
/// - TraceContain the most detailed messages.
///
///
- public LogLevel LogLevel
- {
- get => _logLevel.Value ?? LogLevel.Warning;
- init => _logLevel.Assign(value, ConfigSource.Property);
- }
-
- ///
- public LogTargets LogTargets
- {
- get => _logTargets.Value ?? (GlobalLogEnabled
- ? _runningInContainer.Value.HasValue && _runningInContainer.Value.Value ? LogTargets.StdOut : LogTargets.File
- : LogTargets.None);
- init => _logTargets.Assign(value, ConfigSource.Property);
- }
+ public LogLevel? LogLevel { get; init; }
///
- /// Stops from registering OLTP exporters, useful for testing scenarios.
+ /// Control the targets that the Elastic Distribution of OpenTelemetry .NET will log to.
///
- public bool SkipOtlpExporter
- {
- get => _skipOtlpExporter.Value ?? false;
- init => _skipOtlpExporter.Assign(value, ConfigSource.Property);
- }
+ public LogTargets? LogTargets { get; init; }
///
- /// Allows flags to be set based of to selectively opt in to Elastic Distribution of OpenTelemetry .NET features.
- /// Defaults to
+ /// Stops Elastic Distribution of OpenTelemetry .NET from registering OLTP exporters, useful for testing scenarios.
///
- ///
- /// Valid values are:
- ///
- /// - None Disables all Elastic defaults resulting in the use of the "vanilla" SDK.
- /// - All Enables all defaults (default if this option is not specified).
- /// - Tracing Enables Elastic defaults for tracing.
- /// - Metrics Enables Elastic defaults for metrics.
- /// - Logging Enables Elastic defaults for logging.
- ///
- ///
- public ElasticDefaults ElasticDefaults
- {
- get => _enabledDefaults.Value ?? ElasticDefaults.All;
- init => _enabledDefaults.Assign(value, ConfigSource.Property);
- }
+ public bool? SkipOtlpExporter { get; init; }
///
- /// Control which signals will be automatically enabled by the Elastic Distribution of OpenTelemetry .NET.
- ///
- /// This configuration respects the open telemetry environment configuration out of the box:
- ///
- ///
- ///
- ///
- ///
- ///
- /// Setting this propery in code or configuration will take precedence over environment variables
+ /// An additional to which logs will be written.
///
- public Signals Signals
- {
- get => _signals.Value ?? Signals.All;
- init => _signals.Assign(value, ConfigSource.Property);
- }
-
- /// Enabled trace instrumentations
- public TraceInstrumentations Tracing
- {
- get => _tracing.Value ?? TraceInstrumentations.All;
- init => _tracing.Assign(value, ConfigSource.Property);
- }
-
- /// Enabled trace instrumentations
- public MetricInstrumentations Metrics
- {
- get => _metrics.Value ?? MetricInstrumentations.All;
- init => _metrics.Assign(value, ConfigSource.Property);
- }
-
- /// Enabled trace instrumentations
- public LogInstrumentations Logging
- {
- get => _logging.Value ?? LogInstrumentations.All;
- init => _logging.Assign(value, ConfigSource.Property);
- }
-
- private void SetFromEnvironment(string key, ConfigCell field, Func parser)
- {
- var value = parser(GetSafeEnvironmentVariable(key));
- if (value is null)
- return;
-
- field.Assign(value, ConfigSource.Environment);
+ public ILogger? AdditionalLogger { get; init; }
- }
-
- private string GetSafeEnvironmentVariable(string key)
- {
- var value = _environmentVariables.Contains(key) ? _environmentVariables[key]?.ToString() : null;
- return value ?? string.Empty;
- }
-
-
- internal void LogConfigSources(ILogger logger)
- {
- logger.LogInformation("Configured value for {Configuration}", _logDirectory);
- logger.LogInformation("Configured value for {Configuration}", _logLevel);
- logger.LogInformation("Configured value for {Configuration}", _skipOtlpExporter);
- logger.LogInformation("Configured value for {Configuration}", _enabledDefaults);
- logger.LogInformation("Configured value for {Configuration}", _signals);
- logger.LogInformation("Configured value for {Configuration}", _tracing);
- logger.LogInformation("Configured value for {Configuration}", _metrics);
- logger.LogInformation("Configured value for {Configuration}", _logging);
- }
+ ///
+ /// An that can be used to create an additional
+ /// to which logs will be written.
+ ///
+ public ILoggerFactory? AdditionalLoggerFactory { get; init; }
}
diff --git a/src/Elastic.OpenTelemetry/Configuration/EnvironmentVariables.cs b/src/Elastic.OpenTelemetry/Configuration/EnvironmentVariables.cs
index 61a6aea..7efeeb3 100644
--- a/src/Elastic.OpenTelemetry/Configuration/EnvironmentVariables.cs
+++ b/src/Elastic.OpenTelemetry/Configuration/EnvironmentVariables.cs
@@ -9,22 +9,36 @@ internal static class EnvironmentVariables
// ReSharper disable InconsistentNaming
// ReSharper disable IdentifierTypo
public const string ELASTIC_OTEL_SKIP_OTLP_EXPORTER = nameof(ELASTIC_OTEL_SKIP_OTLP_EXPORTER);
+ public const string ELASTIC_OTEL_LOG_TARGETS = nameof(ELASTIC_OTEL_LOG_TARGETS);
public const string OTEL_DOTNET_AUTO_LOG_DIRECTORY = nameof(OTEL_DOTNET_AUTO_LOG_DIRECTORY);
public const string OTEL_LOG_LEVEL = nameof(OTEL_LOG_LEVEL);
- public const string ELASTIC_OTEL_LOG_TARGETS = nameof(ELASTIC_OTEL_LOG_TARGETS);
-
public const string DOTNET_RUNNING_IN_CONTAINER = nameof(DOTNET_RUNNING_IN_CONTAINER);
-
- public const string ELASTIC_OTEL_DEFAULTS_ENABLED = nameof(ELASTIC_OTEL_DEFAULTS_ENABLED);
-
public const string OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED = nameof(OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED);
public const string OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED = nameof(OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED);
public const string OTEL_DOTNET_AUTO_METRICS_INSTRUMENTATION_ENABLED = nameof(OTEL_DOTNET_AUTO_METRICS_INSTRUMENTATION_ENABLED);
public const string OTEL_DOTNET_AUTO_LOGS_INSTRUMENTATION_ENABLED = nameof(OTEL_DOTNET_AUTO_LOGS_INSTRUMENTATION_ENABLED);
+ public const string OTEL_EXPORTER_OTLP_ENDPOINT = nameof(OTEL_EXPORTER_OTLP_ENDPOINT);
+ public const string OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = nameof(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT);
+ public const string OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = nameof(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT);
+ public const string OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = nameof(OTEL_EXPORTER_OTLP_LOGS_ENDPOINT);
+
+ public const string OTEL_EXPORTER_OTLP_PROTOCOL = nameof(OTEL_EXPORTER_OTLP_PROTOCOL);
+ public const string OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = nameof(OTEL_EXPORTER_OTLP_TRACES_PROTOCOL);
+ public const string OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = nameof(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL);
+ public const string OTEL_EXPORTER_OTLP_LOGS_PROTOCOL = nameof(OTEL_EXPORTER_OTLP_LOGS_PROTOCOL);
+
+ public const string OTEL_EXPORTER_OTLP_TIMEOUT = nameof(OTEL_EXPORTER_OTLP_TIMEOUT);
+ public const string OTEL_EXPORTER_OTLP_TRACES_TIMEOUT = nameof(OTEL_EXPORTER_OTLP_TRACES_TIMEOUT);
+ public const string OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = nameof(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT);
+ public const string OTEL_EXPORTER_OTLP_LOGS_TIMEOUT = nameof(OTEL_EXPORTER_OTLP_LOGS_TIMEOUT);
+ public const string OTEL_EXPORTER_OTLP_HEADERS = nameof(OTEL_EXPORTER_OTLP_HEADERS);
+ public const string OTEL_EXPORTER_OTLP_TRACES_HEADERS = nameof(OTEL_EXPORTER_OTLP_TRACES_HEADERS);
+ public const string OTEL_EXPORTER_OTLP_METRICS_HEADERS = nameof(OTEL_EXPORTER_OTLP_METRICS_HEADERS);
+ public const string OTEL_EXPORTER_OTLP_LOGS_HEADERS = nameof(OTEL_EXPORTER_OTLP_LOGS_HEADERS);
// ReSharper enable IdentifierTypo
// ReSharper enable InconsistentNaming
}
diff --git a/src/Elastic.OpenTelemetry/Configuration/Instrumentations/LogInstrumentation.cs b/src/Elastic.OpenTelemetry/Configuration/Instrumentations/LogInstrumentation.cs
index b2c0240..68c8a01 100644
--- a/src/Elastic.OpenTelemetry/Configuration/Instrumentations/LogInstrumentation.cs
+++ b/src/Elastic.OpenTelemetry/Configuration/Instrumentations/LogInstrumentation.cs
@@ -6,15 +6,19 @@
namespace Elastic.OpenTelemetry.Configuration.Instrumentations;
-/// A hash set to enable
-public class LogInstrumentations : HashSet
+///
+/// A hash set to enable for auto-instrumentation.
+///
+///
+/// Explicitly enable specific libraries.
+///
+internal class LogInstrumentations(IEnumerable instrumentations) : HashSet(instrumentations)
{
- /// All available
+ ///
+ /// All available libraries.
+ ///
public static readonly LogInstrumentations All = new([.. LogInstrumentationExtensions.GetValues()]);
- /// Explicitly enable specific
- public LogInstrumentations(IEnumerable instrumentations) : base(instrumentations) { }
-
///
public override string ToString()
{
@@ -22,17 +26,20 @@ public override string ToString()
return "None";
if (Count == All.Count)
return "All";
- if (All.Count - Count < 5)
+ if (All.Count - Count < All.Count)
return $"All Except: {string.Join(", ", All.Except(this).Select(i => i.ToStringFast()))}";
+
return string.Join(", ", this.Select(i => i.ToStringFast()));
}
}
-/// Available logs instrumentations.
+///
+/// Available logging instrumentations.
+///
[EnumExtensions]
-public enum LogInstrumentation
+internal enum LogInstrumentation
{
- /// ILogger instrumentation
+ /// ILogger instrumentation.
// ReSharper disable once InconsistentNaming
ILogger
}
diff --git a/src/Elastic.OpenTelemetry/Configuration/Instrumentations/MetricInstrumentation.cs b/src/Elastic.OpenTelemetry/Configuration/Instrumentations/MetricInstrumentation.cs
index 1bc5dbf..d8b0adc 100644
--- a/src/Elastic.OpenTelemetry/Configuration/Instrumentations/MetricInstrumentation.cs
+++ b/src/Elastic.OpenTelemetry/Configuration/Instrumentations/MetricInstrumentation.cs
@@ -6,15 +6,19 @@
namespace Elastic.OpenTelemetry.Configuration.Instrumentations;
-/// A hash set to enable
-public class MetricInstrumentations : HashSet
+///
+/// A hash set to enable for auto-instrumentation.
+///
+///
+/// Explicitly enable specific libraries.
+///
+internal class MetricInstrumentations(IEnumerable instrumentations) : HashSet(instrumentations)
{
- /// All available
+ ///
+ /// All available libraries.
+ ///
public static readonly MetricInstrumentations All = new([.. MetricInstrumentationExtensions.GetValues()]);
- /// Explicitly enable specific
- public MetricInstrumentations(IEnumerable instrumentations) : base(instrumentations) { }
-
///
public override string ToString()
{
@@ -22,26 +26,29 @@ public override string ToString()
return "None";
if (Count == All.Count)
return "All";
- if (All.Count - Count < 5)
+ if (All.Count - Count < All.Count)
return $"All Except: {string.Join(", ", All.Except(this).Select(i => i.ToStringFast()))}";
+
return string.Join(", ", this.Select(i => i.ToStringFast()));
}
}
-/// Available metric instrumentations.
+///
+/// Available metric instrumentations.
+///
[EnumExtensions]
-public enum MetricInstrumentation
+internal enum MetricInstrumentation
{
- ///ASP.NET Framework
+ /// ASP.NET Framework.
AspNet,
- ///ASP.NET Core
+ /// ASP.NET Core.
AspNetCore,
- ///System.Net.Http.HttpClient and System.Net.HttpWebRequest, HttpClient metrics
+ /// System.Net.Http.HttpClient and System.Net.HttpWebRequest metrics.
HttpClient,
- ///OpenTelemetry.Instrumentation.Runtime, Runtime metrics
+ /// OpenTelemetry.Instrumentation.Runtime metrics.
NetRuntime,
- ///OpenTelemetry.Instrumentation.Process,Process metrics
+ /// OpenTelemetry.Instrumentation.Process metrics.
Process,
- ///NServiceBus metrics
+ /// NServiceBus metrics.
NServiceBus
}
diff --git a/src/Elastic.OpenTelemetry/Configuration/Instrumentations/TraceInstrumentation.cs b/src/Elastic.OpenTelemetry/Configuration/Instrumentations/TraceInstrumentation.cs
index eaca173..953427f 100644
--- a/src/Elastic.OpenTelemetry/Configuration/Instrumentations/TraceInstrumentation.cs
+++ b/src/Elastic.OpenTelemetry/Configuration/Instrumentations/TraceInstrumentation.cs
@@ -6,15 +6,19 @@
namespace Elastic.OpenTelemetry.Configuration.Instrumentations;
-/// A hash set to enable
-public class TraceInstrumentations : HashSet
+///
+/// A hash set to enable for auto-instrumentation.
+///
+///
+/// Explicitly enable specific libraries.
+///
+internal class TraceInstrumentations(IEnumerable instrumentations) : HashSet(instrumentations)
{
- /// All available
+ ///
+ /// All available libraries.
+ ///
public static readonly TraceInstrumentations All = new([.. TraceInstrumentationExtensions.GetValues()]);
- /// Explicitly enable specific
- public TraceInstrumentations(IEnumerable instrumentations) : base(instrumentations) { }
-
///
public override string ToString()
{
@@ -22,79 +26,82 @@ public override string ToString()
return "None";
if (Count == All.Count)
return "All";
- if (All.Count - Count < 5)
+ if (All.Count - Count < All.Count)
return $"All Except: {string.Join(", ", All.Except(this).Select(i => i.ToStringFast()))}";
+
return string.Join(", ", this.Select(i => i.ToStringFast()));
}
}
-/// Available trace instrumentations.
+///
+/// Available trace instrumentations.
+///
[EnumExtensions]
-public enum TraceInstrumentation
+internal enum TraceInstrumentation
{
- ///ASP.NET (.NET Framework) MVC / WebApi
+ /// ASP.NET (.NET Framework) MVC / WebApi.
AspNet,
- ///ASP.NET Core
+ /// ASP.NET Core.
AspNetCore,
- ///Azure SDK
+ /// Azure SDK.
Azure,
- ///Elastic.Clients.Elasticsearch
+ /// Elastic.Clients.Elasticsearch.
Elasticsearch,
- ///Elastic.Transport >=0.4.16
+ /// Elastic.Transport.
ElasticTransport,
- ///Microsoft.EntityFrameworkCore Not supported on.NET Framework >=6.0.12
+ /// Microsoft.EntityFrameworkCore.
EntityFrameworkCore,
- ///GraphQL Not supported on.NET Framework >=7.5.0
+ /// GraphQL.
Graphql,
- ///Grpc.Net.Client >=2.52 .0 & < 3.0.0
+ /// Grpc.Net.Client.
GrpcNetClient,
- ///System.Net.Http.HttpClient and System.Net.HttpWebRequest
+ /// System.Net.Http.HttpClient and System.Net.HttpWebRequest.
HttpClient,
- ///Confluent.Kafka >=1.4 .0 & < 3.0.0
+ /// Confluent.Kafka.
Kafka,
- ///MassTransit Not supported on.NET Framework ≥8.0.0
+ /// MassTransit.
MassTransit,
- ///MongoDB.Driver.Core >=2.13 .3 & < 3.0.0
+ /// MongoDB.Driver.Core.
MongoDb,
- ///MySqlConnector >=2.0.0
+ /// MySqlConnector.
MysqlConnector,
- ///MySql.Data Not supported on.NET Framework >=8.1.0
+ /// MySql.Data.
MysqlData,
- ///Npgsql >=6.0.0
+ /// Npgsql >=6.0.0.
Npgsql,
- ///NServiceBus >=8.0.0 & < 10.0.0
+ /// NServiceBus.
NServiceBus,
- ///Oracle.ManagedDataAccess.Core and Oracle.ManagedDataAccess Not supported on ARM64 >=23.4.0
+ /// Oracle.ManagedDataAccess.Core and Oracle.ManagedDataAccess.
OracleMda,
- ///Quartz Not supported on.NET Framework 4.7.1 and older >=3.4.0
+ /// Quartz.
Quartz,
- ///Microsoft.Data.SqlClient, System.Data.SqlClient and System.Data (shipped with.NET Framework)
+ /// Microsoft.Data.SqlClient, System.Data.SqlClient and System.Data (shipped with.NET Framework).
SqlClient,
- ///StackExchange.Redis Not supported on.NET Framework >=2.0.405 & < 3.0.0
+ /// StackExchange.Redis.
StackExchangeRedis,
- ///WCF
+ /// WCF client.
WcfClient,
- ///WCF Not supported on.NET.
+ /// WCF server.
WcfService
}
diff --git a/src/Elastic.OpenTelemetry/Configuration/LogTargets.cs b/src/Elastic.OpenTelemetry/Configuration/LogTargets.cs
index 04ab903..8d1c4a7 100644
--- a/src/Elastic.OpenTelemetry/Configuration/LogTargets.cs
+++ b/src/Elastic.OpenTelemetry/Configuration/LogTargets.cs
@@ -10,14 +10,17 @@ namespace Elastic.OpenTelemetry.Configuration;
[Flags]
public enum LogTargets
{
-
- /// No global logging
+ ///
+ /// No global logging.
+ ///
None,
+
///
/// Enable file logging. Use
- /// and to set any values other than the defaults
+ /// and to set any values other than the defaults.
///
File = 1 << 0, //1
+
///
/// Write to standard out, useful in scenarios where file logging might not be an option or harder to set up.
/// e.g. containers, k8s, etc.
diff --git a/src/Elastic.OpenTelemetry/Configuration/Parsers/ConfigurationParser.cs b/src/Elastic.OpenTelemetry/Configuration/Parsers/ConfigurationParser.cs
index 2d359dd..ea95fd8 100644
--- a/src/Elastic.OpenTelemetry/Configuration/Parsers/ConfigurationParser.cs
+++ b/src/Elastic.OpenTelemetry/Configuration/Parsers/ConfigurationParser.cs
@@ -3,11 +3,9 @@
// See the LICENSE file in the project root for more information
using System.Diagnostics.Tracing;
-using Elastic.OpenTelemetry.Configuration.Instrumentations;
-using Elastic.OpenTelemetry.Diagnostics.Logging;
+using Elastic.OpenTelemetry.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
-using static System.StringSplitOptions;
using static Elastic.OpenTelemetry.Configuration.Parsers.SharedParsers;
namespace Elastic.OpenTelemetry.Configuration.Parsers;
@@ -32,7 +30,6 @@ public ConfigurationParser(IConfiguration configuration)
LoggingSectionLogLevel = configuration.GetValue("Logging:LogLevel:Default");
}
-
private static void SetFromConfiguration(IConfiguration configuration, ConfigCell cell, Func parser)
{
//environment configuration takes precedence, assume already configured
@@ -75,6 +72,7 @@ public void ParseLogLevel(ConfigCell logLevel, ref EventLevel eventLe
if (sectionLogLevel < eventLogLevel)
eventLogLevel = sectionLogLevel;
}
+
eventLevel = eventLogLevel switch
{
LogLevel.Trace => EventLevel.Verbose,
@@ -82,87 +80,11 @@ public void ParseLogLevel(ConfigCell logLevel, ref EventLevel eventLe
LogLevel.Warning => EventLevel.Warning,
LogLevel.Error => EventLevel.Error,
LogLevel.Critical => EventLevel.Critical,
+
_ => EventLevel.Informational // fallback to info level
};
-
}
public void ParseSkipOtlpExporter(ConfigCell skipOtlpExporter) =>
SetFromConfiguration(_configuration, skipOtlpExporter, BoolParser);
-
- public void ParseSignals(ConfigCell signals) =>
- SetFromConfiguration(_configuration, signals, SignalsParser);
-
- public void ParseElasticDefaults(ConfigCell defaults) =>
- SetFromConfiguration(_configuration, defaults, ElasticDefaultsParser);
-
- public void ParseInstrumentations(
- ConfigCell tracing,
- ConfigCell metrics,
- ConfigCell logging
- )
- {
- if (tracing.Source != ConfigSource.Environment)
- SetFromConfiguration(_configuration, tracing, ParseTracing);
-
- if (metrics.Source != ConfigSource.Environment)
- SetFromConfiguration(_configuration, metrics, ParseMetrics);
-
- if (logging.Source != ConfigSource.Environment)
- SetFromConfiguration(_configuration, logging, ParseLogs);
-
- }
-
- private static IEnumerable? ParseInstrumentation(string? config, T[] all, Func getter)
- where T : struct
- {
- if (string.IsNullOrWhiteSpace(config))
- return null;
-
- var toRemove = new HashSet();
- var toAdd = new HashSet();
-
- foreach (var token in config.Split(new[] { ';', ',' }, RemoveEmptyEntries))
- {
- var candidate = token.Trim();
- var remove = candidate.StartsWith("-");
- candidate = candidate.TrimStart('-');
-
- var instrumentation = getter(candidate);
- if (!instrumentation.HasValue)
- continue;
-
- if (remove)
- toRemove.Add(instrumentation.Value);
- else
- toAdd.Add(instrumentation.Value);
- }
- if (toAdd.Count > 0)
- return toAdd;
- if (toRemove.Count > 0)
- return all.Except(toRemove);
- return null;
-
- }
-
- private static TraceInstrumentations? ParseTracing(string? tracing)
- {
- var instrumentations = ParseInstrumentation(tracing, TraceInstrumentationExtensions.GetValues(),
- s => TraceInstrumentationExtensions.TryParse(s, out var instrumentation) ? instrumentation : null);
- return instrumentations != null ? new TraceInstrumentations(instrumentations) : null;
- }
-
- private static MetricInstrumentations? ParseMetrics(string? metrics)
- {
- var instrumentations = ParseInstrumentation(metrics, MetricInstrumentationExtensions.GetValues(),
- s => MetricInstrumentationExtensions.TryParse(s, out var instrumentation) ? instrumentation : null);
- return instrumentations != null ? new MetricInstrumentations(instrumentations) : null;
- }
-
- private static LogInstrumentations? ParseLogs(string? logs)
- {
- var instrumentations = ParseInstrumentation(logs, LogInstrumentationExtensions.GetValues(),
- s => LogInstrumentationExtensions.TryParse(s, out var instrumentation) ? instrumentation : null);
- return instrumentations != null ? new LogInstrumentations(instrumentations) : null;
- }
}
diff --git a/src/Elastic.OpenTelemetry/Configuration/Parsers/EnvironmentParser.cs b/src/Elastic.OpenTelemetry/Configuration/Parsers/EnvironmentParser.cs
index b9d491c..4ac9ea0 100644
--- a/src/Elastic.OpenTelemetry/Configuration/Parsers/EnvironmentParser.cs
+++ b/src/Elastic.OpenTelemetry/Configuration/Parsers/EnvironmentParser.cs
@@ -32,8 +32,8 @@ private string GetSafeEnvironmentVariable(string key)
if (enabled.HasValue)
opted = true;
}
- return (opted, instrumentations);
+ return (opted, instrumentations);
}
internal (bool, HashSet) EnabledTraceInstrumentations(bool allEnabled) =>
@@ -49,8 +49,7 @@ public void ParseInstrumentationVariables(
ConfigCell signalsCell,
ConfigCell tracingCell,
ConfigCell metricsCell,
- ConfigCell loggingCell
- )
+ ConfigCell loggingCell)
{
var allEnabled = BoolParser(GetSafeEnvironmentVariable(OTEL_DOTNET_AUTO_INSTRUMENTATION_ENABLED));
var defaultSignals = allEnabled.HasValue
@@ -68,7 +67,6 @@ ConfigCell loggingCell
if (optedTraces)
tracingCell.Assign(new TraceInstrumentations(traceInstrumentations), ConfigSource.Environment);
-
var metricEnabled = Configured(metrics);
var (optedMetrics, metricInstrumentations) = EnabledMetricInstrumentations(metricEnabled);
if (optedMetrics)
@@ -98,8 +96,8 @@ ConfigCell loggingCell
if (logs.HasValue || traces.HasValue || traces.HasValue || allEnabled.HasValue)
signalsCell.Assign(signals, ConfigSource.Environment);
+
if (optedLogs || optedMetrics || optedTraces)
signalsCell.Assign(signals, ConfigSource.Environment);
-
}
}
diff --git a/src/Elastic.OpenTelemetry/Configuration/Parsers/SharedParsers.cs b/src/Elastic.OpenTelemetry/Configuration/Parsers/SharedParsers.cs
index ce40226..33f7746 100644
--- a/src/Elastic.OpenTelemetry/Configuration/Parsers/SharedParsers.cs
+++ b/src/Elastic.OpenTelemetry/Configuration/Parsers/SharedParsers.cs
@@ -2,7 +2,7 @@
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
-using Elastic.OpenTelemetry.Diagnostics.Logging;
+using Elastic.OpenTelemetry.Diagnostics;
using Microsoft.Extensions.Logging;
using static System.StringComparison;
using static System.StringSplitOptions;
@@ -11,20 +11,18 @@ namespace Elastic.OpenTelemetry.Configuration.Parsers;
internal static class SharedParsers
{
-
internal static LogLevel? LogLevelParser(string? s) =>
!string.IsNullOrEmpty(s) ? LogLevelHelpers.ToLogLevel(s) : null;
internal static LogTargets? LogTargetsParser(string? s)
{
- //var tokens = s?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries });
if (string.IsNullOrWhiteSpace(s))
return null;
var logTargets = LogTargets.None;
var found = false;
- foreach (var target in s.Split(new[] { ';', ',' }, RemoveEmptyEntries))
+ foreach (var target in s.Split([';', ','], RemoveEmptyEntries))
{
if (IsSet(target, "stdout"))
logTargets |= LogTargets.StdOut;
@@ -44,82 +42,6 @@ bool IsSet(string k, string v)
}
}
- internal static ElasticDefaults? ElasticDefaultsParser(string? s)
- {
- if (string.IsNullOrWhiteSpace(s))
- return null;
-
- var enabledDefaults = ElasticDefaults.None;
- var found = false;
-
- foreach (var target in s.Split(new[] { ';', ',' }, RemoveEmptyEntries))
- {
- if (IsSet(target, nameof(ElasticDefaults.Traces)))
- enabledDefaults |= ElasticDefaults.Traces;
- else if (IsSet(target, nameof(ElasticDefaults.Metrics)))
- enabledDefaults |= ElasticDefaults.Metrics;
- else if (IsSet(target, nameof(ElasticDefaults.Logs)))
- enabledDefaults |= ElasticDefaults.Logs;
- else if (IsSet(target, nameof(ElasticDefaults.All)))
- {
- enabledDefaults = ElasticDefaults.All;
- break;
- }
- else if (IsSet(target, "none"))
- {
- enabledDefaults = ElasticDefaults.None;
- break;
- }
- }
- return !found ? null : enabledDefaults;
-
- bool IsSet(string k, string v)
- {
- var b = k.Trim().Equals(v, InvariantCultureIgnoreCase);
- if (b)
- found = true;
- return b;
- }
- }
-
- internal static Signals? SignalsParser(string? s)
- {
- if (string.IsNullOrWhiteSpace(s))
- return null;
-
- var enabledDefaults = Signals.None;
- var found = false;
-
- foreach (var target in s.Split(new[] { ';', ',' }, RemoveEmptyEntries))
- {
- if (IsSet(target, nameof(Signals.Traces)))
- enabledDefaults |= Signals.Traces;
- else if (IsSet(target, nameof(Signals.Metrics)))
- enabledDefaults |= Signals.Metrics;
- else if (IsSet(target, nameof(Signals.Logs)))
- enabledDefaults |= Signals.Logs;
- else if (IsSet(target, nameof(Signals.All)))
- {
- enabledDefaults = Signals.All;
- break;
- }
- else if (IsSet(target, "none"))
- {
- enabledDefaults = Signals.None;
- break;
- }
- }
- return !found ? null : enabledDefaults;
-
- bool IsSet(string k, string v)
- {
- var b = k.Trim().Equals(v, InvariantCultureIgnoreCase);
- if (b)
- found = true;
- return b;
- }
- }
-
internal static string? StringParser(string? s) => !string.IsNullOrEmpty(s) ? s : null;
internal static bool? BoolParser(string? s) =>
diff --git a/src/Elastic.OpenTelemetry/EmptyInstrumentationLifetime.cs b/src/Elastic.OpenTelemetry/Configuration/SdkActivationMethod.cs
similarity index 53%
rename from src/Elastic.OpenTelemetry/EmptyInstrumentationLifetime.cs
rename to src/Elastic.OpenTelemetry/Configuration/SdkActivationMethod.cs
index b60d8b0..ede4b2e 100644
--- a/src/Elastic.OpenTelemetry/EmptyInstrumentationLifetime.cs
+++ b/src/Elastic.OpenTelemetry/Configuration/SdkActivationMethod.cs
@@ -2,11 +2,10 @@
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
-namespace Elastic.OpenTelemetry;
+namespace Elastic.OpenTelemetry.Configuration;
-internal sealed class EmptyInstrumentationLifetime : IInstrumentationLifetime
+internal enum SdkActivationMethod
{
- public void Dispose() { }
-
- public ValueTask DisposeAsync() => default;
+ NuGet,
+ AutoInstrumentation
}
diff --git a/src/Elastic.OpenTelemetry/Configuration/Signals.cs b/src/Elastic.OpenTelemetry/Configuration/Signals.cs
index a0c9840..75ae079 100644
--- a/src/Elastic.OpenTelemetry/Configuration/Signals.cs
+++ b/src/Elastic.OpenTelemetry/Configuration/Signals.cs
@@ -6,23 +6,35 @@
namespace Elastic.OpenTelemetry.Configuration;
-/// Observability signals to enable, defaults to all.
+//
+// Observability signals to enable, defaults to all.
+//
[Flags]
[EnumExtensions]
-public enum Signals
+internal enum Signals
{
- /// No Elastic defaults will be included, acting effectively as a vanilla OpenTelemetry
+ ///
+ /// No Elastic defaults will be included, acting effectively as a vanilla OpenTelemetry.
+ ///
None,
- /// Include Elastic Distribution of OpenTelemetry .NET tracing defaults
+ ///
+ /// Include Elastic Distribution of OpenTelemetry .NET tracing defaults.
+ ///
Traces = 1 << 0, //1
- /// Include Elastic Distribution of OpenTelemetry .NET metrics defaults
+ ///
+ /// Include Elastic Distribution of OpenTelemetry .NET metrics defaults.
+ ///
Metrics = 1 << 1, //2
- /// Include Elastic Distribution of OpenTelemetry .NET logging defaults
+ ///
+ /// Include Elastic Distribution of OpenTelemetry .NET logging defaults.
+ ///
Logs = 1 << 2, //4
- /// (default) Include all Elastic Distribution of OpenTelemetry .NET logging defaults
+ ///
+ /// (Default) Include all Elastic Distribution of OpenTelemetry .NET logging defaults.
+ ///
All = ~0
}
diff --git a/src/Elastic.OpenTelemetry/Core/AutoInstrumentationPlugin.cs b/src/Elastic.OpenTelemetry/Core/AutoInstrumentationPlugin.cs
new file mode 100644
index 0000000..c706a7c
--- /dev/null
+++ b/src/Elastic.OpenTelemetry/Core/AutoInstrumentationPlugin.cs
@@ -0,0 +1,108 @@
+// Licensed to Elasticsearch B.V under one or more agreements.
+// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information
+
+using System.Diagnostics;
+using Elastic.OpenTelemetry.Configuration;
+using Elastic.OpenTelemetry.Core;
+using OpenTelemetry;
+using OpenTelemetry.Logs;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Resources;
+using OpenTelemetry.Trace;
+
+#pragma warning disable IDE0130 // Namespace does not match folder structure
+namespace Elastic.OpenTelemetry;
+#pragma warning restore IDE0130 // Namespace does not match folder structure
+
+///
+/// Elastic Distribution of OpenTelemetry .NET plugin for Auto Instrumentation.
+/// Ensures all signals are rich enough to report to Elastic.
+///
+public class AutoInstrumentationPlugin
+{
+ private readonly BootstrapInfo _bootstrapInfo;
+ private readonly ElasticOpenTelemetryComponents? _components;
+
+ ///
+ public AutoInstrumentationPlugin()
+ {
+ SetError();
+
+ _bootstrapInfo = GetBootstrapInfo(out var components);
+
+ if (!_bootstrapInfo.Succeeded)
+ {
+ var errorMessage = $"Unable to bootstrap EDOT .NET due to {_bootstrapInfo.Exception!.Message}";
+
+ Console.Error.WriteLine(errorMessage);
+
+ try // Attempt to log the bootstrap failure to a file
+ {
+ var options = new CompositeElasticOpenTelemetryOptions();
+
+ var directory = options.LogDirectory;
+
+ if (string.IsNullOrEmpty(directory))
+ return;
+
+ var process = Process.GetCurrentProcess();
+ var logFileName = $"{process.ProcessName}_{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}_{process.Id}.auto_instrumentation.log";
+
+ Directory.CreateDirectory(directory);
+
+ using var streamWriter = File.CreateText(Path.Combine(directory, logFileName));
+
+ streamWriter.WriteLine(errorMessage);
+ }
+ catch
+ {
+ // Intended empty catch here. We don't want to crash the application.
+ }
+
+ return;
+ }
+
+ _components = components!;
+ }
+
+ // Used for testing
+ internal virtual BootstrapInfo GetBootstrapInfo(out ElasticOpenTelemetryComponents? components) =>
+ ElasticOpenTelemetry.TryBootstrap(SdkActivationMethod.AutoInstrumentation, out components);
+
+ // Used for testing
+ internal virtual void SetError() { }
+
+ ///
+ /// To configure tracing SDK before Auto Instrumentation configured SDK.
+ ///
+ public TracerProviderBuilder BeforeConfigureTracerProvider(TracerProviderBuilder builder) =>
+ !_bootstrapInfo.Succeeded || _components is null
+ ? builder
+ : builder.UseAutoInstrumentationElasticDefaults(_components);
+
+ ///
+ /// To configure metrics SDK before Auto Instrumentation configured SDK.
+ /// ///
+ public MeterProviderBuilder BeforeConfigureMeterProvider(MeterProviderBuilder builder) =>
+ !_bootstrapInfo.Succeeded || _components is null
+ ? builder
+ : builder.UseElasticDefaults(_components);
+
+ ///
+ /// To configure logs SDK (the method name is the same as for other logs options).
+ ///
+ public void ConfigureLogsOptions(OpenTelemetryLoggerOptions options)
+ {
+ if (_bootstrapInfo.Succeeded && _components is not null)
+ options.UseElasticDefaults(_components.Logger);
+ }
+
+ ///
+ /// To configure Resource.
+ ///
+ public ResourceBuilder ConfigureResource(ResourceBuilder builder) =>
+ !_bootstrapInfo.Succeeded || _components is null
+ ? builder
+ : builder.AddElasticDistroAttributes();
+}
diff --git a/src/Elastic.OpenTelemetry/Core/BootstrapInfo.cs b/src/Elastic.OpenTelemetry/Core/BootstrapInfo.cs
new file mode 100644
index 0000000..637b740
--- /dev/null
+++ b/src/Elastic.OpenTelemetry/Core/BootstrapInfo.cs
@@ -0,0 +1,27 @@
+// Licensed to Elasticsearch B.V under one or more agreements.
+// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information
+
+using System.Diagnostics;
+using Elastic.OpenTelemetry.Configuration;
+
+namespace Elastic.OpenTelemetry.Core;
+
+internal sealed class BootstrapInfo(SdkActivationMethod activationMethod, StackTrace stackTrace, Exception? exception)
+{
+ public BootstrapInfo(SdkActivationMethod activationMethod, StackTrace stackTrace)
+ : this(activationMethod, stackTrace, null) { }
+
+ public BootstrapInfo(SdkActivationMethod activationMethod, Exception exception)
+ : this(activationMethod, new StackTrace(exception), exception) { }
+
+ public SdkActivationMethod ActivationMethod { get; } = activationMethod;
+
+ public StackTrace StackTrace { get; } = stackTrace;
+
+ public Exception? Exception { get; } = exception;
+
+ public bool Succeeded => Exception is null;
+
+ public bool Failed => !Succeeded;
+}
diff --git a/src/Elastic.OpenTelemetry/Core/BuilderState.cs b/src/Elastic.OpenTelemetry/Core/BuilderState.cs
new file mode 100644
index 0000000..5f04384
--- /dev/null
+++ b/src/Elastic.OpenTelemetry/Core/BuilderState.cs
@@ -0,0 +1,29 @@
+// Licensed to Elasticsearch B.V under one or more agreements.
+// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information
+
+namespace Elastic.OpenTelemetry.Core;
+
+///
+/// Used to store bootstrap information and a single component instance that will later be
+/// tracked per builder (OpenTelemetryBuilder, TracerProviderBuilder, MeterProviderBuilder
+/// or LoggerProviderBuilder) instance.
+///
+internal sealed class BuilderState(
+ BootstrapInfo bootstrapInfo,
+ ElasticOpenTelemetryComponents components,
+ Guid? instanceIdentifier = null)
+{
+ private int _useElasticDefaultsCounter;
+
+ public BootstrapInfo BootstrapInfo { get; } = bootstrapInfo;
+
+ public ElasticOpenTelemetryComponents Components { get; } = components;
+
+ public Guid InstanceIdentifier { get; } = instanceIdentifier ?? Guid.NewGuid();
+
+ public void IncrementUseElasticDefaults() =>
+ Interlocked.Increment(ref _useElasticDefaultsCounter);
+
+ public int UseElasticDefaultsCounter => _useElasticDefaultsCounter;
+}
diff --git a/src/Elastic.OpenTelemetry/Core/ElasticOpenTelemetry.cs b/src/Elastic.OpenTelemetry/Core/ElasticOpenTelemetry.cs
new file mode 100644
index 0000000..3630eee
--- /dev/null
+++ b/src/Elastic.OpenTelemetry/Core/ElasticOpenTelemetry.cs
@@ -0,0 +1,179 @@
+// Licensed to Elasticsearch B.V under one or more agreements.
+// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information
+
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Elastic.OpenTelemetry.Configuration;
+using Elastic.OpenTelemetry.Diagnostics;
+using Elastic.OpenTelemetry.Hosting;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+
+namespace Elastic.OpenTelemetry.Core;
+
+internal static class ElasticOpenTelemetry
+{
+ private static volatile ElasticOpenTelemetryComponents? SharedComponents;
+
+#pragma warning disable IDE0028 // Simplify collection initialization
+ internal static readonly ConditionalWeakTable