IronAlpine.Framework.Observability
3.0.7
See the version list below for details.
dotnet add package IronAlpine.Framework.Observability --version 3.0.7
NuGet\Install-Package IronAlpine.Framework.Observability -Version 3.0.7
<PackageReference Include="IronAlpine.Framework.Observability" Version="3.0.7" />
<PackageVersion Include="IronAlpine.Framework.Observability" Version="3.0.7" />
<PackageReference Include="IronAlpine.Framework.Observability" />
paket add IronAlpine.Framework.Observability --version 3.0.7
#r "nuget: IronAlpine.Framework.Observability, 3.0.7"
#:package IronAlpine.Framework.Observability@3.0.7
#addin nuget:?package=IronAlpine.Framework.Observability&version=3.0.7
#tool nuget:?package=IronAlpine.Framework.Observability&version=3.0.7
IronAlpine.Framework.Observability
Serilog host setup with correlation enrichment and sensitive-data masking, the mediator logging behaviour, OpenTelemetry tracing/metrics with a Prometheus endpoint, and named Polly resilience pipelines.
- Package id:
IronAlpine.Framework.Observability(3.0.7,net10.0, referencesMicrosoft.AspNetCore.App) - Depends on: Kernel, Mediator, Serilog.AspNetCore 9, OpenTelemetry 1.16, Polly 8
Installation
<PackageReference Include="IronAlpine.Framework.Observability" Version="3.0.7" />
Quick start
using IronAlpine.Observability; // UseLoggingBehavior
using IronAlpine.Observability.Extensions; // UseIronAlpineSerilog, AddIronAlpineTelemetry, AddIronAlpineResilience, UseIronAlpineTelemetry
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseIronAlpineSerilog("orders-service");
builder.Services
.AddIronAlpineTelemetry(builder.Configuration, "orders-service")
.AddIronAlpineResilience(builder.Configuration);
builder.Services.AddIronAlpineMediator(cfg =>
{
cfg.RegisterServicesFromAssembly(applicationAssembly);
cfg.UseLoggingBehavior(); // first = outermost
});
var app = builder.Build();
app.UseIronAlpineTelemetry(); // Prometheus scraping endpoint
Logging (Serilog)
IHostBuilder.UseIronAlpineSerilog(serviceName = null, configure = null):
- registers
IronAlpineSerilogOptions(sectionIronAlpine:Logging:Serilog), the masking destructuring policy and the event-metadata enricher (AddIronAlpineSerilog); - configures Serilog with
ReadFrom.Configuration(the standardSerilogsection:Using,MinimumLevel,WriteTo,Enrich,Properties),Enrich.FromLogContext(),Applicationproperty (service name),EnvironmentName,ThreadId; - adds
TraceId,CorrelationId,CausationId,TenantIdto every event when anIEventMetadataProvideris registered (the Web package registers one); - adds an OpenTelemetry sink to
IronAlpine:Observability:OpenTelemetry:OtlpEndpoint(orOpenTelemetry:OtlpEndpoint) unlessSerilog:WriteToalready contains anOpenTelemetrysink; - adds a Seq sink to
Serilog:WriteTo:Seq:Args:serverUrl(orSeq:ServerUrl) unlessSerilog:WriteToalready contains aSeqsink.
Service name precedence: IronAlpine:Logging:Serilog:ServiceName → serviceName argument → entry assembly name.
{
"Serilog": {
"Using": [ "Serilog.Sinks.Console" ],
"MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "System": "Warning" } },
"WriteTo": [ { "Name": "Console", "Args": { "formatter": "Serilog.Formatting.Json.JsonFormatter, Serilog" } } ]
},
"IronAlpine": {
"Logging": {
"Serilog": {
"ServiceName": "orders-service",
"LogRequestPayloads": true,
"MaskValue": "***",
"SensitivePropertyNames": [ "iban", "nationalId" ]
}
}
}
}
Sinks other than OpenTelemetry and Seq (for example Console or File) must be configured in the Serilog section;
the package references Serilog.Sinks.OpenTelemetry and Serilog.Sinks.Seq only (Console comes with
Serilog.AspNetCore).
Masking
SensitiveDataDestructuringPolicy replaces the value of properties whose name equals an entry of
SensitivePropertyNames (case-insensitive) with MaskValue when an object is destructured ({@Request}). Defaults:
password, secret, token, accessToken, refreshToken, apiKey, authorization, cookie, clientSecret,
connectionString; configured names are added to them. Names are not matched as substrings (newPassword is not
masked unless listed). Types in System.* namespaces, value types and collections themselves are not handled by the
policy (their elements are).
Mediator logging behaviour
cfg.UseLoggingBehavior() adds LoggingBehavior<TRequest, TResponse> (TResponse : class):
Information"Handling request {RequestName}" - withPayload: {@Request}whenLogRequestPayloadsistrue(the default);Information"completed successfully in {ElapsedMilliseconds}ms" for successfulResults and non-Resultresponses;Warning"failed with error {ErrorCode} ... {@Error}" for failedResults;- exceptions are not caught (they are logged by the exception middleware of the Web package).
Set LogRequestPayloads to false when requests carry personal data.
Tracing and metrics (OpenTelemetry)
AddIronAlpineTelemetry(configuration, serviceName = null, configure = null) (an overload without configuration
exists):
- forces W3C trace ids (
Activity.DefaultIdFormat); - resource
service.name=IronAlpine:Observability:OpenTelemetry:ServiceName→serviceName→ entry assembly; - tracing: ASP.NET Core,
HttpClient, EF Core instrumentation, the event busActivitySource(IronAlpine.Eventbus,TelemetryExtensions.EventBusActivitySourceName), an activity processor that addscorrelation.id,causation.id,tenant.idtags fromIEventMetadataProvider; OTLP exporter whenOtlpEndpointis set (IronAlpine:Observability:OpenTelemetry:OtlpEndpoint, fallbackOpenTelemetry:OtlpEndpoint); - metrics: ASP.NET Core, runtime, Prometheus exporter (only when
EnablePrometheusScrapingEndpointistrue).
The resolved options are registered both as IronAlpineTelemetryOptions and as IOptions<IronAlpineTelemetryOptions>.
app.UseIronAlpineTelemetry() maps the Prometheus scraping endpoint at PrometheusScrapingEndpointPath (default
/metrics) only when EnablePrometheusScrapingEndpoint is true (default).
{
"IronAlpine": {
"Observability": {
"OpenTelemetry": {
"ServiceName": "orders-service",
"OtlpEndpoint": "http://otel-collector:4317",
"EnablePrometheusScrapingEndpoint": true,
"PrometheusScrapingEndpointPath": "/metrics"
}
}
}
}
Add more sources with the standard OpenTelemetry builder; AddOpenTelemetry() can be called again:
builder.Services.AddOpenTelemetry().WithTracing(tracing => tracing.AddSource("MyCompany.Orders"));
Event metadata
EventMetadataContext(TraceId, CorrelationId, CausationId, TenantId, TraceParent, TraceState, Baggage) describes the
current request or message. IEventMetadataProvider.GetCurrent() reads it, IEventMetadataAccessor also sets and
clears it. AsyncLocalEventMetadataAccessor (IronAlpine.Observability.Runtime) is an async-local implementation for
non-HTTP hosts:
services.AddSingleton<AsyncLocalEventMetadataAccessor>();
services.AddSingleton<IEventMetadataAccessor>(sp => sp.GetRequiredService<AsyncLocalEventMetadataAccessor>());
services.AddSingleton<IEventMetadataProvider>(sp => sp.GetRequiredService<AsyncLocalEventMetadataAccessor>());
The Web package registers an HTTP-aware implementation (HttpEventMetadataProvider) that reads X-Correlation-ID,
X-Causation-ID, X-Tenant-ID, traceparent, tracestate and baggage.
Resilience (Polly)
builder.Services.AddIronAlpineResilience(builder.Configuration, policies => policies
.AddHttpPipeline("payments-api", b => b
.AddRetry(new RetryStrategyOptions<HttpResponseMessage> { MaxRetryAttempts = 2 })
.AddTimeout(TimeSpan.FromSeconds(5))));
public sealed class PaymentsClient(HttpClient http, IResiliencePipelineProvider resilience)
{
public async Task<HttpResponseMessage> CaptureAsync(Guid id, CancellationToken ct)
=> await resilience.ExecuteHttpAsync(
ResiliencePolicyNames.HttpDefault,
token => new ValueTask<HttpResponseMessage>(http.PostAsync($"payments/{id}/capture", null, token)),
ct);
public ValueTask<int> CountAsync(CancellationToken ct)
=> resilience.ExecuteAsync("default", token => new ValueTask<int>(42), ct);
}
Overloads of AddIronAlpineResilience: (configuration), (Action<ResilienceOptions>),
(configuration, Action<ResilienceOptions>), (configuration, Action<IResiliencePolicyRegistry>),
(configuration, Action<ResilienceOptions>, Action<IResiliencePolicyRegistry>),
(Action<ResilienceOptions>, Action<IResiliencePolicyRegistry>). Only one call may register custom pipelines.
IResiliencePipelineProvider:
GetPipeline(name)/GetHttpPipeline(name)return a custom pipeline from the registry if one exists, otherwise build one fromResilienceOptions.Policies[name], falling back to thedefaultpolicy for unknown names. Pipelines are cached and rebuilt when options change.- Built pipelines: retry (outermost; handles every exception except
OperationCanceledException; HTTP pipelines also retry 408, 429, 500, 502, 503, 504) → circuit breaker (when enabled) → timeout (per attempt, when enabled). ExecuteAsync,ExecuteAsync<TResult>,ExecuteHttpAsyncextension methods (ResiliencePipelineProviderExtensions).
Section IronAlpine:Resilience (validated on start). Built-in policy names (ResiliencePolicyNames): default,
http-default, kafka-producer, kafka-consumer, outbox-processing, inbox-processing, save-changes. Configured
policies are merged into these defaults.
{
"IronAlpine": {
"Resilience": {
"Policies": {
"default": {
"Enabled": true,
"Retry": { "MaxRetryAttempts": 3, "BaseDelaySeconds": 1, "MaxDelaySeconds": 30, "BackoffType": "Exponential", "UseJitter": true },
"CircuitBreaker": { "Enabled": false, "FailureRatio": 0.5, "MinimumThroughput": 20, "SamplingDurationSeconds": 30, "BreakDurationSeconds": 30 },
"Timeout": { "Enabled": true, "TimeoutSeconds": 30 }
},
"payments-api": { "Retry": { "MaxRetryAttempts": 2 }, "Timeout": { "TimeoutSeconds": 5 } }
}
}
}
}
The named Kafka, outbox, inbox and save-changes policies are defaults for application code; the EventBus and Data packages do not use them (they have their own retry settings).
Other contracts
IExecutionModeDetector/DefaultExecutionModeDetector(IronAlpine.Observability.Runtime) detects EF Core design-time execution (dotnet ef) so start-up code can skip work that needs live infrastructure. It is not registered automatically.IronAlpine.Observability.Contracts.IAuditUseris[Obsolete]since 3.0.5; useIronAlpine.Kernel.Primitives.IAuditUser(the only contract the data layer and Security use).IronAlpine.Observability.Runtime.AsyncLocalEventMetadataAccessorandDefaultExecutionModeDetectorare the canonical implementations; the copies inIronAlpine.Web.Runtimeare[Obsolete]since 3.0.5.
Pitfalls
- Up to 3.0.4
EnablePrometheusScrapingEndpointandPrometheusScrapingEndpointPathhad no effect (the endpoint was always/metrics) and event bus activities were not traced unless the source was added manually. Both are fixed in 3.0.5; check scrape configurations that relied on/metricswhile a different path was configured. LogRequestPayloadsdefaults totrue; request payloads are logged atInformation.- Masking matches exact property names only.
Retry.MaxRetryAttempts = 0means "no retries": the pipeline is built without a retry strategy (circuit breaker and timeout still apply). Negative values fail validation. Use"Enabled": falseto turn the whole policy off.- Without the Web package (or your own
IEventMetadataProvider), logs and spans carry no correlation properties.
| 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
- IronAlpine.Framework.Kernel (>= 3.0.7)
- IronAlpine.Framework.Mediator (>= 3.0.7)
- OpenTelemetry.Exporter.OpenTelemetryProtocol (>= 1.16.0)
- OpenTelemetry.Exporter.Prometheus.AspNetCore (>= 1.16.0-beta.1)
- OpenTelemetry.Extensions.Hosting (>= 1.16.0)
- OpenTelemetry.Instrumentation.AspNetCore (>= 1.16.0)
- OpenTelemetry.Instrumentation.EntityFrameworkCore (>= 1.16.0-beta.1)
- OpenTelemetry.Instrumentation.Http (>= 1.16.0)
- OpenTelemetry.Instrumentation.Runtime (>= 1.16.0)
- Polly (>= 8.6.2)
- Serilog.AspNetCore (>= 9.0.0)
- Serilog.Enrichers.Environment (>= 3.0.1)
- Serilog.Enrichers.Span (>= 3.1.0)
- Serilog.Enrichers.Thread (>= 4.0.0)
- Serilog.Sinks.OpenTelemetry (>= 4.2.0)
- Serilog.Sinks.Seq (>= 9.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on IronAlpine.Framework.Observability:
| Package | Downloads |
|---|---|
|
IronAlpine.Framework.Web
ASP.NET Core defaults, Swagger, health checks, correlation middleware, and YARP gateway transform for IronAlpine microservices. Single entry point: AddIronAlpineWebDefaults + UseIronAlpineWebDefaults. All implementations internal. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.1.1 | 176 | 10/21/2026 |
| 3.0.9 | 200 | 10/15/2026 |
| 3.0.8 | 98 | 10/13/2026 |
| 3.0.7 | 78 | 10/13/2026 |
| 3.0.6 | 89 | 10/9/2026 |
| 3.0.5 | 169 | 10/5/2026 |
| 3.0.4 | 189 | 10/2/2026 |
| 3.0.3 | 150 | 9/30/2026 |
| 3.0.2 | 1,030 | 7/22/2026 |
| 3.0.1 | 99 | 7/22/2026 |
| 3.0.0 | 306 | 7/20/2026 |
| 2.0.3 | 100 | 7/20/2026 |
| 2.0.2 | 128 | 7/13/2026 |
| 2.0.1 | 134 | 7/13/2026 |
| 2.0.0 | 117 | 7/13/2026 |
| 2.0.0-preview.2 | 80 | 7/13/2026 |
| 2.0.0-preview.1 | 81 | 7/6/2026 |
| 1.0.2 | 105 | 7/3/2026 |
| 1.0.1 | 99 | 7/3/2026 |
IronAlpine framework release. See the package README and repository documentation for details.