diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 37d8181..ed3849d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -34,12 +34,12 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup .NET
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@v5
with:
global-json-file: global.json
@@ -94,11 +94,9 @@ jobs:
- name: Generate coverage report
if: matrix.os == 'ubuntu-latest'
- uses: danielpalme/ReportGenerator-GitHub-Action@5.5.0
+ uses: danielpalme/ReportGenerator-GitHub-Action@5.5.10
with:
- reports: |
- artifacts/test-results/**/coverage.cobertura.xml
- artifacts/coverage/coverage.cobertura.xml
+ reports: artifacts/test-results/**/coverage.cobertura.xml;artifacts/coverage/coverage.cobertura.xml
targetdir: artifacts/coverage-report
reporttypes: HtmlInline;MarkdownSummaryGithub;Cobertura
diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml
index 5951a88..90a28e2 100644
--- a/.github/workflows/publish-nuget.yml
+++ b/.github/workflows/publish-nuget.yml
@@ -37,7 +37,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
fetch-depth: 0
@@ -111,7 +111,7 @@ jobs:
Write-Host "Package version: $version"
- name: Setup .NET
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@v5
with:
global-json-file: global.json
@@ -211,7 +211,7 @@ jobs:
if-no-files-found: error
- name: Attest package artifacts
- uses: actions/attest-build-provenance@v2
+ uses: actions/attest-build-provenance@v4
with:
subject-path: |
artifacts/packages/*.nupkg
@@ -246,7 +246,7 @@ jobs:
git push origin "v$env:PACKAGE_VERSION"
- name: Create GitHub Release
- uses: softprops/action-gh-release@v2
+ uses: softprops/action-gh-release@v3
with:
tag_name: v${{ steps.version.outputs.version }}
name: v${{ steps.version.outputs.version }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d7b1bdf..434c6fb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,9 @@ This project follows semantic versioning. Release tags use `vMAJOR.MINOR.PATCH`.
## [Unreleased]
-No unreleased changes.
+- Changed `OtlpOptions.Protocol` from a string to the nullable OpenTelemetry `OtlpExportProtocol` enum.
+- Added opt-in console exporter configuration for local logging, tracing, and metrics debugging.
+- Added opt-in OpenTelemetry logging pipeline registration with OTLP log export support.
## [1.0.0] - 2026-05-24
diff --git a/Directory.Packages.props b/Directory.Packages.props
index a7e6c74..b449a9c 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -3,11 +3,13 @@
true
true
+
-
-
+
+
+
@@ -24,14 +26,17 @@
+
+
-
+
+
@@ -42,6 +47,7 @@
+
diff --git a/benchmarks/OpenTelemetry.Benchmarks/Program.cs b/benchmarks/OpenTelemetry.Benchmarks/Program.cs
index 073c0f7..7ef961e 100644
--- a/benchmarks/OpenTelemetry.Benchmarks/Program.cs
+++ b/benchmarks/OpenTelemetry.Benchmarks/Program.cs
@@ -4,6 +4,7 @@
using BenchmarkDotNet.Order;
using BenchmarkDotNet.Running;
using Microsoft.Extensions.DependencyInjection;
+using OpenTelemetry.Exporter;
namespace OpenTelemetry.Benchmarks;
@@ -68,7 +69,7 @@ public static int BuildMinimalServiceProvider()
private static void ConfigureMinimal(OpenTelemetryOptions options)
{
- options.ServiceName = ServiceName;
+ options.Observation.ServiceName = ServiceName;
options.EnableObservationLogging = false;
options.EnableTracing = true;
options.EnableMetrics = true;
@@ -77,18 +78,19 @@ private static void ConfigureMinimal(OpenTelemetryOptions options)
private static void ConfigureFull(OpenTelemetryOptions options)
{
ConfigureMinimal(options);
- options.ServiceVersion = "1.0.0";
- options.ActivitySourceName = "Benchmarks.Orders.Tracing";
- options.MeterName = "Benchmarks.Orders.Metrics";
+ options.Observation.ServiceVersion = "1.0.0";
+ options.Observation.ActivitySourceName = "Benchmarks.Orders.Tracing";
+ options.Observation.MeterName = "Benchmarks.Orders.Metrics";
options.Resource.ServiceNamespace = "benchmarks";
options.Resource.DeploymentEnvironment = "production";
options.Resource.Attributes["team"] = "platform";
options.Instrumentations.AspNetCore.Enabled = true;
options.Instrumentations.HttpClient.Enabled = true;
options.Instrumentations.Runtime.Enabled = true;
+ options.Exporters.Console.Enabled = true;
options.Exporters.Otlp.Enabled = true;
options.Exporters.Otlp.Endpoint = "http://localhost:4317";
- options.Exporters.Otlp.Protocol = "grpc";
+ options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc;
options.Exporters.Otlp.Headers["x-benchmark"] = "opentelemetry";
}
}
diff --git a/benchmarks/OpenTelemetry.Benchmarks/packages.lock.json b/benchmarks/OpenTelemetry.Benchmarks/packages.lock.json
index d27a0f2..5acbc78 100644
--- a/benchmarks/OpenTelemetry.Benchmarks/packages.lock.json
+++ b/benchmarks/OpenTelemetry.Benchmarks/packages.lock.json
@@ -31,8 +31,8 @@
},
"Atya.Diagnostics.Logging": {
"type": "Transitive",
- "resolved": "1.0.0",
- "contentHash": "JXgn5jimNlnYA94WynXTdcp6ayybTveqTCcfxN/60fqO3ucaQ9YGf3JDVRzo0en5D6lYKwZKNZXWzo3/wnO9ew==",
+ "resolved": "1.0.1",
+ "contentHash": "PlrizTJNeGkV0jTc4iw5ceswuGqH2wV3dDfo+LUcrYCjYtgbtT8ycFfNWV4ZuPoZR5vSj4b0LGQu5dGK/B98LA==",
"dependencies": {
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
@@ -41,8 +41,8 @@
},
"Atya.Diagnostics.Metrics": {
"type": "Transitive",
- "resolved": "1.0.0",
- "contentHash": "2iT9yJeBSFnPpkszq+i9/Bp3adrqp1q85x9EgTLfsvi+FWms3e48rgvIO6zeer8Jtehe0Whur1Njn5AB4/usHQ==",
+ "resolved": "1.0.1",
+ "contentHash": "1H70t3SEcoxIPI1bD/i9Y7+NnOnAMM3YqwuK1DpHoqH+aqX5RIbDOarACJ60oyhz6HjIIGTiypN4GqhgDzRmtg==",
"dependencies": {
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
@@ -51,8 +51,8 @@
},
"Atya.Diagnostics.Tracing": {
"type": "Transitive",
- "resolved": "1.0.0",
- "contentHash": "Er7R3/oL8s1XrzrVy4h1QKEVLsNo8vFYEZ93kfl/XURyAUOapajK9UUI5azQOMDtsUK3yNtMjCqVi8V97wmEhA==",
+ "resolved": "1.0.1",
+ "contentHash": "8lGM/J451JmkWZJRDYtxJuKXcSs0P18igKB9S3EhAwUM5X4v59SIkb0Lg9eRYTae7+vQcPJvOVQNqfwXQvh/Hg==",
"dependencies": {
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
@@ -148,15 +148,6 @@
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8"
}
},
- "Microsoft.Extensions.Options.DataAnnotations": {
- "type": "Transitive",
- "resolved": "10.0.8",
- "contentHash": "HhxwIGECGGJ8ox2kvm6/hkN/w1ZyKrO5uu/rLAL51V0ypPdahoNf+dHS6Er/DJs2aeUmH38ZTTzACfLy1O6w3Q==",
- "dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
- "Microsoft.Extensions.Options": "10.0.8"
- }
- },
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "10.0.8",
@@ -210,13 +201,14 @@
"Atya.Diagnostics.OpenTelemetry": {
"type": "Project",
"dependencies": {
- "Atya.Diagnostics.Observation": "[1.0.0, )",
+ "Atya.Diagnostics.Observation": "[1.0.1, )",
"Atya.Foundation.Guards": "[1.0.0, )",
"Microsoft.Extensions.Configuration.Abstractions": "[10.0.8, )",
"Microsoft.Extensions.Configuration.Binder": "[10.0.8, )",
"Microsoft.Extensions.DependencyInjection.Abstractions": "[10.0.8, )",
"Microsoft.Extensions.Options": "[10.0.8, )",
"OpenTelemetry": "[1.15.3, )",
+ "OpenTelemetry.Exporter.Console": "[1.15.3, )",
"OpenTelemetry.Exporter.OpenTelemetryProtocol": "[1.15.3, )",
"OpenTelemetry.Extensions.Hosting": "[1.15.3, )",
"OpenTelemetry.Instrumentation.AspNetCore": "[1.15.2, )",
@@ -229,17 +221,16 @@
},
"Atya.Diagnostics.Observation": {
"type": "CentralTransitive",
- "requested": "[1.0.0, )",
- "resolved": "1.0.0",
- "contentHash": "85nmR5rEEEzwg8n76NHLv+j8sGMWx1EdfMADlhZqBvS8oPSe70N1mZ9iBFfYtMz27jN8+9YVHyIf5GI+r9nFHg==",
+ "requested": "[1.0.1, )",
+ "resolved": "1.0.1",
+ "contentHash": "Rx7dLfRsqN2eLCnHr5Yswa2w8yQUxXNgVcAvjifrULEPDWHx5ZUY4Morb/0uf2FKKn2WLtEGTh9uA2nEdEyZbg==",
"dependencies": {
- "Atya.Diagnostics.Logging": "1.0.0",
- "Atya.Diagnostics.Metrics": "1.0.0",
- "Atya.Diagnostics.Tracing": "1.0.0",
+ "Atya.Diagnostics.Logging": "1.0.1",
+ "Atya.Diagnostics.Metrics": "1.0.1",
+ "Atya.Diagnostics.Tracing": "1.0.1",
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
- "Microsoft.Extensions.Options": "10.0.8",
- "Microsoft.Extensions.Options.DataAnnotations": "10.0.8"
+ "Microsoft.Extensions.Options": "10.0.8"
}
},
"Atya.Foundation.Guards": {
@@ -366,6 +357,15 @@
"OpenTelemetry.Api.ProviderBuilderExtensions": "1.15.3"
}
},
+ "OpenTelemetry.Exporter.Console": {
+ "type": "CentralTransitive",
+ "requested": "[1.15.3, )",
+ "resolved": "1.15.3",
+ "contentHash": "QBGOoPwLHDXX+hXeUpspOjsqEn4vMkLw672QN+MzVWFBzjf625DdxLxhzowS1J/dRtW93U34rRbJec+4808fkg==",
+ "dependencies": {
+ "OpenTelemetry": "1.15.3"
+ }
+ },
"OpenTelemetry.Exporter.OpenTelemetryProtocol": {
"type": "CentralTransitive",
"requested": "[1.15.3, )",
diff --git a/samples/OpenTelemetry.Samples.Console/OpenTelemetry.Samples.Console.csproj b/samples/OpenTelemetry.Samples.Console/OpenTelemetry.Samples.Console.csproj
index bf54fc6..3abf333 100644
--- a/samples/OpenTelemetry.Samples.Console/OpenTelemetry.Samples.Console.csproj
+++ b/samples/OpenTelemetry.Samples.Console/OpenTelemetry.Samples.Console.csproj
@@ -13,6 +13,7 @@
+
diff --git a/samples/OpenTelemetry.Samples.Console/Program.cs b/samples/OpenTelemetry.Samples.Console/Program.cs
index d4c81f1..8f8358b 100644
--- a/samples/OpenTelemetry.Samples.Console/Program.cs
+++ b/samples/OpenTelemetry.Samples.Console/Program.cs
@@ -3,6 +3,7 @@
using Atya.Diagnostics.Tracing.Abstractions;
using Atya.Diagnostics.Tracing.Extensions;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
// ------------------------------------------------------------------------
@@ -10,24 +11,26 @@
//
// Demonstrates the full OpenTelemetry telemetry pipeline:
// - Resource metadata configuration
-// - Tracing + Metrics pipelines with OTLP export
+// - Logging + Tracing + Metrics pipelines with console and OTLP export
// - ASP.NET Core / HttpClient / Runtime instrumentations
-// - Using generic Tracing + Metrics building blocks inside the pipeline
+// - Using generic Logging + Tracing + Metrics building blocks inside the pipeline
// ------------------------------------------------------------------------
-var services = new ServiceCollection();
+var builder = Host.CreateApplicationBuilder(args);
// Register console logging so we can see log output.
-services.AddLogging(logging => logging.AddConsole());
+_ = builder.Logging.ClearProviders();
+_ = builder.Logging.AddConsole();
// Register the full telemetry pipeline.
-services.AddAtyaOpenTelemetry(options =>
+_ = builder.Services.AddAtyaOpenTelemetry(options =>
{
// Service identity (required).
- options.ServiceName = "Samples.OrderProcessor";
- options.ServiceVersion = "1.0.0";
+ options.Observation.ServiceName = "Samples.OrderProcessor";
+ options.Observation.ServiceVersion = "1.0.0";
// Pipeline toggles.
+ options.EnableLogging = true;
options.EnableTracing = true;
options.EnableMetrics = true;
options.EnableObservationLogging = true;
@@ -42,27 +45,38 @@
options.Instrumentations.AspNetCore.Enabled = true;
options.Instrumentations.Runtime.Enabled = true;
- // OTLP exporter (point to your collector).
- options.Exporters.Otlp.Enabled = true;
+ // Console exporter is handy while developing locally.
+ options.Exporters.Console.Enabled = true;
+
+ // OTLP exporter (enable when a collector is available).
+ options.Exporters.Otlp.Enabled = false;
options.Exporters.Otlp.Endpoint = "http://localhost:4317";
});
-using var provider = services.BuildServiceProvider();
+using var host = builder.Build();
+await host.StartAsync();
-// Resolve the generic building blocks that OpenTelemetry registered for us.
-var logger = provider.GetRequiredService>();
-var activitySourceAccessor = provider.GetRequiredService();
-var meterAccessor = provider.GetRequiredService();
+try
+{
+ // Resolve the generic building blocks that OpenTelemetry registered for us.
+ var logger = host.Services.GetRequiredService>();
+ var activitySourceAccessor = host.Services.GetRequiredService();
+ var meterAccessor = host.Services.GetRequiredService();
-var processor = new OrderProcessor(logger, activitySourceAccessor, meterAccessor);
+ var processor = new OrderProcessor(logger, activitySourceAccessor, meterAccessor);
-// Simulate processing some orders.
-processor.ProcessOrder("ORD-001", "tenant-acme");
-processor.ProcessOrder("ORD-002", "tenant-globex");
+ // Simulate processing some orders.
+ processor.ProcessOrder("ORD-001", "tenant-acme");
+ processor.ProcessOrder("ORD-002", "tenant-globex");
+}
+finally
+{
+ await host.StopAsync();
+}
Console.WriteLine();
-Console.WriteLine("Sample completed. In a real setup with OTLP enabled,");
-Console.WriteLine("traces and metrics would be exported to your collector.");
+Console.WriteLine("Sample completed. Console exporter output is written while the host stops.");
+Console.WriteLine("logs, traces, and metrics would be exported to your collector.");
// ------------------------------------------------------------------------
// Sample service that uses all three diagnostics building blocks.
diff --git a/samples/OpenTelemetry.Samples.Console/packages.lock.json b/samples/OpenTelemetry.Samples.Console/packages.lock.json
index 72d5baf..d6730b2 100644
--- a/samples/OpenTelemetry.Samples.Console/packages.lock.json
+++ b/samples/OpenTelemetry.Samples.Console/packages.lock.json
@@ -11,6 +11,36 @@
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8"
}
},
+ "Microsoft.Extensions.Hosting": {
+ "type": "Direct",
+ "requested": "[10.0.8, )",
+ "resolved": "10.0.8",
+ "contentHash": "VfEyM2BipThcSd0GG/FS2ZPCVCTiosVq2zLKEDsfeMIg78sOVZPEmS7CgWlb+dqTlgXvLSL4OG2q6sM4xRhHNg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.8",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.8",
+ "Microsoft.Extensions.Configuration.Binder": "10.0.8",
+ "Microsoft.Extensions.Configuration.CommandLine": "10.0.8",
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": "10.0.8",
+ "Microsoft.Extensions.Configuration.FileExtensions": "10.0.8",
+ "Microsoft.Extensions.Configuration.Json": "10.0.8",
+ "Microsoft.Extensions.Configuration.UserSecrets": "10.0.8",
+ "Microsoft.Extensions.DependencyInjection": "10.0.8",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
+ "Microsoft.Extensions.Diagnostics": "10.0.8",
+ "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8",
+ "Microsoft.Extensions.FileProviders.Physical": "10.0.8",
+ "Microsoft.Extensions.Hosting.Abstractions": "10.0.8",
+ "Microsoft.Extensions.Logging": "10.0.8",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.8",
+ "Microsoft.Extensions.Logging.Configuration": "10.0.8",
+ "Microsoft.Extensions.Logging.Console": "10.0.8",
+ "Microsoft.Extensions.Logging.Debug": "10.0.8",
+ "Microsoft.Extensions.Logging.EventLog": "10.0.8",
+ "Microsoft.Extensions.Logging.EventSource": "10.0.8",
+ "Microsoft.Extensions.Options": "10.0.8"
+ }
+ },
"Microsoft.Extensions.Logging.Console": {
"type": "Direct",
"requested": "[10.0.8, )",
@@ -26,8 +56,8 @@
},
"Atya.Diagnostics.Logging": {
"type": "Transitive",
- "resolved": "1.0.0",
- "contentHash": "JXgn5jimNlnYA94WynXTdcp6ayybTveqTCcfxN/60fqO3ucaQ9YGf3JDVRzo0en5D6lYKwZKNZXWzo3/wnO9ew==",
+ "resolved": "1.0.1",
+ "contentHash": "PlrizTJNeGkV0jTc4iw5ceswuGqH2wV3dDfo+LUcrYCjYtgbtT8ycFfNWV4ZuPoZR5vSj4b0LGQu5dGK/B98LA==",
"dependencies": {
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
@@ -36,8 +66,8 @@
},
"Atya.Diagnostics.Metrics": {
"type": "Transitive",
- "resolved": "1.0.0",
- "contentHash": "2iT9yJeBSFnPpkszq+i9/Bp3adrqp1q85x9EgTLfsvi+FWms3e48rgvIO6zeer8Jtehe0Whur1Njn5AB4/usHQ==",
+ "resolved": "1.0.1",
+ "contentHash": "1H70t3SEcoxIPI1bD/i9Y7+NnOnAMM3YqwuK1DpHoqH+aqX5RIbDOarACJ60oyhz6HjIIGTiypN4GqhgDzRmtg==",
"dependencies": {
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
@@ -46,8 +76,8 @@
},
"Atya.Diagnostics.Tracing": {
"type": "Transitive",
- "resolved": "1.0.0",
- "contentHash": "Er7R3/oL8s1XrzrVy4h1QKEVLsNo8vFYEZ93kfl/XURyAUOapajK9UUI5azQOMDtsUK3yNtMjCqVi8V97wmEhA==",
+ "resolved": "1.0.1",
+ "contentHash": "8lGM/J451JmkWZJRDYtxJuKXcSs0P18igKB9S3EhAwUM5X4v59SIkb0Lg9eRYTae7+vQcPJvOVQNqfwXQvh/Hg==",
"dependencies": {
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
@@ -63,6 +93,72 @@
"Microsoft.Extensions.Primitives": "10.0.8"
}
},
+ "Microsoft.Extensions.Configuration.CommandLine": {
+ "type": "Transitive",
+ "resolved": "10.0.8",
+ "contentHash": "nQXq1a4MiInYh+0VF9fguxAl06q2ftmOyYQ+5e933s4rk57xjgkbTjUdFUySzjrcrvDeWsSqlZB+TE8+TbM2HA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.8",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.8"
+ }
+ },
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": {
+ "type": "Transitive",
+ "resolved": "10.0.8",
+ "contentHash": "bVGqctAfPGfTxJvNp8pMshtvpsUj6r6JkeiCNVIGVYO5gBxuxdN0Lbr25kEvE/zXdctkEc44g8HssnPgDnFGVA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.8",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.8"
+ }
+ },
+ "Microsoft.Extensions.Configuration.FileExtensions": {
+ "type": "Transitive",
+ "resolved": "10.0.8",
+ "contentHash": "1g9mzuu8gIHkjYb0jLxOTQVl/QDG5nn0b0JzgT/gbgNKr6gXZzxOHRAsdYRc1eDApB7LdHR8uK5vQrNjIQdRrQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.8",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.8",
+ "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8",
+ "Microsoft.Extensions.FileProviders.Physical": "10.0.8",
+ "Microsoft.Extensions.Primitives": "10.0.8"
+ }
+ },
+ "Microsoft.Extensions.Configuration.UserSecrets": {
+ "type": "Transitive",
+ "resolved": "10.0.8",
+ "contentHash": "6XTfFOnf27WY8kEeZkTZ4YNn0t+imgvdQ0YaAdR4vgURKATo9bCaVJ1KB71IOJAQtJP7Elb53VHlTNXg2CtSsA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.8",
+ "Microsoft.Extensions.Configuration.Json": "10.0.8",
+ "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8",
+ "Microsoft.Extensions.FileProviders.Physical": "10.0.8"
+ }
+ },
+ "Microsoft.Extensions.Diagnostics": {
+ "type": "Transitive",
+ "resolved": "10.0.8",
+ "contentHash": "uduyw9d3Fi+sbredO5drA1S44AQS2FRNFyn72UmB2vmQIO1qaXprpp1U/2lYhYi8yFdVERfY9sy/pxw/qPOU9w==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.8",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "10.0.8",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "10.0.8"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Physical": {
+ "type": "Transitive",
+ "resolved": "10.0.8",
+ "contentHash": "GkPvQe6IdidLu6Q3Lw6+B8NJpW8feW8czZ5mBKt5rXM/x8MvZfEp5WvAsjznzDGd23chIDrW0b2mmt+ScnEgiw==",
+ "dependencies": {
+ "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8",
+ "Microsoft.Extensions.FileSystemGlobbing": "10.0.8",
+ "Microsoft.Extensions.Primitives": "10.0.8"
+ }
+ },
+ "Microsoft.Extensions.FileSystemGlobbing": {
+ "type": "Transitive",
+ "resolved": "10.0.8",
+ "contentHash": "IUQet3SY51xIFcFZKtAB6a54/Zdxs7T3SQ84kJtOD6yeXfZgiOMksACWD5qtTmXGQGFH4QYGBOT0KIO8Uy/dJw=="
+ },
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Transitive",
"resolved": "10.0.8",
@@ -71,13 +167,38 @@
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8"
}
},
- "Microsoft.Extensions.Options.DataAnnotations": {
+ "Microsoft.Extensions.Logging.Debug": {
"type": "Transitive",
"resolved": "10.0.8",
- "contentHash": "HhxwIGECGGJ8ox2kvm6/hkN/w1ZyKrO5uu/rLAL51V0ypPdahoNf+dHS6Er/DJs2aeUmH38ZTTzACfLy1O6w3Q==",
+ "contentHash": "4HW3M1lGHHDwEYcDZHRNptBQ48LCI2yW+XV4vuxdfQUqafTpVT8j9RqAsez08krZKhIiaArWu8iQq5uRKZ9Ffg==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
- "Microsoft.Extensions.Options": "10.0.8"
+ "Microsoft.Extensions.Logging": "10.0.8",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.8"
+ }
+ },
+ "Microsoft.Extensions.Logging.EventLog": {
+ "type": "Transitive",
+ "resolved": "10.0.8",
+ "contentHash": "kK/C3SLIoGrcZvddYQw4eMm6YaROiSYBO7YgUR5Hdv5l+GIjBmbvQK5cST2FqjeubiAOPqFEimBT2N/8wVI+3A==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
+ "Microsoft.Extensions.Logging": "10.0.8",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.8",
+ "Microsoft.Extensions.Options": "10.0.8",
+ "System.Diagnostics.EventLog": "10.0.8"
+ }
+ },
+ "Microsoft.Extensions.Logging.EventSource": {
+ "type": "Transitive",
+ "resolved": "10.0.8",
+ "contentHash": "HX2M0MgzwQM8jpLe3AYAEMd0YsUfOP5RgGrDuk+Ki9n7HSuMbvLm9TEV3qRI3Pg9aqxc56GfgK/KdMRBhfWwKw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
+ "Microsoft.Extensions.Logging": "10.0.8",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.8",
+ "Microsoft.Extensions.Options": "10.0.8",
+ "Microsoft.Extensions.Primitives": "10.0.8"
}
},
"Microsoft.Extensions.Primitives": {
@@ -99,16 +220,22 @@
"OpenTelemetry.Api": "1.15.3"
}
},
+ "System.Diagnostics.EventLog": {
+ "type": "Transitive",
+ "resolved": "10.0.8",
+ "contentHash": "+Ro7WgIom+BDNH+YhTuZKL6QJ0ctfOpTyfUG/h3aU5KwXt3OaNf0wYWrTvoBUj+34Dy5V8dN9yCco1hAJQ4txw=="
+ },
"Atya.Diagnostics.OpenTelemetry": {
"type": "Project",
"dependencies": {
- "Atya.Diagnostics.Observation": "[1.0.0, )",
+ "Atya.Diagnostics.Observation": "[1.0.1, )",
"Atya.Foundation.Guards": "[1.0.0, )",
"Microsoft.Extensions.Configuration.Abstractions": "[10.0.8, )",
"Microsoft.Extensions.Configuration.Binder": "[10.0.8, )",
"Microsoft.Extensions.DependencyInjection.Abstractions": "[10.0.8, )",
"Microsoft.Extensions.Options": "[10.0.8, )",
"OpenTelemetry": "[1.15.3, )",
+ "OpenTelemetry.Exporter.Console": "[1.15.3, )",
"OpenTelemetry.Exporter.OpenTelemetryProtocol": "[1.15.3, )",
"OpenTelemetry.Extensions.Hosting": "[1.15.3, )",
"OpenTelemetry.Instrumentation.AspNetCore": "[1.15.2, )",
@@ -121,17 +248,16 @@
},
"Atya.Diagnostics.Observation": {
"type": "CentralTransitive",
- "requested": "[1.0.0, )",
- "resolved": "1.0.0",
- "contentHash": "85nmR5rEEEzwg8n76NHLv+j8sGMWx1EdfMADlhZqBvS8oPSe70N1mZ9iBFfYtMz27jN8+9YVHyIf5GI+r9nFHg==",
+ "requested": "[1.0.1, )",
+ "resolved": "1.0.1",
+ "contentHash": "Rx7dLfRsqN2eLCnHr5Yswa2w8yQUxXNgVcAvjifrULEPDWHx5ZUY4Morb/0uf2FKKn2WLtEGTh9uA2nEdEyZbg==",
"dependencies": {
- "Atya.Diagnostics.Logging": "1.0.0",
- "Atya.Diagnostics.Metrics": "1.0.0",
- "Atya.Diagnostics.Tracing": "1.0.0",
+ "Atya.Diagnostics.Logging": "1.0.1",
+ "Atya.Diagnostics.Metrics": "1.0.1",
+ "Atya.Diagnostics.Tracing": "1.0.1",
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
- "Microsoft.Extensions.Options": "10.0.8",
- "Microsoft.Extensions.Options.DataAnnotations": "10.0.8"
+ "Microsoft.Extensions.Options": "10.0.8"
}
},
"Atya.Foundation.Guards": {
@@ -159,6 +285,18 @@
"Microsoft.Extensions.Configuration.Abstractions": "10.0.8"
}
},
+ "Microsoft.Extensions.Configuration.Json": {
+ "type": "CentralTransitive",
+ "requested": "[10.0.8, )",
+ "resolved": "10.0.8",
+ "contentHash": "KLtAZ6A38s1pIfCO2ns6aG14NNGMYNZ4PBYfFK4M+R4A+xuSc6oklhqDcpHZxvDpyBWeFtR5C8iQBw2ng8tUHQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.8",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.8",
+ "Microsoft.Extensions.Configuration.FileExtensions": "10.0.8",
+ "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8"
+ }
+ },
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "CentralTransitive",
"requested": "[10.0.8, )",
@@ -258,6 +396,15 @@
"OpenTelemetry.Api.ProviderBuilderExtensions": "1.15.3"
}
},
+ "OpenTelemetry.Exporter.Console": {
+ "type": "CentralTransitive",
+ "requested": "[1.15.3, )",
+ "resolved": "1.15.3",
+ "contentHash": "QBGOoPwLHDXX+hXeUpspOjsqEn4vMkLw672QN+MzVWFBzjf625DdxLxhzowS1J/dRtW93U34rRbJec+4808fkg==",
+ "dependencies": {
+ "OpenTelemetry": "1.15.3"
+ }
+ },
"OpenTelemetry.Exporter.OpenTelemetryProtocol": {
"type": "CentralTransitive",
"requested": "[1.15.3, )",
diff --git a/src/OpenTelemetry/DependencyInjection/OpenTelemetryServiceCollectionExtensions.cs b/src/OpenTelemetry/DependencyInjection/OpenTelemetryServiceCollectionExtensions.cs
index e8b4928..b79febc 100644
--- a/src/OpenTelemetry/DependencyInjection/OpenTelemetryServiceCollectionExtensions.cs
+++ b/src/OpenTelemetry/DependencyInjection/OpenTelemetryServiceCollectionExtensions.cs
@@ -2,10 +2,11 @@
// Copyright (c) Atya. All rights reserved.
//
using Atya.Diagnostics.OpenTelemetry.Internal;
+using Atya.Diagnostics.OpenTelemetry.Logging;
using Atya.Diagnostics.OpenTelemetry.Metrics;
using Atya.Diagnostics.OpenTelemetry.Options;
using Atya.Diagnostics.OpenTelemetry.Tracing;
-using Atya.Diagnostics.Observation.DependencyInjection;
+using Atya.Diagnostics.Observation.Models;
using Atya.Foundation.Guards;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -44,44 +45,46 @@ public static IServiceCollection AddAtyaOpenTelemetry(
.Configure(configureOptions)
.ValidateOnStart();
- services.TryAddSingleton, OpenTelemetryOptionsValidator>();
+ services.TryAddEnumerable(
+ ServiceDescriptor.Singleton, OpenTelemetryOptionsValidator>());
- var serviceName = bootstrapOptions.ServiceName.Trim();
- var activitySourceName = string.IsNullOrWhiteSpace(bootstrapOptions.ActivitySourceName)
- ? serviceName
- : bootstrapOptions.ActivitySourceName.Trim();
- var meterName = string.IsNullOrWhiteSpace(bootstrapOptions.MeterName)
- ? serviceName
- : bootstrapOptions.MeterName.Trim();
+ var identity = ObservationIdentityResolver.Resolve(bootstrapOptions.Observation);
// Compose the generic Observation layer (Logging + Tracing + Metrics registration).
_ = services.AddAtyaObservation(observationOptions =>
{
- observationOptions.ServiceName = serviceName;
- observationOptions.ServiceVersion = bootstrapOptions.ServiceVersion;
- observationOptions.ActivitySourceName = activitySourceName;
- observationOptions.MeterName = meterName;
+ observationOptions.ServiceName = bootstrapOptions.Observation.ServiceName;
+ observationOptions.ServiceVersion = bootstrapOptions.Observation.ServiceVersion;
+ observationOptions.ActivitySourceName = bootstrapOptions.Observation.ActivitySourceName;
+ observationOptions.MeterName = bootstrapOptions.Observation.MeterName;
observationOptions.ConfigureLogging = bootstrapOptions.EnableObservationLogging;
observationOptions.ConfigureTracing = bootstrapOptions.EnableTracing;
observationOptions.ConfigureMetrics = bootstrapOptions.EnableMetrics;
});
// Build the OpenTelemetry resource.
- var resourceBuilder = ResourceBuilderFactory.Create(bootstrapOptions, activitySourceName, meterName);
+ var resourceBuilder = ResourceBuilderFactory.Create(identity, bootstrapOptions.Resource);
// Delegate pipeline configuration to folder-based configurators.
var otelBuilder = services.AddOpenTelemetry();
+ if (bootstrapOptions.EnableLogging)
+ {
+ _ = otelBuilder.WithLogging(
+ logging => logging.ConfigureAtyaLogging(bootstrapOptions, resourceBuilder),
+ loggingOptions => loggingOptions.ConfigureAtyaLogging(bootstrapOptions.Logging));
+ }
+
if (bootstrapOptions.EnableTracing)
{
_ = otelBuilder.WithTracing(tracing =>
- tracing.ConfigureAtyaTracing(bootstrapOptions, resourceBuilder, activitySourceName));
+ tracing.ConfigureAtyaTracing(bootstrapOptions, resourceBuilder, identity.ActivitySourceName));
}
if (bootstrapOptions.EnableMetrics)
{
_ = otelBuilder.WithMetrics(metrics =>
- metrics.ConfigureAtyaMetrics(bootstrapOptions, resourceBuilder, meterName));
+ metrics.ConfigureAtyaMetrics(bootstrapOptions, resourceBuilder, identity.MeterName));
}
return services;
diff --git a/src/OpenTelemetry/Internal/OpenTelemetryOptionsValidator.cs b/src/OpenTelemetry/Internal/OpenTelemetryOptionsValidator.cs
index 470b1e5..772a27e 100644
--- a/src/OpenTelemetry/Internal/OpenTelemetryOptionsValidator.cs
+++ b/src/OpenTelemetry/Internal/OpenTelemetryOptionsValidator.cs
@@ -4,6 +4,7 @@
using Atya.Diagnostics.OpenTelemetry.Options;
using Atya.Foundation.Guards;
using Microsoft.Extensions.Options;
+using OpenTelemetry.Exporter;
namespace Atya.Diagnostics.OpenTelemetry.Internal;
@@ -14,79 +15,71 @@ public ValidateOptionsResult Validate(string? name, OpenTelemetryOptions options
_ = name;
_ = Guard.AgainstNull(options);
- if (string.IsNullOrWhiteSpace(options.ServiceName))
- {
- return ValidateOptionsResult.Fail("OpenTelemetryOptions.ServiceName cannot be null or whitespace.");
- }
+ var failures = new List();
- var activitySourceValidation = ValidateTelemetryNames(options.ActivitySources, nameof(options.ActivitySources));
- if (activitySourceValidation is not null)
+ if (string.IsNullOrWhiteSpace(options.Observation.ServiceName))
{
- return activitySourceValidation;
+ failures.Add("OpenTelemetryOptions.Observation.ServiceName cannot be null or whitespace.");
}
- var meterValidation = ValidateTelemetryNames(options.Meters, nameof(options.Meters));
- if (meterValidation is not null)
- {
- return meterValidation;
- }
+ AddTelemetryNameFailures(options.ActivitySources, nameof(options.ActivitySources), failures);
+ AddTelemetryNameFailures(options.Meters, nameof(options.Meters), failures);
- if (!options.Exporters.Otlp.Enabled)
+ if (options.Exporters.Otlp.Enabled)
{
- return ValidateOptionsResult.Success;
- }
-
- if (options.Exporters.Otlp.Endpoint is not null &&
- !Uri.TryCreate(options.Exporters.Otlp.Endpoint, UriKind.Absolute, out _))
- {
- return ValidateOptionsResult.Fail(
- $"OpenTelemetryOptions.Exporters.Otlp.Endpoint '{options.Exporters.Otlp.Endpoint}' is not a valid absolute URI.");
- }
-
- if (!OtlpExporterConfigurator.IsSupportedProtocol(options.Exporters.Otlp.Protocol))
- {
- return ValidateOptionsResult.Fail(
- "OpenTelemetryOptions.Exporters.Otlp.Protocol must be either 'grpc' or 'http/protobuf'.");
- }
-
- foreach (var header in options.Exporters.Otlp.Headers)
- {
- if (string.IsNullOrWhiteSpace(header.Key))
+ if (options.Exporters.Otlp.Endpoint is not null &&
+ !Uri.TryCreate(options.Exporters.Otlp.Endpoint, UriKind.Absolute, out _))
{
- return ValidateOptionsResult.Fail("OpenTelemetryOptions.Exporters.Otlp.Headers cannot contain a null or whitespace header name.");
+ failures.Add(
+ $"OpenTelemetryOptions.Exporters.Otlp.Endpoint '{options.Exporters.Otlp.Endpoint}' is not a valid absolute URI.");
}
- if (header.Key.Contains(',', StringComparison.Ordinal) ||
- header.Key.Contains('=', StringComparison.Ordinal))
+ if (options.Exporters.Otlp.Protocol is { } protocol &&
+ !Enum.IsDefined(typeof(OtlpExportProtocol), protocol))
{
- return ValidateOptionsResult.Fail("OpenTelemetryOptions.Exporters.Otlp.Headers header names cannot contain ',' or '='.");
+ failures.Add("OpenTelemetryOptions.Exporters.Otlp.Protocol must be a defined OtlpExportProtocol value.");
}
- if (header.Value is null)
+ foreach (var header in options.Exporters.Otlp.Headers)
{
- return ValidateOptionsResult.Fail("OpenTelemetryOptions.Exporters.Otlp.Headers cannot contain a null header value.");
- }
+ if (string.IsNullOrWhiteSpace(header.Key))
+ {
+ failures.Add("OpenTelemetryOptions.Exporters.Otlp.Headers cannot contain a null or whitespace header name.");
+ }
- if (header.Value.Contains(',', StringComparison.Ordinal))
- {
- return ValidateOptionsResult.Fail("OpenTelemetryOptions.Exporters.Otlp.Headers header values cannot contain ','.");
+ if (header.Key.Contains(',', StringComparison.Ordinal) ||
+ header.Key.Contains('=', StringComparison.Ordinal))
+ {
+ failures.Add("OpenTelemetryOptions.Exporters.Otlp.Headers header names cannot contain ',' or '='.");
+ }
+
+ if (header.Value is null)
+ {
+ failures.Add("OpenTelemetryOptions.Exporters.Otlp.Headers cannot contain a null header value.");
+ }
+ else if (header.Value.Contains(',', StringComparison.Ordinal))
+ {
+ failures.Add("OpenTelemetryOptions.Exporters.Otlp.Headers header values cannot contain ','.");
+ }
}
}
- return ValidateOptionsResult.Success;
+ return failures.Count == 0
+ ? ValidateOptionsResult.Success
+ : ValidateOptionsResult.Fail(failures);
}
- private static ValidateOptionsResult? ValidateTelemetryNames(IEnumerable names, string optionName)
+ private static void AddTelemetryNameFailures(
+ IEnumerable names,
+ string optionName,
+ List failures)
{
foreach (var name in names)
{
if (string.IsNullOrWhiteSpace(name))
{
- return ValidateOptionsResult.Fail(
- $"OpenTelemetryOptions.{optionName} cannot contain a null or whitespace name.");
+ failures.Add($"OpenTelemetryOptions.{optionName} cannot contain a null or whitespace name.");
}
}
-
- return null;
}
}
diff --git a/src/OpenTelemetry/Internal/OtlpExporterConfigurator.cs b/src/OpenTelemetry/Internal/OtlpExporterConfigurator.cs
index e802017..40d3281 100644
--- a/src/OpenTelemetry/Internal/OtlpExporterConfigurator.cs
+++ b/src/OpenTelemetry/Internal/OtlpExporterConfigurator.cs
@@ -9,7 +9,7 @@ namespace Atya.Diagnostics.OpenTelemetry.Internal;
///
/// Applies configuration to the underlying OpenTelemetry .
-/// Shared between tracing and metrics pipelines.
+/// Shared between logging, tracing, and metrics pipelines.
///
internal static class OtlpExporterConfigurator
{
@@ -23,9 +23,17 @@ public static void Apply(OtlpExporterOptions otlp, OtlpOptions options)
otlp.Endpoint = new Uri(options.Endpoint);
}
- if (!string.IsNullOrWhiteSpace(options.Protocol))
+ if (options.Protocol is { } protocol)
{
- otlp.Protocol = ParseProtocol(options.Protocol);
+ if (!Enum.IsDefined(typeof(OtlpExportProtocol), protocol))
+ {
+ throw new ArgumentOutOfRangeException(
+ nameof(options),
+ protocol,
+ "OTLP protocol must be a defined OtlpExportProtocol value.");
+ }
+
+ otlp.Protocol = protocol;
}
if (options.Headers.Count > 0)
@@ -34,33 +42,4 @@ public static void Apply(OtlpExporterOptions otlp, OtlpOptions options)
}
}
- public static bool IsSupportedProtocol(string? protocol)
- {
- if (string.IsNullOrWhiteSpace(protocol))
- {
- return true;
- }
-
- return protocol.Equals("grpc", StringComparison.OrdinalIgnoreCase) ||
- protocol.Equals("http/protobuf", StringComparison.OrdinalIgnoreCase);
- }
-
- private static OtlpExportProtocol ParseProtocol(string protocol)
- {
- var normalizedProtocol = Guard.AgainstNullOrWhiteSpace(protocol).Trim();
-
- if (normalizedProtocol.Equals("grpc", StringComparison.OrdinalIgnoreCase))
- {
- return OtlpExportProtocol.Grpc;
- }
-
- if (normalizedProtocol.Equals("http/protobuf", StringComparison.OrdinalIgnoreCase))
- {
- return OtlpExportProtocol.HttpProtobuf;
- }
-
- throw new ArgumentException(
- "OTLP protocol must be either 'grpc' or 'http/protobuf'.",
- nameof(protocol));
- }
}
diff --git a/src/OpenTelemetry/Internal/ResourceBuilderFactory.cs b/src/OpenTelemetry/Internal/ResourceBuilderFactory.cs
index cc3953e..f164d6a 100644
--- a/src/OpenTelemetry/Internal/ResourceBuilderFactory.cs
+++ b/src/OpenTelemetry/Internal/ResourceBuilderFactory.cs
@@ -2,6 +2,7 @@
// Copyright (c) Atya. All rights reserved.
//
using Atya.Diagnostics.OpenTelemetry.Options;
+using Atya.Diagnostics.Observation.Models;
using Atya.Foundation.Guards;
using OpenTelemetry.Resources;
@@ -9,30 +10,32 @@ namespace Atya.Diagnostics.OpenTelemetry.Internal;
internal static class ResourceBuilderFactory
{
- public static ResourceBuilder Create(OpenTelemetryOptions options, string activitySourceName, string meterName)
+ public static ResourceBuilder Create(
+ ObservationIdentity identity,
+ OpenTelemetryResourceOptions resourceOptions)
{
- _ = Guard.AgainstNull(options);
- _ = Guard.AgainstNullOrWhiteSpace(activitySourceName);
- _ = Guard.AgainstNullOrWhiteSpace(meterName);
+ _ = Guard.AgainstNull(identity);
+ _ = Guard.AgainstNull(resourceOptions);
var resourceBuilder = ResourceBuilder.CreateDefault()
.AddService(
- serviceName: options.ServiceName.Trim(),
- serviceVersion: string.IsNullOrWhiteSpace(options.ServiceVersion) ? null : options.ServiceVersion.Trim(),
- serviceNamespace: options.Resource.ServiceNamespace,
- serviceInstanceId: options.Resource.ServiceInstanceId);
+ serviceName: identity.ServiceName.Trim(),
+ serviceVersion: string.IsNullOrWhiteSpace(identity.ServiceVersion) ? null : identity.ServiceVersion.Trim(),
+ serviceNamespace: resourceOptions.ServiceNamespace,
+ serviceInstanceId: resourceOptions.ServiceInstanceId);
- if (!string.IsNullOrWhiteSpace(options.Resource.DeploymentEnvironment))
+ if (!string.IsNullOrWhiteSpace(resourceOptions.DeploymentEnvironment))
{
_ = resourceBuilder.AddAttributes(new KeyValuePair[]
{
- new ("deployment.environment", options.Resource.DeploymentEnvironment),
+ new ("deployment.environment.name", resourceOptions.DeploymentEnvironment),
+ new ("deployment.environment", resourceOptions.DeploymentEnvironment),
});
}
- if (options.Resource.Attributes.Count > 0)
+ if (resourceOptions.Attributes.Count > 0)
{
- _ = resourceBuilder.AddAttributes(options.Resource.Attributes);
+ _ = resourceBuilder.AddAttributes(resourceOptions.Attributes);
}
return resourceBuilder;
diff --git a/src/OpenTelemetry/Logging/LoggerProviderBuilderExtensions.cs b/src/OpenTelemetry/Logging/LoggerProviderBuilderExtensions.cs
new file mode 100644
index 0000000..c780a7d
--- /dev/null
+++ b/src/OpenTelemetry/Logging/LoggerProviderBuilderExtensions.cs
@@ -0,0 +1,54 @@
+//
+// Copyright (c) Atya. All rights reserved.
+//
+using Atya.Diagnostics.OpenTelemetry.Internal;
+using Atya.Diagnostics.OpenTelemetry.Options;
+using Atya.Foundation.Guards;
+using OpenTelemetry.Logs;
+using OpenTelemetry.Resources;
+
+namespace Atya.Diagnostics.OpenTelemetry.Logging;
+
+///
+/// Provides fluent extension methods for configuring the Atya
+/// OpenTelemetry logging pipeline on a .
+///
+internal static class LoggerProviderBuilderExtensions
+{
+ ///
+ /// Configures the logging pipeline with the Atya telemetry
+ /// resource and exporters.
+ ///
+ /// The same instance.
+ public static LoggerProviderBuilder ConfigureAtyaLogging(
+ this LoggerProviderBuilder builder,
+ OpenTelemetryOptions options,
+ ResourceBuilder resourceBuilder)
+ {
+ _ = Guard.AgainstNull(builder);
+ _ = Guard.AgainstNull(options);
+ _ = Guard.AgainstNull(resourceBuilder);
+
+ _ = builder.SetResourceBuilder(resourceBuilder);
+ _ = builder.AddConfiguredExporters(options.Exporters);
+
+ return builder;
+ }
+
+ private static LoggerProviderBuilder AddConfiguredExporters(
+ this LoggerProviderBuilder builder,
+ OpenTelemetryExporterOptions exporters)
+ {
+ if (exporters.Console.Enabled)
+ {
+ _ = builder.AddConsoleExporter();
+ }
+
+ if (exporters.Otlp.Enabled)
+ {
+ _ = builder.AddOtlpExporter(otlp => OtlpExporterConfigurator.Apply(otlp, exporters.Otlp));
+ }
+
+ return builder;
+ }
+}
diff --git a/src/OpenTelemetry/Logging/OpenTelemetryLoggerOptionsExtensions.cs b/src/OpenTelemetry/Logging/OpenTelemetryLoggerOptionsExtensions.cs
new file mode 100644
index 0000000..8234da7
--- /dev/null
+++ b/src/OpenTelemetry/Logging/OpenTelemetryLoggerOptionsExtensions.cs
@@ -0,0 +1,32 @@
+//
+// Copyright (c) Atya. All rights reserved.
+//
+using Atya.Diagnostics.OpenTelemetry.Options;
+using Atya.Foundation.Guards;
+using OpenTelemetry.Logs;
+
+namespace Atya.Diagnostics.OpenTelemetry.Logging;
+
+///
+/// Provides fluent extension methods for configuring OpenTelemetry logger options.
+///
+internal static class OpenTelemetryLoggerOptionsExtensions
+{
+ ///
+ /// Applies Atya log record options to the OpenTelemetry logging provider.
+ ///
+ /// The same instance.
+ public static OpenTelemetryLoggerOptions ConfigureAtyaLogging(
+ this OpenTelemetryLoggerOptions loggerOptions,
+ OpenTelemetryLoggingOptions options)
+ {
+ _ = Guard.AgainstNull(loggerOptions);
+ _ = Guard.AgainstNull(options);
+
+ loggerOptions.IncludeFormattedMessage = options.IncludeFormattedMessage;
+ loggerOptions.IncludeScopes = options.IncludeScopes;
+ loggerOptions.ParseStateValues = options.ParseStateValues;
+
+ return loggerOptions;
+ }
+}
diff --git a/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs
index 7b68638..4570ba8 100644
--- a/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs
+++ b/src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs
@@ -74,6 +74,11 @@ private static MeterProviderBuilder AddConfiguredExporters(
this MeterProviderBuilder builder,
OpenTelemetryExporterOptions exporters)
{
+ if (exporters.Console.Enabled)
+ {
+ _ = builder.AddConsoleExporter();
+ }
+
if (exporters.Otlp.Enabled)
{
_ = builder.AddOtlpExporter(otlp => OtlpExporterConfigurator.Apply(otlp, exporters.Otlp));
diff --git a/src/OpenTelemetry/OpenTelemetry.csproj b/src/OpenTelemetry/OpenTelemetry.csproj
index 2799f1c..f1fa356 100644
--- a/src/OpenTelemetry/OpenTelemetry.csproj
+++ b/src/OpenTelemetry/OpenTelemetry.csproj
@@ -8,8 +8,9 @@
v
alpha.0
+ true
- 1.0.0
+ 1.0.0
$(NoWarn);NU5104
@@ -22,8 +23,8 @@
-
-
+
+
@@ -34,6 +35,7 @@
+
diff --git a/src/OpenTelemetry/Options/ConsoleOptions.cs b/src/OpenTelemetry/Options/ConsoleOptions.cs
new file mode 100644
index 0000000..36236e4
--- /dev/null
+++ b/src/OpenTelemetry/Options/ConsoleOptions.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Atya. All rights reserved.
+//
+namespace Atya.Diagnostics.OpenTelemetry.Options;
+
+///
+/// Options for configuring the console exporter.
+///
+public sealed class ConsoleOptions
+{
+ ///
+ /// Gets or sets a value indicating whether the console exporter is enabled. Default is false.
+ ///
+ public bool Enabled { get; set; }
+}
diff --git a/src/OpenTelemetry/Options/OpenTelemetryExporterOptions.cs b/src/OpenTelemetry/Options/OpenTelemetryExporterOptions.cs
index 4bd0d4b..4b0c8db 100644
--- a/src/OpenTelemetry/Options/OpenTelemetryExporterOptions.cs
+++ b/src/OpenTelemetry/Options/OpenTelemetryExporterOptions.cs
@@ -8,6 +8,11 @@ namespace Atya.Diagnostics.OpenTelemetry.Options;
///
public sealed class OpenTelemetryExporterOptions
{
+ ///
+ /// Gets console exporter configuration.
+ ///
+ public ConsoleOptions Console { get; } = new();
+
///
/// Gets OTLP exporter configuration.
///
diff --git a/src/OpenTelemetry/Options/OpenTelemetryLoggingOptions.cs b/src/OpenTelemetry/Options/OpenTelemetryLoggingOptions.cs
new file mode 100644
index 0000000..d83007a
--- /dev/null
+++ b/src/OpenTelemetry/Options/OpenTelemetryLoggingOptions.cs
@@ -0,0 +1,28 @@
+//
+// Copyright (c) Atya. All rights reserved.
+//
+namespace Atya.Diagnostics.OpenTelemetry.Options;
+
+///
+/// Options for configuring OpenTelemetry log records.
+///
+public sealed class OpenTelemetryLoggingOptions
+{
+ ///
+ /// Gets or sets a value indicating whether formatted log messages are included on exported log records.
+ /// Default is true.
+ ///
+ public bool IncludeFormattedMessage { get; set; } = true;
+
+ ///
+ /// Gets or sets a value indicating whether logging scopes are included on exported log records.
+ /// Default is true.
+ ///
+ public bool IncludeScopes { get; set; } = true;
+
+ ///
+ /// Gets or sets a value indicating whether structured log state values are parsed into log record attributes.
+ /// Default is true.
+ ///
+ public bool ParseStateValues { get; set; } = true;
+}
diff --git a/src/OpenTelemetry/Options/OpenTelemetryOptions.cs b/src/OpenTelemetry/Options/OpenTelemetryOptions.cs
index 5aabe3d..86962be 100644
--- a/src/OpenTelemetry/Options/OpenTelemetryOptions.cs
+++ b/src/OpenTelemetry/Options/OpenTelemetryOptions.cs
@@ -1,6 +1,8 @@
//
// Copyright (c) Atya. All rights reserved.
//
+using Atya.Diagnostics.Observation.Options;
+
namespace Atya.Diagnostics.OpenTelemetry.Options;
///
@@ -10,14 +12,17 @@ namespace Atya.Diagnostics.OpenTelemetry.Options;
public sealed class OpenTelemetryOptions
{
///
- /// Gets or sets the logical service name used for resource metadata, tracing, and metrics.
- ///
- public string ServiceName { get; set; } = string.Empty;
-
- ///
- /// Gets or sets the service version used for resource metadata and instrument versioning.
+ /// Gets the shared observation identity (service name, version,
+ /// activity source name, meter name) used across the Atya
+ /// diagnostics layers. Single source of truth for identity.
///
- public string? ServiceVersion { get; set; }
+ ///
+ /// Setting Observation.ConfigureLogging / ConfigureTracing /
+ /// ConfigureMetrics directly is IGNORED. The OpenTelemetry-layer
+ /// toggles EnableObservationLogging / EnableTracing / EnableMetrics
+ /// take precedence and overwrite them at registration time.
+ ///
+ public ObservationOptions Observation { get; } = new();
///
/// Gets or sets a value indicating whether the OpenTelemetry tracing pipeline is enabled. Default is true.
@@ -30,19 +35,28 @@ public sealed class OpenTelemetryOptions
public bool EnableMetrics { get; set; } = true;
///
- /// Gets or sets a value indicating whether the Atya Observation logging layer is enabled. Default is false.
- ///
- public bool EnableObservationLogging { get; set; }
-
- ///
- /// Gets or sets the ActivitySource name override. When null, defaults to .
+ /// Gets or sets a value indicating whether the OpenTelemetry logging pipeline is enabled. Default is false.
///
- public string? ActivitySourceName { get; set; }
+ ///
+ /// Independent of , which only
+ /// registers the in-process Atya.Diagnostics.Logging helpers (scope
+ /// factories, structured property helpers) and does NOT export logs
+ /// anywhere. EnableLogging controls the OpenTelemetry SDK LoggerProvider
+ /// pipeline (OTLP / Console export).
+ ///
+ public bool EnableLogging { get; set; }
///
- /// Gets or sets the Meter name override. When null, defaults to .
+ /// Gets or sets a value indicating whether the Atya Observation logging layer is enabled. Default is false.
///
- public string? MeterName { get; set; }
+ ///
+ /// Independent of , which controls the
+ /// OpenTelemetry SDK LoggerProvider pipeline (OTLP / Console export).
+ /// EnableObservationLogging only registers the in-process
+ /// Atya.Diagnostics.Logging helpers (scope factories, structured property
+ /// helpers) and does NOT export logs anywhere.
+ ///
+ public bool EnableObservationLogging { get; set; }
///
/// Gets additional application names to subscribe to.
@@ -64,6 +78,11 @@ public sealed class OpenTelemetryOptions
///
public OpenTelemetryInstrumentationOptions Instrumentations { get; } = new();
+ ///
+ /// Gets OpenTelemetry logging options.
+ ///
+ public OpenTelemetryLoggingOptions Logging { get; } = new();
+
///
/// Gets exporter configuration options.
///
diff --git a/src/OpenTelemetry/Options/OtlpOptions.cs b/src/OpenTelemetry/Options/OtlpOptions.cs
index 5e0ab3f..2e757f8 100644
--- a/src/OpenTelemetry/Options/OtlpOptions.cs
+++ b/src/OpenTelemetry/Options/OtlpOptions.cs
@@ -1,6 +1,8 @@
//
// Copyright (c) Atya. All rights reserved.
//
+using OpenTelemetry.Exporter;
+
namespace Atya.Diagnostics.OpenTelemetry.Options;
///
@@ -20,10 +22,10 @@ public sealed class OtlpOptions
public string? Endpoint { get; set; }
///
- /// Gets or sets the OTLP transport protocol. Supported values: "grpc", "http/protobuf".
+ /// Gets or sets the OTLP transport protocol.
/// When null, the OpenTelemetry SDK default is used.
///
- public string? Protocol { get; set; }
+ public OtlpExportProtocol? Protocol { get; set; }
///
/// Gets additional headers to include in OTLP export requests.
diff --git a/src/OpenTelemetry/PublicAPI.Shipped.txt b/src/OpenTelemetry/PublicAPI.Shipped.txt
index af2bfe2..135fcf6 100644
--- a/src/OpenTelemetry/PublicAPI.Shipped.txt
+++ b/src/OpenTelemetry/PublicAPI.Shipped.txt
@@ -22,8 +22,8 @@ Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryInstrumentationOptions.OpenT
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryInstrumentationOptions.Runtime.get -> Atya.Diagnostics.OpenTelemetry.Options.InstrumentationToggle!
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryInstrumentationOptions.SqlClient.get -> Atya.Diagnostics.OpenTelemetry.Options.DatabaseInstrumentationOptions!
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions
-Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ActivitySourceName.get -> string?
-Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ActivitySourceName.set -> void
+*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ActivitySourceName.get -> string?
+*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ActivitySourceName.set -> void
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ActivitySources.get -> System.Collections.Generic.IList!
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableMetrics.get -> bool
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableMetrics.set -> void
@@ -33,15 +33,15 @@ Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableTracing.get ->
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableTracing.set -> void
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Exporters.get -> Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryExporterOptions!
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Instrumentations.get -> Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryInstrumentationOptions!
-Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.MeterName.get -> string?
-Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.MeterName.set -> void
+*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.MeterName.get -> string?
+*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.MeterName.set -> void
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Meters.get -> System.Collections.Generic.IList!
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.OpenTelemetryOptions() -> void
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Resource.get -> Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryResourceOptions!
-Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceName.get -> string!
-Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceName.set -> void
-Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceVersion.get -> string?
-Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceVersion.set -> void
+*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceName.get -> string!
+*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceName.set -> void
+*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceVersion.get -> string?
+*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.ServiceVersion.set -> void
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryResourceOptions
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryResourceOptions.Attributes.get -> System.Collections.Generic.IDictionary!
Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryResourceOptions.DeploymentEnvironment.get -> string?
@@ -58,7 +58,7 @@ Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Endpoint.get -> string?
Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Endpoint.set -> void
Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Headers.get -> System.Collections.Generic.IDictionary!
Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.OtlpOptions() -> void
-Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Protocol.get -> string?
+*REMOVED*Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Protocol.get -> string?
Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Protocol.set -> void
static Microsoft.Extensions.DependencyInjection.OpenTelemetryServiceCollectionExtensions.AddAtyaOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, Microsoft.Extensions.Configuration.IConfiguration! configuration, string! sectionName = "OpenTelemetry") -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
static Microsoft.Extensions.DependencyInjection.OpenTelemetryServiceCollectionExtensions.AddAtyaOpenTelemetry(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action? configure = null) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
diff --git a/src/OpenTelemetry/PublicAPI.Unshipped.txt b/src/OpenTelemetry/PublicAPI.Unshipped.txt
index 7dc5c58..5a01198 100644
--- a/src/OpenTelemetry/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry/PublicAPI.Unshipped.txt
@@ -1 +1,19 @@
#nullable enable
+Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions
+Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions.ConsoleOptions() -> void
+Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions.Enabled.get -> bool
+Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions.Enabled.set -> void
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryExporterOptions.Console.get -> Atya.Diagnostics.OpenTelemetry.Options.ConsoleOptions!
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.IncludeFormattedMessage.get -> bool
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.IncludeFormattedMessage.set -> void
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.IncludeScopes.get -> bool
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.IncludeScopes.set -> void
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.OpenTelemetryLoggingOptions() -> void
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.ParseStateValues.get -> bool
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions.ParseStateValues.set -> void
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableLogging.get -> bool
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.EnableLogging.set -> void
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Logging.get -> Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryLoggingOptions!
+Atya.Diagnostics.OpenTelemetry.Options.OpenTelemetryOptions.Observation.get -> Atya.Diagnostics.Observation.Options.ObservationOptions!
+Atya.Diagnostics.OpenTelemetry.Options.OtlpOptions.Protocol.get -> OpenTelemetry.Exporter.OtlpExportProtocol?
diff --git a/src/OpenTelemetry/README.md b/src/OpenTelemetry/README.md
index aa7202f..007dda1 100644
--- a/src/OpenTelemetry/README.md
+++ b/src/OpenTelemetry/README.md
@@ -1,6 +1,6 @@
# Atya.Diagnostics.OpenTelemetry
-`Atya.Diagnostics.OpenTelemetry` is the host-facing OpenTelemetry integration package for Atya diagnostics libraries. It wires OpenTelemetry tracing and metrics, Atya service identity, resource metadata, optional instrumentations, and OTLP export through one dependency-injection entry point.
+`Atya.Diagnostics.OpenTelemetry` is the host-facing OpenTelemetry integration package for Atya diagnostics libraries. It wires OpenTelemetry logging, tracing, and metrics, Atya service identity, resource metadata, optional instrumentations, and OTLP export through one dependency-injection entry point.
## Supported Framework
@@ -16,11 +16,13 @@ dotnet add package Atya.Diagnostics.OpenTelemetry
```csharp
using Microsoft.Extensions.DependencyInjection;
+using OpenTelemetry.Exporter;
services.AddAtyaOpenTelemetry(options =>
{
- options.ServiceName = "Orders.Service";
- options.ServiceVersion = "1.0.0";
+ options.Observation.ServiceName = "Orders.Service";
+ options.Observation.ServiceVersion = "1.0.0";
+ options.EnableLogging = true;
options.ActivitySources.Add("Orders.Workflows");
options.Meters.Add("Orders.Business");
@@ -36,9 +38,10 @@ services.AddAtyaOpenTelemetry(options =>
options.Instrumentations.GrpcClient.Enabled = true;
options.Instrumentations.Runtime.Enabled = true;
+ options.Exporters.Console.Enabled = true;
options.Exporters.Otlp.Enabled = true;
options.Exporters.Otlp.Endpoint = "http://otel-collector:4317";
- options.Exporters.Otlp.Protocol = "grpc";
+ options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc;
});
```
@@ -49,8 +52,11 @@ Bind from the default `OpenTelemetry` configuration section:
```json
{
"OpenTelemetry": {
- "ServiceName": "Orders.Service",
- "ServiceVersion": "1.0.0",
+ "Observation": {
+ "ServiceName": "Orders.Service",
+ "ServiceVersion": "1.0.0"
+ },
+ "EnableLogging": true,
"EnableTracing": true,
"EnableMetrics": true,
"EnableObservationLogging": false,
@@ -63,6 +69,11 @@ Bind from the default `OpenTelemetry` configuration section:
"team": "platform"
}
},
+ "Logging": {
+ "IncludeFormattedMessage": true,
+ "IncludeScopes": true,
+ "ParseStateValues": true
+ },
"Instrumentations": {
"AspNetCore": { "Enabled": true },
"HttpClient": { "Enabled": true },
@@ -78,10 +89,13 @@ Bind from the default `OpenTelemetry` configuration section:
"Runtime": { "Enabled": true }
},
"Exporters": {
+ "Console": {
+ "Enabled": true
+ },
"Otlp": {
"Enabled": true,
"Endpoint": "http://otel-collector:4317",
- "Protocol": "grpc",
+ "Protocol": "Grpc",
"Headers": {
"x-service": "orders"
}
@@ -103,16 +117,18 @@ services.AddAtyaOpenTelemetry(configuration, "Diagnostics:OpenTelemetry");
## Behavior
-- `ServiceName` is required and is trimmed before registration.
-- `ActivitySourceName` defaults to `ServiceName` when omitted.
-- `MeterName` defaults to `ServiceName` when omitted.
+- `Observation.ServiceName` is required and is trimmed before registration.
+- `Observation.ActivitySourceName` defaults to `Observation.ServiceName` when omitted.
+- `Observation.MeterName` defaults to `Observation.ServiceName` when omitted.
- `ActivitySources` adds extra application `ActivitySource` names beyond the package default.
- `Meters` adds extra application `Meter` names beyond the package default.
- Options passed to `AddAtyaOpenTelemetry` are validated immediately because the OpenTelemetry providers are configured during service registration.
-- Configure the package through the delegate or configuration section passed to `AddAtyaOpenTelemetry`; later `services.Configure(...)` calls do not rebuild the OpenTelemetry tracing or metrics providers.
+- Configure the package through the delegate or configuration section passed to `AddAtyaOpenTelemetry`; later `services.Configure(...)` calls do not rebuild the OpenTelemetry logging, tracing, or metrics providers.
- Tracing and metrics are enabled by default.
+- OpenTelemetry logging is disabled by default. Set `EnableLogging` to `true` to register the OpenTelemetry logging provider and export logs through configured exporters.
- Observation-layer logging is disabled by default.
-- ASP.NET Core, HttpClient, Runtime, and OTLP exporter registrations are opt-in.
+- `EnableObservationLogging` registers Atya Observation logging services; it does not by itself register the OpenTelemetry logging provider.
+- ASP.NET Core, HttpClient, Runtime, console exporter, and OTLP exporter registrations are opt-in.
- SqlClient, Entity Framework Core, and gRPC client instrumentations are opt-in.
- SQL command text capture is disabled by default because command text can contain sensitive data.
- The package composes `Atya.Diagnostics.Observation`; it does not define business metrics, activity names, or log catalogs.
@@ -121,10 +137,10 @@ services.AddAtyaOpenTelemetry(configuration, "Diagnostics:OpenTelemetry");
Options are validated through `Microsoft.Extensions.Options`. Invalid options fail when options are resolved or when host startup validation runs.
-- `ServiceName` cannot be null, empty, or whitespace.
+- `Observation.ServiceName` cannot be null, empty, or whitespace.
- `ActivitySources` and `Meters` cannot contain null, empty, or whitespace names.
- OTLP `Endpoint`, when set, must be an absolute URI.
-- OTLP `Protocol`, when set, must be `grpc` or `http/protobuf`.
+- OTLP `Protocol`, when set, must be a defined `OtlpExportProtocol` value such as `Grpc` or `HttpProtobuf`.
- OTLP header names cannot be empty and cannot contain `,` or `=`.
- OTLP header values cannot be null and cannot contain `,`.
@@ -152,7 +168,8 @@ Leave SQL text capture disabled unless queries are known not to contain secrets
| Exporter | Toggle | Configuration |
| -------- | ------ | ------------- |
-| OTLP | `Exporters.Otlp.Enabled` | `Endpoint`, `Protocol`, `Headers` |
+| Console | `Exporters.Console.Enabled` | `Enabled` |
+| OTLP | `Exporters.Otlp.Enabled` | `Endpoint`, `Protocol`, `Headers` for enabled logging, tracing, and metrics pipelines |
## Package Boundaries
diff --git a/src/OpenTelemetry/Tracing/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry/Tracing/TracerProviderBuilderExtensions.cs
index 309cf7c..4462cde 100644
--- a/src/OpenTelemetry/Tracing/TracerProviderBuilderExtensions.cs
+++ b/src/OpenTelemetry/Tracing/TracerProviderBuilderExtensions.cs
@@ -92,6 +92,11 @@ private static TracerProviderBuilder AddConfiguredExporters(
this TracerProviderBuilder builder,
OpenTelemetryExporterOptions exporters)
{
+ if (exporters.Console.Enabled)
+ {
+ _ = builder.AddConsoleExporter();
+ }
+
if (exporters.Otlp.Enabled)
{
_ = builder.AddOtlpExporter(otlp => OtlpExporterConfigurator.Apply(otlp, exporters.Otlp));
diff --git a/src/OpenTelemetry/packages.lock.json b/src/OpenTelemetry/packages.lock.json
index 94ed890..6d89887 100644
--- a/src/OpenTelemetry/packages.lock.json
+++ b/src/OpenTelemetry/packages.lock.json
@@ -4,17 +4,16 @@
"net10.0": {
"Atya.Diagnostics.Observation": {
"type": "Direct",
- "requested": "[1.0.0, )",
- "resolved": "1.0.0",
- "contentHash": "85nmR5rEEEzwg8n76NHLv+j8sGMWx1EdfMADlhZqBvS8oPSe70N1mZ9iBFfYtMz27jN8+9YVHyIf5GI+r9nFHg==",
+ "requested": "[1.0.1, )",
+ "resolved": "1.0.1",
+ "contentHash": "Rx7dLfRsqN2eLCnHr5Yswa2w8yQUxXNgVcAvjifrULEPDWHx5ZUY4Morb/0uf2FKKn2WLtEGTh9uA2nEdEyZbg==",
"dependencies": {
- "Atya.Diagnostics.Logging": "1.0.0",
- "Atya.Diagnostics.Metrics": "1.0.0",
- "Atya.Diagnostics.Tracing": "1.0.0",
+ "Atya.Diagnostics.Logging": "1.0.1",
+ "Atya.Diagnostics.Metrics": "1.0.1",
+ "Atya.Diagnostics.Tracing": "1.0.1",
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
- "Microsoft.Extensions.Options": "10.0.8",
- "Microsoft.Extensions.Options.DataAnnotations": "10.0.8"
+ "Microsoft.Extensions.Options": "10.0.8"
}
},
"Atya.Foundation.Guards": {
@@ -64,6 +63,23 @@
"Microsoft.Extensions.Primitives": "10.0.8"
}
},
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[10.0.300, )",
+ "resolved": "10.0.300",
+ "contentHash": "QzCtLkXVb3l4IxcpvJCbzUwMLihAmLN6vVLjQGSzYSF8d2dvXxqJAZk83RV3gYnp2egz8jRMgSR2woY3vOahTA==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "10.0.300",
+ "Microsoft.SourceLink.Common": "10.0.300",
+ "System.IO.Hashing": "10.0.8"
+ }
+ },
+ "MinVer": {
+ "type": "Direct",
+ "requested": "[7.0.0, )",
+ "resolved": "7.0.0",
+ "contentHash": "2lMTCQl5bGP4iv0JNkockPnyllC6eHLz+CoK2ICvalvHod+exXSxueu9hq+zNkU7bZBJf8wMfeRC/Edn8AGmEg=="
+ },
"OpenTelemetry": {
"type": "Direct",
"requested": "[1.15.3, )",
@@ -75,6 +91,15 @@
"OpenTelemetry.Api.ProviderBuilderExtensions": "1.15.3"
}
},
+ "OpenTelemetry.Exporter.Console": {
+ "type": "Direct",
+ "requested": "[1.15.3, )",
+ "resolved": "1.15.3",
+ "contentHash": "QBGOoPwLHDXX+hXeUpspOjsqEn4vMkLw672QN+MzVWFBzjf625DdxLxhzowS1J/dRtW93U34rRbJec+4808fkg==",
+ "dependencies": {
+ "OpenTelemetry": "1.15.3"
+ }
+ },
"OpenTelemetry.Exporter.OpenTelemetryProtocol": {
"type": "Direct",
"requested": "[1.15.3, )",
@@ -156,8 +181,8 @@
},
"Atya.Diagnostics.Logging": {
"type": "Transitive",
- "resolved": "1.0.0",
- "contentHash": "JXgn5jimNlnYA94WynXTdcp6ayybTveqTCcfxN/60fqO3ucaQ9YGf3JDVRzo0en5D6lYKwZKNZXWzo3/wnO9ew==",
+ "resolved": "1.0.1",
+ "contentHash": "PlrizTJNeGkV0jTc4iw5ceswuGqH2wV3dDfo+LUcrYCjYtgbtT8ycFfNWV4ZuPoZR5vSj4b0LGQu5dGK/B98LA==",
"dependencies": {
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
@@ -166,8 +191,8 @@
},
"Atya.Diagnostics.Metrics": {
"type": "Transitive",
- "resolved": "1.0.0",
- "contentHash": "2iT9yJeBSFnPpkszq+i9/Bp3adrqp1q85x9EgTLfsvi+FWms3e48rgvIO6zeer8Jtehe0Whur1Njn5AB4/usHQ==",
+ "resolved": "1.0.1",
+ "contentHash": "1H70t3SEcoxIPI1bD/i9Y7+NnOnAMM3YqwuK1DpHoqH+aqX5RIbDOarACJ60oyhz6HjIIGTiypN4GqhgDzRmtg==",
"dependencies": {
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
@@ -176,14 +201,22 @@
},
"Atya.Diagnostics.Tracing": {
"type": "Transitive",
- "resolved": "1.0.0",
- "contentHash": "Er7R3/oL8s1XrzrVy4h1QKEVLsNo8vFYEZ93kfl/XURyAUOapajK9UUI5azQOMDtsUK3yNtMjCqVi8V97wmEhA==",
+ "resolved": "1.0.1",
+ "contentHash": "8lGM/J451JmkWZJRDYtxJuKXcSs0P18igKB9S3EhAwUM5X4v59SIkb0Lg9eRYTae7+vQcPJvOVQNqfwXQvh/Hg==",
"dependencies": {
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
"Microsoft.Extensions.Options": "10.0.8"
}
},
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "10.0.300",
+ "contentHash": "P0kaQwVZx4xIUe2FtrLyBadYNXuAljttJUPvjBYRuHhPE8L77L42KakLDkaADRiUrGspoLcMwayjrbQhYTr0zA==",
+ "dependencies": {
+ "System.IO.Hashing": "10.0.8"
+ }
+ },
"Microsoft.Extensions.Configuration": {
"type": "Transitive",
"resolved": "10.0.8",
@@ -201,20 +234,16 @@
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8"
}
},
- "Microsoft.Extensions.Options.DataAnnotations": {
- "type": "Transitive",
- "resolved": "10.0.8",
- "contentHash": "HhxwIGECGGJ8ox2kvm6/hkN/w1ZyKrO5uu/rLAL51V0ypPdahoNf+dHS6Er/DJs2aeUmH38ZTTzACfLy1O6w3Q==",
- "dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
- "Microsoft.Extensions.Options": "10.0.8"
- }
- },
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "10.0.8",
"contentHash": "OBPo4nYhMyIbtueoC10CBm6AGAbo/A9IV8QQ/6ryZS7VvmqpGT7hunazeHLxFawRzn3oLOq4jhqhpBX4tfswWQ=="
},
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "10.0.300",
+ "contentHash": "0jlkXaUGjYlWTIVPve5MftjKHnT3SlAtq9BCLV4J9IjdPrxV/+4rMlBSjfr1khG8/GC6KGojjola8E1VvWF0qQ=="
+ },
"OpenTelemetry.Api": {
"type": "Transitive",
"resolved": "1.15.3",
@@ -229,6 +258,11 @@
"OpenTelemetry.Api": "1.15.3"
}
},
+ "System.IO.Hashing": {
+ "type": "Transitive",
+ "resolved": "10.0.8",
+ "contentHash": "+dJsbPJ3FyUbTZNplFj0RCKePFizmv6ewDV46JE9q/IVH4c3xTCftHfHelLsAKf0jryIPqgMb5GpS0x7TAY3mg=="
+ },
"Microsoft.Extensions.DependencyInjection": {
"type": "CentralTransitive",
"requested": "[10.0.8, )",
diff --git a/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs b/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs
index 0d51081..7e9ec4e 100644
--- a/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs
+++ b/tests/OpenTelemetry.UnitTests/DependencyInjection/OpenTelemetryServiceCollectionExtensionsTests.cs
@@ -1,12 +1,17 @@
+using System.Text;
using Atya.Diagnostics.Metrics.Abstractions;
using Atya.Diagnostics.Metrics.Options;
-using Atya.Diagnostics.Observation.Models;
+using Atya.Diagnostics.OpenTelemetry.Internal;
using Atya.Diagnostics.OpenTelemetry.Options;
+using Atya.Diagnostics.Observation.Models;
using Atya.Diagnostics.Tracing.Abstractions;
using Atya.Diagnostics.Tracing.Options;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
+using OpenTelemetry.Exporter;
+using OpenTelemetry.Logs;
namespace OpenTelemetry.UnitTests.DependencyInjection;
@@ -54,8 +59,8 @@ public void AddAtyaOpenTelemetry_Should_Register_ObservationIdentity_And_Map_Def
_ = services.AddAtyaOpenTelemetry(options =>
{
- options.ServiceName = "Orders.Service";
- options.ServiceVersion = "1.0.0";
+ options.Observation.ServiceName = "Orders.Service";
+ options.Observation.ServiceVersion = "1.0.0";
});
using var provider = services.BuildServiceProvider();
@@ -81,9 +86,9 @@ public void AddAtyaOpenTelemetry_Should_Trim_Service_And_Use_Explicit_ActivitySo
_ = services.AddAtyaOpenTelemetry(options =>
{
- options.ServiceName = " Orders.Service ";
- options.ActivitySourceName = " Orders.Tracing ";
- options.MeterName = " Orders.Metrics ";
+ options.Observation.ServiceName = " Orders.Service ";
+ options.Observation.ActivitySourceName = " Orders.Tracing ";
+ options.Observation.MeterName = " Orders.Metrics ";
});
using var provider = services.BuildServiceProvider();
@@ -99,7 +104,7 @@ public void AddAtyaOpenTelemetry_Should_Register_Tracing_And_Metrics_By_Default(
{
var services = new ServiceCollection();
- _ = services.AddAtyaOpenTelemetry(options => options.ServiceName = "Orders.Service");
+ _ = services.AddAtyaOpenTelemetry(options => options.Observation.ServiceName = "Orders.Service");
using var provider = services.BuildServiceProvider();
@@ -107,6 +112,23 @@ public void AddAtyaOpenTelemetry_Should_Register_Tracing_And_Metrics_By_Default(
_ = provider.GetService().Should().NotBeNull();
}
+ [Fact]
+ public void AddAtyaOpenTelemetry_Should_Let_OpenTelemetry_Toggles_Override_Observation_Toggles()
+ {
+ var services = new ServiceCollection();
+
+ _ = services.AddAtyaOpenTelemetry(options =>
+ {
+ options.Observation.ServiceName = "Orders.Service";
+ options.Observation.ConfigureTracing = false;
+ options.EnableTracing = true;
+ });
+
+ using var provider = services.BuildServiceProvider();
+
+ _ = provider.GetService().Should().NotBeNull();
+ }
+
[Fact]
public void AddAtyaOpenTelemetry_Should_Allow_Disabling_Tracing()
{
@@ -114,7 +136,7 @@ public void AddAtyaOpenTelemetry_Should_Allow_Disabling_Tracing()
_ = services.AddAtyaOpenTelemetry(options =>
{
- options.ServiceName = "Orders.Service";
+ options.Observation.ServiceName = "Orders.Service";
options.EnableTracing = false;
});
@@ -131,7 +153,7 @@ public void AddAtyaOpenTelemetry_Should_Allow_Disabling_Metrics()
_ = services.AddAtyaOpenTelemetry(options =>
{
- options.ServiceName = "Orders.Service";
+ options.Observation.ServiceName = "Orders.Service";
options.EnableMetrics = false;
});
@@ -142,20 +164,35 @@ public void AddAtyaOpenTelemetry_Should_Allow_Disabling_Metrics()
}
[Fact]
- public void AddAtyaOpenTelemetry_Should_Register_Logging_When_Enabled()
+ public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetry_Logging_When_Enabled()
{
var services = new ServiceCollection();
_ = services.AddAtyaOpenTelemetry(options =>
{
- options.ServiceName = "Orders.Service";
- options.EnableObservationLogging = true;
+ options.Observation.ServiceName = "Orders.Service";
+ options.EnableLogging = true;
});
using var provider = services.BuildServiceProvider();
var resolvedOptions = provider.GetRequiredService>().Value;
+ var loggerProviders = provider.GetServices();
- _ = resolvedOptions.EnableObservationLogging.Should().BeTrue();
+ _ = resolvedOptions.EnableLogging.Should().BeTrue();
+ _ = loggerProviders.Should().Contain(provider => provider is OpenTelemetryLoggerProvider);
+ }
+
+ [Fact]
+ public void AddAtyaOpenTelemetry_Should_Not_Register_OpenTelemetry_Logging_By_Default()
+ {
+ var services = new ServiceCollection();
+
+ _ = services.AddAtyaOpenTelemetry(options => options.Observation.ServiceName = "Orders.Service");
+
+ using var provider = services.BuildServiceProvider();
+ var loggerProviders = provider.GetServices();
+
+ _ = loggerProviders.Should().NotContain(provider => provider is OpenTelemetryLoggerProvider);
}
[Fact]
@@ -175,12 +212,27 @@ public void AddAtyaOpenTelemetry_Should_Be_Idempotent_For_Core_Identity_Service(
{
var services = new ServiceCollection();
- _ = services.AddAtyaOpenTelemetry(options => options.ServiceName = "Orders.Service");
- _ = services.AddAtyaOpenTelemetry(options => options.ServiceName = "Orders.Service");
+ _ = services.AddAtyaOpenTelemetry(options => options.Observation.ServiceName = "Orders.Service");
+ _ = services.AddAtyaOpenTelemetry(options => options.Observation.ServiceName = "Orders.Service");
_ = services.Count(d => d.ServiceType == typeof(ObservationIdentity)).Should().Be(1);
}
+ [Fact]
+ public void AddAtyaOpenTelemetry_Should_Register_Validator_Through_Enumerable()
+ {
+ var services = new ServiceCollection();
+ services.AddSingleton, TestOpenTelemetryOptionsValidator>();
+
+ _ = services.AddAtyaOpenTelemetry(options => options.Observation.ServiceName = "Orders.Service");
+
+ using var provider = services.BuildServiceProvider();
+ var validators = provider.GetServices>().ToArray();
+
+ _ = validators.Should().ContainSingle(validator => validator is TestOpenTelemetryOptionsValidator);
+ _ = validators.Should().ContainSingle(validator => validator is OpenTelemetryOptionsValidator);
+ }
+
[Fact]
public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetryOptions()
{
@@ -188,14 +240,19 @@ public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetryOptions()
_ = services.AddAtyaOpenTelemetry(options =>
{
- options.ServiceName = "Orders.Service";
- options.ServiceVersion = "2.0.0";
+ options.Observation.ServiceName = "Orders.Service";
+ options.Observation.ServiceVersion = "2.0.0";
+ options.EnableLogging = true;
options.EnableObservationLogging = true;
+ options.Logging.IncludeFormattedMessage = false;
+ options.Logging.IncludeScopes = false;
+ options.Logging.ParseStateValues = false;
options.ActivitySources.Add("Orders.Workflows");
options.Meters.Add("Orders.Business");
+ options.Exporters.Console.Enabled = true;
options.Exporters.Otlp.Enabled = true;
options.Exporters.Otlp.Endpoint = "http://localhost:4317";
- options.Exporters.Otlp.Protocol = "grpc";
+ options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc;
options.Exporters.Otlp.Headers["authorization"] = "Bearer token";
options.Instrumentations.AspNetCore.Enabled = true;
options.Instrumentations.HttpClient.Enabled = true;
@@ -211,14 +268,19 @@ public void AddAtyaOpenTelemetry_Should_Register_OpenTelemetryOptions()
var resolvedOptions = provider.GetRequiredService>().Value;
- _ = resolvedOptions.ServiceName.Should().Be("Orders.Service");
- _ = resolvedOptions.ServiceVersion.Should().Be("2.0.0");
+ _ = resolvedOptions.Observation.ServiceName.Should().Be("Orders.Service");
+ _ = resolvedOptions.Observation.ServiceVersion.Should().Be("2.0.0");
+ _ = resolvedOptions.EnableLogging.Should().BeTrue();
_ = resolvedOptions.EnableObservationLogging.Should().BeTrue();
+ _ = resolvedOptions.Logging.IncludeFormattedMessage.Should().BeFalse();
+ _ = resolvedOptions.Logging.IncludeScopes.Should().BeFalse();
+ _ = resolvedOptions.Logging.ParseStateValues.Should().BeFalse();
_ = resolvedOptions.ActivitySources.Should().ContainSingle("Orders.Workflows");
_ = resolvedOptions.Meters.Should().ContainSingle("Orders.Business");
+ _ = resolvedOptions.Exporters.Console.Enabled.Should().BeTrue();
_ = resolvedOptions.Exporters.Otlp.Enabled.Should().BeTrue();
_ = resolvedOptions.Exporters.Otlp.Endpoint.Should().Be("http://localhost:4317");
- _ = resolvedOptions.Exporters.Otlp.Protocol.Should().Be("grpc");
+ _ = resolvedOptions.Exporters.Otlp.Protocol.Should().Be(OtlpExportProtocol.Grpc);
_ = resolvedOptions.Exporters.Otlp.Headers.Should().ContainKey("authorization");
_ = resolvedOptions.Instrumentations.AspNetCore.Enabled.Should().BeTrue();
_ = resolvedOptions.Instrumentations.HttpClient.Enabled.Should().BeTrue();
@@ -236,9 +298,13 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary
{
- ["OpenTelemetry:ServiceName"] = "Billing.Service",
- ["OpenTelemetry:ServiceVersion"] = "3.1.4",
+ ["OpenTelemetry:Observation:ServiceName"] = "Billing.Service",
+ ["OpenTelemetry:Observation:ServiceVersion"] = "3.1.4",
+ ["OpenTelemetry:EnableLogging"] = "true",
["OpenTelemetry:EnableObservationLogging"] = "true",
+ ["OpenTelemetry:Logging:IncludeFormattedMessage"] = "false",
+ ["OpenTelemetry:Logging:IncludeScopes"] = "false",
+ ["OpenTelemetry:Logging:ParseStateValues"] = "false",
["OpenTelemetry:ActivitySources:0"] = "Billing.Workflows",
["OpenTelemetry:Meters:0"] = "Billing.Business",
["OpenTelemetry:Instrumentations:HttpClient:Enabled"] = "true",
@@ -247,9 +313,10 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_
["OpenTelemetry:Instrumentations:EntityFrameworkCore:Enabled"] = "true",
["OpenTelemetry:Instrumentations:EntityFrameworkCore:CaptureSqlText"] = "true",
["OpenTelemetry:Instrumentations:GrpcClient:Enabled"] = "true",
+ ["OpenTelemetry:Exporters:Console:Enabled"] = "true",
["OpenTelemetry:Exporters:Otlp:Enabled"] = "true",
["OpenTelemetry:Exporters:Otlp:Endpoint"] = "http://collector:4317",
- ["OpenTelemetry:Exporters:Otlp:Protocol"] = "http/protobuf",
+ ["OpenTelemetry:Exporters:Otlp:Protocol"] = "HttpProtobuf",
["OpenTelemetry:Exporters:Otlp:Headers:tenant"] = "billing",
})
.Build();
@@ -260,9 +327,13 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_
using var provider = services.BuildServiceProvider();
var resolvedOptions = provider.GetRequiredService>().Value;
- _ = resolvedOptions.ServiceName.Should().Be("Billing.Service");
- _ = resolvedOptions.ServiceVersion.Should().Be("3.1.4");
+ _ = resolvedOptions.Observation.ServiceName.Should().Be("Billing.Service");
+ _ = resolvedOptions.Observation.ServiceVersion.Should().Be("3.1.4");
+ _ = resolvedOptions.EnableLogging.Should().BeTrue();
_ = resolvedOptions.EnableObservationLogging.Should().BeTrue();
+ _ = resolvedOptions.Logging.IncludeFormattedMessage.Should().BeFalse();
+ _ = resolvedOptions.Logging.IncludeScopes.Should().BeFalse();
+ _ = resolvedOptions.Logging.ParseStateValues.Should().BeFalse();
_ = resolvedOptions.ActivitySources.Should().ContainSingle("Billing.Workflows");
_ = resolvedOptions.Meters.Should().ContainSingle("Billing.Business");
_ = resolvedOptions.Instrumentations.HttpClient.Enabled.Should().BeTrue();
@@ -271,21 +342,46 @@ public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Default_Configuration_
_ = resolvedOptions.Instrumentations.EntityFrameworkCore.Enabled.Should().BeTrue();
_ = resolvedOptions.Instrumentations.EntityFrameworkCore.CaptureSqlText.Should().BeTrue();
_ = resolvedOptions.Instrumentations.GrpcClient.Enabled.Should().BeTrue();
+ _ = resolvedOptions.Exporters.Console.Enabled.Should().BeTrue();
_ = resolvedOptions.Exporters.Otlp.Enabled.Should().BeTrue();
_ = resolvedOptions.Exporters.Otlp.Endpoint.Should().Be("http://collector:4317");
- _ = resolvedOptions.Exporters.Otlp.Protocol.Should().Be("http/protobuf");
+ _ = resolvedOptions.Exporters.Otlp.Protocol.Should().Be(OtlpExportProtocol.HttpProtobuf);
_ = resolvedOptions.Exporters.Otlp.Headers.Should().Contain("tenant", "billing");
}
+ [Fact]
+ public void OpenTelemetryOptions_Should_Bind_Nested_Observation_From_Json()
+ {
+ const string Json = """
+ {
+ "OpenTelemetry": {
+ "Observation": {
+ "ServiceName": "Catalog.Service"
+ }
+ }
+ }
+ """;
+
+ using var stream = new MemoryStream(Encoding.UTF8.GetBytes(Json));
+ var configuration = new ConfigurationBuilder()
+ .AddJsonStream(stream)
+ .Build();
+ var options = new OpenTelemetryOptions();
+
+ configuration.GetSection("OpenTelemetry").Bind(options);
+
+ _ = options.Observation.ServiceName.Should().Be("Catalog.Service");
+ }
+
[Fact]
public void AddAtyaOpenTelemetry_Should_Bind_Options_From_Custom_Configuration_Section()
{
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary
{
- ["Diagnostics:ServiceName"] = "Shipping.Service",
- ["Diagnostics:ActivitySourceName"] = "Shipping.Tracing",
- ["Diagnostics:MeterName"] = "Shipping.Metrics",
+ ["Diagnostics:Observation:ServiceName"] = "Shipping.Service",
+ ["Diagnostics:Observation:ActivitySourceName"] = "Shipping.Tracing",
+ ["Diagnostics:Observation:MeterName"] = "Shipping.Metrics",
})
.Build();
var services = new ServiceCollection();
@@ -305,15 +401,19 @@ public void OpenTelemetryOptions_Defaults_Should_Be_Production_Safe()
{
var options = new OpenTelemetryOptions();
- _ = options.ServiceName.Should().BeEmpty();
- _ = options.ServiceVersion.Should().BeNull();
- _ = options.ActivitySourceName.Should().BeNull();
- _ = options.MeterName.Should().BeNull();
+ _ = options.Observation.ServiceName.Should().BeEmpty();
+ _ = options.Observation.ServiceVersion.Should().BeNull();
+ _ = options.Observation.ActivitySourceName.Should().BeNull();
+ _ = options.Observation.MeterName.Should().BeNull();
_ = options.ActivitySources.Should().BeEmpty();
_ = options.Meters.Should().BeEmpty();
+ _ = options.EnableLogging.Should().BeFalse();
_ = options.EnableTracing.Should().BeTrue();
_ = options.EnableMetrics.Should().BeTrue();
_ = options.EnableObservationLogging.Should().BeFalse();
+ _ = options.Logging.IncludeFormattedMessage.Should().BeTrue();
+ _ = options.Logging.IncludeScopes.Should().BeTrue();
+ _ = options.Logging.ParseStateValues.Should().BeTrue();
_ = options.Instrumentations.AspNetCore.Enabled.Should().BeFalse();
_ = options.Instrumentations.HttpClient.Enabled.Should().BeFalse();
_ = options.Instrumentations.SqlClient.Enabled.Should().BeFalse();
@@ -322,6 +422,7 @@ public void OpenTelemetryOptions_Defaults_Should_Be_Production_Safe()
_ = options.Instrumentations.EntityFrameworkCore.CaptureSqlText.Should().BeFalse();
_ = options.Instrumentations.GrpcClient.Enabled.Should().BeFalse();
_ = options.Instrumentations.Runtime.Enabled.Should().BeFalse();
+ _ = options.Exporters.Console.Enabled.Should().BeFalse();
_ = options.Exporters.Otlp.Enabled.Should().BeFalse();
_ = options.Exporters.Otlp.Endpoint.Should().BeNull();
_ = options.Exporters.Otlp.Protocol.Should().BeNull();
@@ -331,4 +432,14 @@ public void OpenTelemetryOptions_Defaults_Should_Be_Production_Safe()
_ = options.Resource.DeploymentEnvironment.Should().BeNull();
_ = options.Resource.Attributes.Should().BeEmpty();
}
+
+ private sealed class TestOpenTelemetryOptionsValidator : IValidateOptions
+ {
+ public ValidateOptionsResult Validate(string? name, OpenTelemetryOptions options)
+ {
+ _ = name;
+ _ = options;
+ return ValidateOptionsResult.Success;
+ }
+ }
}
diff --git a/tests/OpenTelemetry.UnitTests/Integration/OpenTelemetryHostIntegrationTests.cs b/tests/OpenTelemetry.UnitTests/Integration/OpenTelemetryHostIntegrationTests.cs
index 4e96484..438cba2 100644
--- a/tests/OpenTelemetry.UnitTests/Integration/OpenTelemetryHostIntegrationTests.cs
+++ b/tests/OpenTelemetry.UnitTests/Integration/OpenTelemetryHostIntegrationTests.cs
@@ -14,11 +14,12 @@ public async Task AddAtyaOpenTelemetry_Should_Start_And_Stop_OpenTelemetry_Hoste
_ = builder.Logging.ClearProviders();
_ = builder.Services.AddAtyaOpenTelemetry(options =>
{
- options.ServiceName = "Orders.Service";
- options.ServiceVersion = "1.0.0";
+ options.Observation.ServiceName = "Orders.Service";
+ options.Observation.ServiceVersion = "1.0.0";
options.Resource.ServiceNamespace = "orders";
options.Resource.DeploymentEnvironment = "test";
options.Resource.Attributes["team"] = "platform";
+ options.EnableLogging = true;
options.Instrumentations.HttpClient.Enabled = true;
options.Instrumentations.Runtime.Enabled = true;
});
@@ -29,6 +30,9 @@ public async Task AddAtyaOpenTelemetry_Should_Start_And_Stop_OpenTelemetry_Hoste
try
{
var hostedServices = host.Services.GetServices().ToArray();
+ var logger = host.Services.GetRequiredService>();
+
+ logger.LogInformation("OpenTelemetry logging pipeline started.");
_ = hostedServices.Should().NotBeEmpty();
}
diff --git a/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs b/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs
index 238c0c9..2676abc 100644
--- a/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs
+++ b/tests/OpenTelemetry.UnitTests/Internal/OpenTelemetryInternalTests.cs
@@ -1,16 +1,22 @@
using System.Data;
using System.Diagnostics;
using Atya.Diagnostics.OpenTelemetry.Internal;
+using Atya.Diagnostics.OpenTelemetry.Logging;
using Atya.Diagnostics.OpenTelemetry.Metrics;
using Atya.Diagnostics.OpenTelemetry.Options;
using Atya.Diagnostics.OpenTelemetry.Tracing;
+using Atya.Diagnostics.Observation.Models;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NSubstitute;
using OpenTelemetry;
using OpenTelemetry.Exporter;
+using OpenTelemetry.Logs;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
+using AtyaLoggerProviderBuilderExtensions = Atya.Diagnostics.OpenTelemetry.Logging.LoggerProviderBuilderExtensions;
+using AtyaOpenTelemetryLoggerOptionsExtensions = Atya.Diagnostics.OpenTelemetry.Logging.OpenTelemetryLoggerOptionsExtensions;
using AtyaTracerProviderBuilderExtensions = Atya.Diagnostics.OpenTelemetry.Tracing.TracerProviderBuilderExtensions;
namespace OpenTelemetry.UnitTests.Internal;
@@ -24,7 +30,7 @@ public void OtlpExporterConfigurator_Should_Apply_Endpoint_Grpc_And_Headers()
var options = new OtlpOptions
{
Endpoint = "http://localhost:4317",
- Protocol = "grpc",
+ Protocol = OtlpExportProtocol.Grpc,
};
options.Headers["authorization"] = "Bearer token";
options.Headers["tenant"] = "orders";
@@ -42,7 +48,7 @@ public void OtlpExporterConfigurator_Should_Apply_HttpProtobuf_Protocol()
var otlp = new OtlpExporterOptions();
var options = new OtlpOptions
{
- Protocol = " http/protobuf ",
+ Protocol = OtlpExportProtocol.HttpProtobuf,
};
OtlpExporterConfigurator.Apply(otlp, options);
@@ -66,34 +72,18 @@ public void OtlpExporterConfigurator_Should_Leave_Defaults_When_Optional_Values_
}
[Fact]
- public void OtlpExporterConfigurator_Should_Throw_For_Invalid_Protocol()
+ public void OtlpExporterConfigurator_Should_Throw_For_Undefined_Protocol()
{
var otlp = new OtlpExporterOptions();
var options = new OtlpOptions
{
- Protocol = "json",
+ Protocol = (OtlpExportProtocol)42,
};
var act = () => OtlpExporterConfigurator.Apply(otlp, options);
- _ = act.Should().Throw()
- .WithParameterName("protocol");
- }
-
- [Theory]
- [InlineData(null, true)]
- [InlineData("", true)]
- [InlineData(" ", true)]
- [InlineData("grpc", true)]
- [InlineData("GRPC", true)]
- [InlineData("http/protobuf", true)]
- [InlineData("HTTP/PROTOBUF", true)]
- [InlineData("http/json", false)]
- public void OtlpExporterConfigurator_Should_Report_Supported_Protocols(string? protocol, bool expected)
- {
- var supported = OtlpExporterConfigurator.IsSupportedProtocol(protocol);
-
- _ = supported.Should().Be(expected);
+ _ = act.Should().Throw()
+ .WithParameterName("options");
}
[Fact]
@@ -114,7 +104,7 @@ public void OpenTelemetryOptionsValidator_Should_Return_Success_For_Valid_Option
var options = CreateValidOptions();
options.Exporters.Otlp.Enabled = true;
options.Exporters.Otlp.Endpoint = "http://localhost:4317";
- options.Exporters.Otlp.Protocol = "grpc";
+ options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc;
options.Exporters.Otlp.Headers["authorization"] = "Bearer token";
var result = new OpenTelemetryOptionsValidator().Validate(null, options);
@@ -127,7 +117,7 @@ public void OpenTelemetryOptionsValidator_Should_Ignore_Disabled_Otlp_Details()
{
var options = CreateValidOptions();
options.Exporters.Otlp.Endpoint = "not a uri";
- options.Exporters.Otlp.Protocol = "json";
+ options.Exporters.Otlp.Protocol = (OtlpExportProtocol)42;
options.Exporters.Otlp.Headers["bad,key"] = "bad,value";
var result = new OpenTelemetryOptionsValidator().Validate(null, options);
@@ -142,12 +132,38 @@ public void OpenTelemetryOptionsValidator_Should_Ignore_Disabled_Otlp_Details()
public void OpenTelemetryOptionsValidator_Should_Fail_When_ServiceName_Is_Missing(string? serviceName)
{
var options = CreateValidOptions();
- options.ServiceName = serviceName!;
+ options.Observation.ServiceName = serviceName!;
var result = new OpenTelemetryOptionsValidator().Validate("named", options);
_ = result.Failed.Should().BeTrue();
- _ = result.FailureMessage.Should().Contain("ServiceName");
+ _ = result.Failures.Should().Contain("OpenTelemetryOptions.Observation.ServiceName cannot be null or whitespace.");
+ }
+
+ [Fact]
+ public void OpenTelemetryOptionsValidator_Should_Collect_All_Failures()
+ {
+ var options = CreateValidOptions();
+ options.Observation.ServiceName = string.Empty;
+ options.ActivitySources.Add(" ");
+ options.Meters.Add("");
+ options.Exporters.Otlp.Enabled = true;
+ options.Exporters.Otlp.Endpoint = "not a uri";
+ options.Exporters.Otlp.Protocol = (OtlpExportProtocol)42;
+ options.Exporters.Otlp.Headers["bad,key"] = "bad,value";
+ options.Exporters.Otlp.Headers["missing-value"] = null!;
+
+ var result = new OpenTelemetryOptionsValidator().Validate(null, options);
+
+ _ = result.Failed.Should().BeTrue();
+ _ = result.Failures.Should().Contain("OpenTelemetryOptions.Observation.ServiceName cannot be null or whitespace.");
+ _ = result.Failures.Should().Contain("OpenTelemetryOptions.ActivitySources cannot contain a null or whitespace name.");
+ _ = result.Failures.Should().Contain("OpenTelemetryOptions.Meters cannot contain a null or whitespace name.");
+ _ = result.Failures.Should().Contain(failure => failure.Contains("OpenTelemetryOptions.Exporters.Otlp.Endpoint", StringComparison.Ordinal));
+ _ = result.Failures.Should().Contain("OpenTelemetryOptions.Exporters.Otlp.Protocol must be a defined OtlpExportProtocol value.");
+ _ = result.Failures.Should().Contain("OpenTelemetryOptions.Exporters.Otlp.Headers header names cannot contain ',' or '='.");
+ _ = result.Failures.Should().Contain("OpenTelemetryOptions.Exporters.Otlp.Headers header values cannot contain ','.");
+ _ = result.Failures.Should().Contain("OpenTelemetryOptions.Exporters.Otlp.Headers cannot contain a null header value.");
}
[Theory]
@@ -190,7 +206,7 @@ public void OpenTelemetryOptionsValidator_Should_Fail_When_Enabled_Otlp_Protocol
{
var options = CreateValidOptions();
options.Exporters.Otlp.Enabled = true;
- options.Exporters.Otlp.Protocol = "json";
+ options.Exporters.Otlp.Protocol = (OtlpExportProtocol)42;
var result = new OpenTelemetryOptionsValidator().Validate(null, options);
@@ -232,20 +248,23 @@ public void OpenTelemetryOptionsValidator_Should_Throw_When_Options_Are_Null()
public void ResourceBuilderFactory_Should_Create_Resource_With_Service_Metadata_And_Custom_Attributes()
{
var options = CreateValidOptions();
- options.ServiceName = " Orders.Service ";
- options.ServiceVersion = " 1.2.3 ";
+ options.Observation.ServiceName = " Orders.Service ";
+ options.Observation.ServiceVersion = " 1.2.3 ";
options.Resource.ServiceNamespace = "orders";
options.Resource.ServiceInstanceId = "pod-123";
options.Resource.DeploymentEnvironment = "production";
options.Resource.Attributes["team"] = "platform";
- var resource = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics").Build();
+ var resource = ResourceBuilderFactory.Create(
+ ObservationIdentityResolver.Resolve(options.Observation),
+ options.Resource).Build();
var attributes = resource.Attributes.ToDictionary(attribute => attribute.Key, attribute => attribute.Value);
_ = attributes.Should().Contain("service.name", "Orders.Service");
_ = attributes.Should().Contain("service.version", "1.2.3");
_ = attributes.Should().Contain("service.namespace", "orders");
_ = attributes.Should().Contain("service.instance.id", "pod-123");
+ _ = attributes.Should().Contain("deployment.environment.name", "production");
_ = attributes.Should().Contain("deployment.environment", "production");
_ = attributes.Should().Contain("team", "platform");
}
@@ -253,10 +272,14 @@ public void ResourceBuilderFactory_Should_Create_Resource_With_Service_Metadata_
[Fact]
public void ResourceBuilderFactory_Should_Create_Minimal_Resource()
{
- var resource = ResourceBuilderFactory.Create(CreateValidOptions(), "Orders.Tracing", "Orders.Metrics").Build();
+ var options = CreateValidOptions();
+ var resource = ResourceBuilderFactory.Create(
+ ObservationIdentityResolver.Resolve(options.Observation),
+ options.Resource).Build();
var attributes = resource.Attributes.ToDictionary(attribute => attribute.Key, attribute => attribute.Value);
_ = attributes.Should().Contain("service.name", "Orders.Service");
+ _ = attributes.Should().NotContainKey("deployment.environment.name");
_ = attributes.Should().NotContainKey("deployment.environment");
}
@@ -264,16 +287,14 @@ public void ResourceBuilderFactory_Should_Create_Minimal_Resource()
public void ResourceBuilderFactory_Should_Throw_When_Arguments_Are_Invalid()
{
var validOptions = CreateValidOptions();
- var actForNullOptions = () => ResourceBuilderFactory.Create(null!, "source", "meter");
- var actForInvalidSource = () => ResourceBuilderFactory.Create(validOptions, " ", "meter");
- var actForInvalidMeter = () => ResourceBuilderFactory.Create(validOptions, "source", "");
+ var validIdentity = ObservationIdentityResolver.Resolve(validOptions.Observation);
+ var actForNullIdentity = () => ResourceBuilderFactory.Create(null!, validOptions.Resource);
+ var actForNullResource = () => ResourceBuilderFactory.Create(validIdentity, null!);
- _ = actForNullOptions.Should().Throw()
- .WithParameterName("options");
- _ = actForInvalidSource.Should().Throw()
- .WithParameterName("activitySourceName");
- _ = actForInvalidMeter.Should().Throw()
- .WithParameterName("meterName");
+ _ = actForNullIdentity.Should().Throw()
+ .WithParameterName("identity");
+ _ = actForNullResource.Should().Throw()
+ .WithParameterName("resourceOptions");
}
[Fact]
@@ -311,7 +332,7 @@ public void TelemetryNameNormalizer_Should_Throw_When_Arguments_Are_Invalid()
public void TracerProviderBuilderExtensions_Should_Configure_All_Tracing_Branches()
{
var options = CreateFullOptions();
- var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics");
+ var resourceBuilder = CreateResourceBuilder(options);
var builder = Sdk.CreateTracerProviderBuilder();
var result = builder.ConfigureAtyaTracing(options, resourceBuilder, "Orders.Tracing");
@@ -325,7 +346,7 @@ public void TracerProviderBuilderExtensions_Should_Configure_All_Tracing_Branche
public void TracerProviderBuilderExtensions_Should_Configure_Minimal_Tracing_Branches()
{
var options = CreateValidOptions();
- var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics");
+ var resourceBuilder = CreateResourceBuilder(options);
var builder = Sdk.CreateTracerProviderBuilder();
var result = builder.ConfigureAtyaTracing(options, resourceBuilder, "Orders.Tracing");
@@ -339,7 +360,7 @@ public void TracerProviderBuilderExtensions_Should_Configure_Database_Instrument
var options = CreateValidOptions();
options.Instrumentations.SqlClient.Enabled = true;
options.Instrumentations.EntityFrameworkCore.Enabled = true;
- var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics");
+ var resourceBuilder = CreateResourceBuilder(options);
var builder = Sdk.CreateTracerProviderBuilder();
var result = builder.ConfigureAtyaTracing(options, resourceBuilder, "Orders.Tracing");
@@ -353,7 +374,7 @@ public void TracerProviderBuilderExtensions_Should_Configure_Database_Instrument
public void TracerProviderBuilderExtensions_Should_Throw_When_Arguments_Are_Invalid()
{
var options = CreateValidOptions();
- var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics");
+ var resourceBuilder = CreateResourceBuilder(options);
var builder = Sdk.CreateTracerProviderBuilder();
var actForNullBuilder = () => AtyaTracerProviderBuilderExtensions.ConfigureAtyaTracing(null!, options, resourceBuilder, "source");
@@ -375,7 +396,7 @@ public void TracerProviderBuilderExtensions_Should_Throw_When_Arguments_Are_Inva
public void MeterProviderBuilderExtensions_Should_Configure_All_Metrics_Branches()
{
var options = CreateFullOptions();
- var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics");
+ var resourceBuilder = CreateResourceBuilder(options);
var builder = Sdk.CreateMeterProviderBuilder();
var result = builder.ConfigureAtyaMetrics(options, resourceBuilder, "Orders.Metrics");
@@ -387,7 +408,7 @@ public void MeterProviderBuilderExtensions_Should_Configure_All_Metrics_Branches
public void MeterProviderBuilderExtensions_Should_Configure_Minimal_Metrics_Branches()
{
var options = CreateValidOptions();
- var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics");
+ var resourceBuilder = CreateResourceBuilder(options);
var builder = Sdk.CreateMeterProviderBuilder();
var result = builder.ConfigureAtyaMetrics(options, resourceBuilder, "Orders.Metrics");
@@ -399,7 +420,7 @@ public void MeterProviderBuilderExtensions_Should_Configure_Minimal_Metrics_Bran
public void MeterProviderBuilderExtensions_Should_Throw_When_Arguments_Are_Invalid()
{
var options = CreateValidOptions();
- var resourceBuilder = ResourceBuilderFactory.Create(options, "Orders.Tracing", "Orders.Metrics");
+ var resourceBuilder = CreateResourceBuilder(options);
var builder = Sdk.CreateMeterProviderBuilder();
var actForNullBuilder = () => MeterProviderBuilderExtensions.ConfigureAtyaMetrics(null!, options, resourceBuilder, "meter");
@@ -417,6 +438,73 @@ public void MeterProviderBuilderExtensions_Should_Throw_When_Arguments_Are_Inval
.WithParameterName("meterName");
}
+ [Fact]
+ public void LoggerProviderBuilderExtensions_Should_Configure_Through_OpenTelemetry_Builder()
+ {
+ var options = CreateFullOptions();
+ var resourceBuilder = CreateResourceBuilder(options);
+ var services = new ServiceCollection();
+ var configured = false;
+
+ _ = services.AddOpenTelemetry()
+ .WithLogging(logging =>
+ {
+ var result = logging.ConfigureAtyaLogging(options, resourceBuilder);
+ configured = ReferenceEquals(result, logging);
+ });
+
+ using var provider = services.BuildServiceProvider();
+ var loggerProviders = provider.GetServices();
+
+ _ = loggerProviders.Should().Contain(loggerProvider => loggerProvider is OpenTelemetryLoggerProvider);
+ _ = configured.Should().BeTrue();
+ }
+
+ [Fact]
+ public void LoggerProviderBuilderExtensions_Should_Throw_When_Builder_Is_Null()
+ {
+ var options = CreateValidOptions();
+ var resourceBuilder = CreateResourceBuilder(options);
+
+ var actForNullBuilder = () => AtyaLoggerProviderBuilderExtensions.ConfigureAtyaLogging(null!, options, resourceBuilder);
+
+ _ = actForNullBuilder.Should().Throw()
+ .WithParameterName("builder");
+ }
+
+ [Fact]
+ public void OpenTelemetryLoggerOptionsExtensions_Should_Apply_Log_Record_Options()
+ {
+ var loggerOptions = new OpenTelemetryLoggerOptions();
+ var options = new OpenTelemetryLoggingOptions
+ {
+ IncludeFormattedMessage = false,
+ IncludeScopes = false,
+ ParseStateValues = false,
+ };
+
+ var result = loggerOptions.ConfigureAtyaLogging(options);
+
+ _ = result.Should().BeSameAs(loggerOptions);
+ _ = loggerOptions.IncludeFormattedMessage.Should().BeFalse();
+ _ = loggerOptions.IncludeScopes.Should().BeFalse();
+ _ = loggerOptions.ParseStateValues.Should().BeFalse();
+ }
+
+ [Fact]
+ public void OpenTelemetryLoggerOptionsExtensions_Should_Throw_When_Arguments_Are_Null()
+ {
+ var loggerOptions = new OpenTelemetryLoggerOptions();
+
+ var actForNullOptions = () => loggerOptions.ConfigureAtyaLogging(null!);
+ var actForNullLoggerOptions = () => AtyaOpenTelemetryLoggerOptionsExtensions.ConfigureAtyaLogging(null!, new OpenTelemetryLoggingOptions());
+
+ _ = actForNullOptions.Should().Throw()
+ .WithParameterName("options");
+ _ = actForNullLoggerOptions.Should().Throw()
+ .WithParameterName("loggerOptions");
+ }
+
[Fact]
public void DatabaseInstrumentationEnricher_Should_Add_Query_Text_Tags_From_Database_Command()
{
@@ -488,10 +576,20 @@ private static OpenTelemetryOptions CreateValidOptions()
{
return new OpenTelemetryOptions
{
- ServiceName = "Orders.Service",
+ Observation =
+ {
+ ServiceName = "Orders.Service",
+ },
};
}
+ private static ResourceBuilder CreateResourceBuilder(OpenTelemetryOptions options)
+ {
+ return ResourceBuilderFactory.Create(
+ ObservationIdentityResolver.Resolve(options.Observation),
+ options.Resource);
+ }
+
private static OpenTelemetryOptions CreateFullOptions()
{
var options = CreateValidOptions();
@@ -505,9 +603,10 @@ private static OpenTelemetryOptions CreateFullOptions()
options.Instrumentations.EntityFrameworkCore.CaptureSqlText = true;
options.Instrumentations.GrpcClient.Enabled = true;
options.Instrumentations.Runtime.Enabled = true;
+ options.Exporters.Console.Enabled = true;
options.Exporters.Otlp.Enabled = true;
options.Exporters.Otlp.Endpoint = "http://localhost:4317";
- options.Exporters.Otlp.Protocol = "grpc";
+ options.Exporters.Otlp.Protocol = OtlpExportProtocol.Grpc;
return options;
}
}
diff --git a/tests/OpenTelemetry.UnitTests/OpenTelemetry.UnitTests.csproj b/tests/OpenTelemetry.UnitTests/OpenTelemetry.UnitTests.csproj
index 14351e6..39792a3 100644
--- a/tests/OpenTelemetry.UnitTests/OpenTelemetry.UnitTests.csproj
+++ b/tests/OpenTelemetry.UnitTests/OpenTelemetry.UnitTests.csproj
@@ -5,6 +5,7 @@
+
diff --git a/tests/OpenTelemetry.UnitTests/packages.lock.json b/tests/OpenTelemetry.UnitTests/packages.lock.json
index 9949df7..aa17d80 100644
--- a/tests/OpenTelemetry.UnitTests/packages.lock.json
+++ b/tests/OpenTelemetry.UnitTests/packages.lock.json
@@ -36,6 +36,18 @@
"Microsoft.Extensions.Primitives": "10.0.8"
}
},
+ "Microsoft.Extensions.Configuration.Json": {
+ "type": "Direct",
+ "requested": "[10.0.8, )",
+ "resolved": "10.0.8",
+ "contentHash": "KLtAZ6A38s1pIfCO2ns6aG14NNGMYNZ4PBYfFK4M+R4A+xuSc6oklhqDcpHZxvDpyBWeFtR5C8iQBw2ng8tUHQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.8",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.8",
+ "Microsoft.Extensions.Configuration.FileExtensions": "10.0.8",
+ "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8"
+ }
+ },
"Microsoft.Extensions.DependencyInjection": {
"type": "Direct",
"requested": "[10.0.8, )",
@@ -129,8 +141,8 @@
},
"Atya.Diagnostics.Logging": {
"type": "Transitive",
- "resolved": "1.0.0",
- "contentHash": "JXgn5jimNlnYA94WynXTdcp6ayybTveqTCcfxN/60fqO3ucaQ9YGf3JDVRzo0en5D6lYKwZKNZXWzo3/wnO9ew==",
+ "resolved": "1.0.1",
+ "contentHash": "PlrizTJNeGkV0jTc4iw5ceswuGqH2wV3dDfo+LUcrYCjYtgbtT8ycFfNWV4ZuPoZR5vSj4b0LGQu5dGK/B98LA==",
"dependencies": {
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
@@ -139,8 +151,8 @@
},
"Atya.Diagnostics.Metrics": {
"type": "Transitive",
- "resolved": "1.0.0",
- "contentHash": "2iT9yJeBSFnPpkszq+i9/Bp3adrqp1q85x9EgTLfsvi+FWms3e48rgvIO6zeer8Jtehe0Whur1Njn5AB4/usHQ==",
+ "resolved": "1.0.1",
+ "contentHash": "1H70t3SEcoxIPI1bD/i9Y7+NnOnAMM3YqwuK1DpHoqH+aqX5RIbDOarACJ60oyhz6HjIIGTiypN4GqhgDzRmtg==",
"dependencies": {
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
@@ -149,8 +161,8 @@
},
"Atya.Diagnostics.Tracing": {
"type": "Transitive",
- "resolved": "1.0.0",
- "contentHash": "Er7R3/oL8s1XrzrVy4h1QKEVLsNo8vFYEZ93kfl/XURyAUOapajK9UUI5azQOMDtsUK3yNtMjCqVi8V97wmEhA==",
+ "resolved": "1.0.1",
+ "contentHash": "8lGM/J451JmkWZJRDYtxJuKXcSs0P18igKB9S3EhAwUM5X4v59SIkb0Lg9eRYTae7+vQcPJvOVQNqfwXQvh/Hg==",
"dependencies": {
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
@@ -192,17 +204,6 @@
"Microsoft.Extensions.Primitives": "10.0.8"
}
},
- "Microsoft.Extensions.Configuration.Json": {
- "type": "Transitive",
- "resolved": "10.0.8",
- "contentHash": "KLtAZ6A38s1pIfCO2ns6aG14NNGMYNZ4PBYfFK4M+R4A+xuSc6oklhqDcpHZxvDpyBWeFtR5C8iQBw2ng8tUHQ==",
- "dependencies": {
- "Microsoft.Extensions.Configuration": "10.0.8",
- "Microsoft.Extensions.Configuration.Abstractions": "10.0.8",
- "Microsoft.Extensions.Configuration.FileExtensions": "10.0.8",
- "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8"
- }
- },
"Microsoft.Extensions.Configuration.UserSecrets": {
"type": "Transitive",
"resolved": "10.0.8",
@@ -281,15 +282,6 @@
"Microsoft.Extensions.Primitives": "10.0.8"
}
},
- "Microsoft.Extensions.Options.DataAnnotations": {
- "type": "Transitive",
- "resolved": "10.0.8",
- "contentHash": "HhxwIGECGGJ8ox2kvm6/hkN/w1ZyKrO5uu/rLAL51V0ypPdahoNf+dHS6Er/DJs2aeUmH38ZTTzACfLy1O6w3Q==",
- "dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
- "Microsoft.Extensions.Options": "10.0.8"
- }
- },
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "10.0.8",
@@ -366,13 +358,14 @@
"Atya.Diagnostics.OpenTelemetry": {
"type": "Project",
"dependencies": {
- "Atya.Diagnostics.Observation": "[1.0.0, )",
+ "Atya.Diagnostics.Observation": "[1.0.1, )",
"Atya.Foundation.Guards": "[1.0.0, )",
"Microsoft.Extensions.Configuration.Abstractions": "[10.0.8, )",
"Microsoft.Extensions.Configuration.Binder": "[10.0.8, )",
"Microsoft.Extensions.DependencyInjection.Abstractions": "[10.0.8, )",
"Microsoft.Extensions.Options": "[10.0.8, )",
"OpenTelemetry": "[1.15.3, )",
+ "OpenTelemetry.Exporter.Console": "[1.15.3, )",
"OpenTelemetry.Exporter.OpenTelemetryProtocol": "[1.15.3, )",
"OpenTelemetry.Extensions.Hosting": "[1.15.3, )",
"OpenTelemetry.Instrumentation.AspNetCore": "[1.15.2, )",
@@ -385,17 +378,16 @@
},
"Atya.Diagnostics.Observation": {
"type": "CentralTransitive",
- "requested": "[1.0.0, )",
- "resolved": "1.0.0",
- "contentHash": "85nmR5rEEEzwg8n76NHLv+j8sGMWx1EdfMADlhZqBvS8oPSe70N1mZ9iBFfYtMz27jN8+9YVHyIf5GI+r9nFHg==",
+ "requested": "[1.0.1, )",
+ "resolved": "1.0.1",
+ "contentHash": "Rx7dLfRsqN2eLCnHr5Yswa2w8yQUxXNgVcAvjifrULEPDWHx5ZUY4Morb/0uf2FKKn2WLtEGTh9uA2nEdEyZbg==",
"dependencies": {
- "Atya.Diagnostics.Logging": "1.0.0",
- "Atya.Diagnostics.Metrics": "1.0.0",
- "Atya.Diagnostics.Tracing": "1.0.0",
+ "Atya.Diagnostics.Logging": "1.0.1",
+ "Atya.Diagnostics.Metrics": "1.0.1",
+ "Atya.Diagnostics.Tracing": "1.0.1",
"Atya.Foundation.Guards": "1.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8",
- "Microsoft.Extensions.Options": "10.0.8",
- "Microsoft.Extensions.Options.DataAnnotations": "10.0.8"
+ "Microsoft.Extensions.Options": "10.0.8"
}
},
"Atya.Foundation.Guards": {
@@ -540,6 +532,15 @@
"OpenTelemetry.Api.ProviderBuilderExtensions": "1.15.3"
}
},
+ "OpenTelemetry.Exporter.Console": {
+ "type": "CentralTransitive",
+ "requested": "[1.15.3, )",
+ "resolved": "1.15.3",
+ "contentHash": "QBGOoPwLHDXX+hXeUpspOjsqEn4vMkLw672QN+MzVWFBzjf625DdxLxhzowS1J/dRtW93U34rRbJec+4808fkg==",
+ "dependencies": {
+ "OpenTelemetry": "1.15.3"
+ }
+ },
"OpenTelemetry.Exporter.OpenTelemetryProtocol": {
"type": "CentralTransitive",
"requested": "[1.15.3, )",