PANiXiDA.Core.Observability
2.1.1
See the version list below for details.
<Sdk Name="PANiXiDA.Core.Observability" Version="2.1.1" />
#:sdk PANiXiDA.Core.Observability@2.1.1
PANiXiDA.Core.Observability
PANiXiDA.Core.Observability is an MSBuild SDK package that adds PANiXiDA host observability conventions on top of OpenTelemetry.
It is intended for ASP.NET Core services that need consistent logging, metrics, tracing, resource metadata, and OTLP exporter wiring without duplicating bootstrap code in every service.
The same package and assembly also support Blazor WebAssembly clients.
Status
Overview
The package configures OpenTelemetry for ASP.NET Core hosts with:
- resource metadata based on OpenTelemetry resource defaults, application assembly version, and machine name;
- ASP.NET Core, HTTP client, runtime, and Npgsql instrumentation;
- Wolverine and Quartz 4.x metrics and traces when the application uses these libraries;
- OpenTelemetry logging with formatted messages, scopes, and parsed state values;
- OTLP exporters for logs, metrics, and traces;
- configuration-driven OTLP exporter options through standard OpenTelemetry keys.
Requirements
- .NET 10 SDK
- ASP.NET Core application using
WebApplicationBuilder, or a Blazor WebAssembly client usingWebAssemblyHostBuilder - OTLP-compatible collector or backend when telemetry export is enabled
Installation
Set the SDK version in global.json:
{
"msbuild-sdks": {
"PANiXiDA.Core.Observability": "2.1.1"
}
}
Add to each host .csproj, keeping its existing primary SDK and net10.0 target:
<Sdk Name="PANiXiDA.Core.Observability" />
The SDK resolves through configured NuGet feeds and selects server or browser dependencies.
Quick Start
using PANiXiDA.Core.Observability;
var builder = WebApplication.CreateBuilder(args);
builder.AddObservability();
var app = builder.Build();
app.MapGet("/", () => Results.Ok());
app.Run();
service.version is resolved from Assembly.GetEntryAssembly(), which points to the application entry assembly for a normal ASP.NET Core host.
Usage
Typical ASP.NET Core Host
using PANiXiDA.Core.Observability;
var builder = WebApplication.CreateBuilder(args);
builder.AddObservability();
builder.Services.AddHealthChecks();
var app = builder.Build();
app.MapHealthChecks("/health");
app.MapGet("/orders/{id:guid}", (Guid id) => Results.Ok(new { id }));
app.Run();
Set the service name outside the package with OpenTelemetry resource configuration:
OTEL_SERVICE_NAME=orders-api
Blazor WebAssembly
using PANiXiDA.Core.Observability.WebAssembly;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.AddObservability();
var host = builder.Build();
host.UseObservability();
await host.RunAsync();
Enable in the client .csproj:
<PropertyGroup>
<MetricsSupport>true</MetricsSupport>
<EventSourceSupport>true</EventSourceSupport>
<HttpActivityPropagationSupport>true</HttpActivityPropagationSupport>
</PropertyGroup>
Configure public wwwroot/appsettings.json:
{
"OTEL_SERVICE_NAME": "admin-client",
"OTEL_EXPORTER_OTLP_ENDPOINT": "/telemetry",
"OpenTelemetry": {
"Otlp": { "MaxRequestSizeBytes": 1048576 }
}
}
The client collects Blazor/HTTP telemetry and application logs. Export is disabled
without an endpoint; enabled export requires a nonblank service name. Options
validation checks the name, HTTP/HTTPS endpoint, and optional request limit.
Relative endpoints use the app base address. A BFF can forward the v1/logs,
v1/metrics, and v1/traces requests to a collector. Match the limit with the
BFF/collector limits and keep collector credentials on the server.
Browser telemetry relay
On a BFF, set BrowserTelemetry:Enabled to true, configure CollectorEndpoint
(an internal HTTP/HTTPS URL) and ServiceName, then call app.MapBrowserTelemetry()
after Build(). The existing builder.AddObservability() registers the relay.
Other servers leave it disabled. Session middleware can recognize relay requests
with request.IsBrowserTelemetryRequest() instead of checking URL prefixes.
The relay requires authentication, enforces same-origin protobuf requests, and
forwards only the body and server-owned frontend identity. AuthorizationPolicy
optionally names a host policy, including its authentication schemes. Failures return
401/403 without login redirects. Defaults: Path=/telemetry, MaxRequestBodySize=1048576,
RequestsPerMinute=120, RequestTimeout=00:00:05. Use the same path in the browser
exporter and align body limits with the collector. The host configures authentication;
relay traffic should not renew its session. YARP spans are collected automatically.
Configuration
Service Name
Set service.name through the standard OpenTelemetry resource key:
OTEL_SERVICE_NAME=orders-api
or:
OTEL_RESOURCE_ATTRIBUTES=service.name=orders-api
In appsettings.json, use flat OpenTelemetry keys such as OTEL_SERVICE_NAME; nested keys are not equivalent.
The package does not define a custom OpenTelemetry:ServiceName key. If no OpenTelemetry service name is configured, builder.Environment.ApplicationName is used as the fallback service name required by AddService.
OTLP Exporter
The package does not hard-code OTLP endpoint, protocol, headers, or timeout values. Configure them through standard OpenTelemetry configuration keys.
Wolverine
AddObservability() subscribes to the Wolverine activity source and the
Wolverine* meters. Wolverine names its meters Wolverine:{ApplicationName}, so
the wildcard also collects metrics from application-specific meter names. These
signals use the same configured OTLP exporters as the rest of the application.
No Wolverine package dependency or additional registration is required in this
observability package; applications without Wolverine emit no Wolverine signals.
Wolverine logs already use the standard ILogger pipeline and are exported by
the existing OpenTelemetry logging provider. Normal application logging filters
still apply, including message-type categories used by Wolverine handlers.
Enabling metrics and traces does not change logging levels.
The built-in wolverine-dead-letter-queue metric counts messages moved to a dead
letter queue; it does not measure the number of messages currently stored there.
Exporting it does not add a DLQ backlog gauge or configure alert thresholds.
See Wolverine instrumentation and metrics.
Quartz
AddObservability() subscribes to the Quartz activity source and meter used by
Quartz 4.x. Job and scheduler metrics and traces use the existing OTLP exporters;
this package does not require a Quartz dependency or a separate instrumentation
package. Quartz 3.x instrumentation is not covered by these subscriptions.
Quartz logs already use ILogger and follow the configured logging filters.
Exporting the built-in signals does not add last-success tracking, job deadlines,
or alert rules.
See Quartz observability.
Production Minimum
No OTLP exporter key is mandatory when the collector is available at the OpenTelemetry defaults. In production, configure only the values that differ from those defaults.
Usually required for a deployed service:
OTEL_SERVICE_NAME, so the service has a stableservice.name;OTEL_EXPORTER_OTLP_ENDPOINTwhen the collector is not available at the default local endpoint.
Minimal appsettings.json example for a service exporting to a gRPC collector:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"OTEL_SERVICE_NAME": "orders-api",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector:4317"
}
OTEL_SERVICE_NAME can be provided either as a real environment variable or as a flat appsettings.json key. For containers and Kubernetes, prefer deployment environment variables so the same package binary can run with different service names.
Keep OTEL keys flat in appsettings.json. A nested structure such as OTEL:EXPORTER:OTLP:ENDPOINT produces a different IConfiguration key and is not the same as OTEL_EXPORTER_OTLP_ENDPOINT.
Defaults provided by OpenTelemetry are usually enough for processor and reader settings:
OTEL_EXPORTER_OTLP_PROTOCOLdefaults togrpc.OTEL_EXPORTER_OTLP_ENDPOINTdefaults tohttp://localhost:4317for gRPC andhttp://localhost:4318for HTTP/protobuf.OTEL_EXPORTER_OTLP_TIMEOUTdefaults to10000milliseconds.- metrics export interval defaults to
60000milliseconds. - tracing and logging exporters use batch processing by default.
Set OTEL_EXPORTER_OTLP_PROTOCOL only when using HTTP/protobuf, typically with port 4318:
{
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector:4318",
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf"
}
Client Cancellation Logs
AddObservability registers an HTTP context accessor and normalizes cancellation logs before OTLP batch export. An Error record becomes Information only when the current HTTP request's RequestAborted token is canceled and the exception is either OperationCanceledException (including TaskCanceledException) or a nonempty AggregateException containing only cancellations, including nested aggregates.
The record is retained with its original message, exception, stack trace, attributes, scopes, timestamp, and trace/span IDs. Npgsql cancellations represented by OperationCanceledException with an inner PostgresException follow the same rule.
Background cancellations, cancellations without an aborted request, database timeouts, bare database exceptions, unknown wrappers, empty or mixed aggregates, and unrelated application failures retain their original level. Other levels, including Critical, are unchanged. This normalization applies only to OpenTelemetry logs; console and other logging providers are unaffected. Application logging filters still apply before this processor.
Optional Tuning
Set these only when your backend or operating requirements need them:
{
"OTEL_EXPORTER_OTLP_HEADERS": "api-key=secret",
"OTEL_EXPORTER_OTLP_TIMEOUT": "10000",
"OTEL_BSP_SCHEDULE_DELAY": "5000",
"OTEL_BSP_EXPORT_TIMEOUT": "30000",
"OTEL_BLRP_SCHEDULE_DELAY": "5000",
"OTEL_BLRP_EXPORT_TIMEOUT": "30000",
"OTEL_METRIC_EXPORT_INTERVAL": "60000",
"OTEL_METRIC_EXPORT_TIMEOUT": "30000"
}
The same OTLP values can be provided as environment variables:
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
OTEL_EXPORTER_OTLP_HEADERS=api-key=secret
OTEL_EXPORTER_OTLP_TIMEOUT=10000
Use signal-specific keys in appsettings.json only when logs, metrics, and traces need different endpoints. These keys are supported by OpenTelemetry .NET UseOtlpExporter; if all signals use the same collector, prefer OTEL_EXPORTER_OTLP_ENDPOINT.
{
"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "http://traces-collector:4317",
"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT": "http://metrics-collector:4317",
"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT": "http://logs-collector:4317"
}
For HTTP/protobuf signal-specific endpoints, provide the full signal path and configure the protocol:
{
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "http://traces-collector:4318/v1/traces",
"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT": "http://metrics-collector:4318/v1/metrics",
"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT": "http://logs-collector:4318/v1/logs"
}
OpenTelemetry .NET reads these keys through IConfiguration, so they may come from environment variables, command-line arguments, or appsettings.json.
Public API
AddObservability
public static WebApplicationBuilder AddObservability(
this WebApplicationBuilder builder)
Behavior:
- configures OpenTelemetry resource metadata using the entry assembly version when available;
- adds ASP.NET Core, HTTP client, Npgsql, and runtime instrumentation;
- subscribes to Wolverine and Quartz 4.x metrics and traces and YARP traces without dependencies on these libraries;
- adds the OTLP exporter for logging, metrics, and tracing through OpenTelemetry
UseOtlpExporter; - returns the same
WebApplicationBuilderinstance for chaining.
Production Notes
- Run an OTLP collector or backend outside this package.
- Keep endpoints, protocols, headers, and credentials in environment-specific configuration.
- Prefer HTTP/protobuf on port
4318or gRPC on port4317, depending on the collector setup. - Ensure application logging filters are configured intentionally, because OpenTelemetry logging follows normal
ILoggerfiltering. - Treat exporter headers as secrets when they contain tokens or API keys.
Project Structure
.
|-- src/
| `-- PANiXiDA.Core.Observability/
|-- tests/
| `-- PANiXiDA.Core.Observability.UnitTests/
|-- Directory.Build.props
|-- Directory.Build.targets
|-- Directory.Packages.props
|-- global.json
|-- version.json
|-- README.md
|-- LICENSE
`-- icon.png
Development
Build
dotnet restore
dotnet build --configuration Release
Format
dotnet format
Test
dotnet test --configuration Release
Coverage
dotnet test --configuration Release --coverage --coverage-output coverage.xml --coverage-output-format xml
Pack
dotnet pack --configuration Release
Continuous integration
Every pull request and push to main runs formatting, tests, and mandatory
SonarQube analysis. Publishing from main starts only after the SonarQube
Quality Gate succeeds.
License
This project is licensed under the Apache-2.0 license.
See the LICENSE file for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.1.7 | 0 | 11/9/2026 |
| 2.1.6 | 1,670 | 10/28/2026 |
| 2.1.5 | 346 | 10/27/2026 |
| 2.1.4 | 394 | 10/27/2026 |
| 2.1.3 | 269 | 10/27/2026 |
| 2.1.2 | 526 | 10/27/2026 |
| 2.1.1 | 118 | 10/26/2026 |
| 2.0.1 | 134 | 10/26/2026 |
| 1.0.8 | 202 | 10/11/2026 |
| 1.0.7 | 124 | 10/11/2026 |
| 1.0.6 | 134 | 10/9/2026 |
| 1.0.5 | 132 | 10/8/2026 |
| 1.0.4 | 318 | 8/28/2026 |
| 1.0.3 | 319 | 6/13/2026 |
| 1.0.2 | 148 | 6/13/2026 |