IronAlpine.Framework.Observability 3.0.6

There is a newer version of this package available.
See the version list below for details.
dotnet add package IronAlpine.Framework.Observability --version 3.0.6
                    
NuGet\Install-Package IronAlpine.Framework.Observability -Version 3.0.6
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="IronAlpine.Framework.Observability" Version="3.0.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="IronAlpine.Framework.Observability" Version="3.0.6" />
                    
Directory.Packages.props
<PackageReference Include="IronAlpine.Framework.Observability" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add IronAlpine.Framework.Observability --version 3.0.6
                    
#r "nuget: IronAlpine.Framework.Observability, 3.0.6"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package IronAlpine.Framework.Observability@3.0.6
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=IronAlpine.Framework.Observability&version=3.0.6
                    
Install as a Cake Addin
#tool nuget:?package=IronAlpine.Framework.Observability&version=3.0.6
                    
Install as a Cake Tool

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.6, net10.0, references Microsoft.AspNetCore.App)
  • Depends on: Kernel, Mediator, Serilog.AspNetCore 9, OpenTelemetry 1.16, Polly 8

Installation

<PackageReference Include="IronAlpine.Framework.Observability" Version="3.0.6" />

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 (section IronAlpine:Logging:Serilog), the masking destructuring policy and the event-metadata enricher (AddIronAlpineSerilog);
  • configures Serilog with ReadFrom.Configuration (the standard Serilog section: Using, MinimumLevel, WriteTo, Enrich, Properties), Enrich.FromLogContext(), Application property (service name), EnvironmentName, ThreadId;
  • adds TraceId, CorrelationId, CausationId, TenantId to every event when an IEventMetadataProvider is registered (the Web package registers one);
  • adds an OpenTelemetry sink to IronAlpine:Observability:OpenTelemetry:OtlpEndpoint (or OpenTelemetry:OtlpEndpoint) unless Serilog:WriteTo already contains an OpenTelemetry sink;
  • adds a Seq sink to Serilog:WriteTo:Seq:Args:serverUrl (or Seq:ServerUrl) unless Serilog:WriteTo already contains a Seq sink.

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}" - with Payload: {@Request} when LogRequestPayloads is true (the default);
  • Information "completed successfully in {ElapsedMilliseconds}ms" for successful Results and non-Result responses;
  • Warning "failed with error {ErrorCode} ... {@Error}" for failed Results;
  • 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 bus ActivitySource (IronAlpine.Eventbus, TelemetryExtensions.EventBusActivitySourceName), an activity processor that adds correlation.id, causation.id, tenant.id tags from IEventMetadataProvider; OTLP exporter when OtlpEndpoint is set (IronAlpine:Observability:OpenTelemetry:OtlpEndpoint, fallback OpenTelemetry:OtlpEndpoint);
  • metrics: ASP.NET Core, runtime, Prometheus exporter (only when EnablePrometheusScrapingEndpoint is true).

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 from ResilienceOptions.Policies[name], falling back to the default policy 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>, ExecuteHttpAsync extension 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.IAuditUser is [Obsolete] since 3.0.5; use IronAlpine.Kernel.Primitives.IAuditUser (the only contract the data layer and Security use).
  • IronAlpine.Observability.Runtime.AsyncLocalEventMetadataAccessor and DefaultExecutionModeDetector are the canonical implementations; the copies in IronAlpine.Web.Runtime are [Obsolete] since 3.0.5.

Pitfalls

  • Up to 3.0.4 EnablePrometheusScrapingEndpoint and PrometheusScrapingEndpointPath had 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 /metrics while a different path was configured.
  • LogRequestPayloads defaults to true; request payloads are logged at Information.
  • Masking matches exact property names only.
  • Retry.MaxRetryAttempts = 0 means "no retries": the pipeline is built without a retry strategy (circuit breaker and timeout still apply). Negative values fail validation. Use "Enabled": false to turn the whole policy off.
  • Without the Web package (or your own IEventMetadataProvider), logs and spans carry no correlation properties.
Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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 192 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
Loading failed

IronAlpine framework release. See the package README and repository documentation for details.