-
Notifications
You must be signed in to change notification settings - Fork 0
Serilog Extensions
MSL.Plumber.Serilog.Extensions adds one middleware that emits a single structured Serilog event when a request completes — carrying the request id, elapsed time, trace and span ids, and anything you enrich onto Serilog's DiagnosticContext during the request. It's the request-logging line you'd otherwise hand-write at the top of every pipeline.
This page covers wiring it up and the logging behavior. The full options surface lives on RequestLoggerOptions.
dotnet add package MSL.Plumber.Serilog.ExtensionsThe package targets .NET 10 and references the core MSL.Plumber.Pipeline package.
The middleware resolves Serilog's ILogger and DiagnosticContext from the pipeline's service provider, so register Serilog in ConfigureServices with AddSerilog before you register the middleware:
using Plumber;
using Plumber.Serilog.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Serilog;
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateLogger();
using var handler = RequestHandlerBuilder.Create<MyRequest, MyResponse>()
.ConfigureServices((services, _) => services.AddSerilog(Log.Logger))
.Build()
.UseSerilogRequestLogging()
.Use<ValidationMiddleware>()
.Use<ProcessingMiddleware>();
var response = await handler.InvokeAsync(request);AddSerilog (from Serilog.Extensions.Hosting) registers both the ILogger and the DiagnosticContext the middleware needs. Skip it and the middleware throws on first invocation when those dependencies fail to resolve.
The request type must be a reference type — the extension methods constrain TRequest : class.
Register UseSerilogRequestLogging first, as the outermost middleware. It wraps the rest of the pipeline in a try/catch and logs once on the way out, so registering it first lets it observe the whole pipeline's outcome — including exceptions thrown by anything downstream. Elapsed time comes from context.Elapsed, measured from the start of the request (see Request lifecycle), so the timing is whole-request regardless of placement.
One event per request, when the pipeline returns or throws:
- A success completes at the configured
LogLevel(defaultInformation). - A failure completes at
Error, with the exception attached, then rethrows unless you setThrowOnExceptiontofalse.
Every event carries the message-template properties (by default RequestId from context.Id and Elapsed from context.Elapsed.TotalMilliseconds), plus the current Activity trace id and span id when one is in flight — so request logs line up with distributed traces with no extra work.
Anything written to the DiagnosticContext during the request attaches to that single completion event. Use EnrichDiagnosticContext to add request- and response-derived properties:
handler.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = (diagnosticContext, context) =>
{
diagnosticContext.Set("Request", context.Request);
diagnosticContext.Set("Response", context.Response);
};
});One completion event then carries Request, Response, RequestId, Elapsed, and the trace ids — a single line that describes the whole request rather than a scatter of log statements.
Two ways to supply RequestLoggerOptions:
- Inline, per registration — pass an
Action<RequestLoggerOptions<TRequest, TResponse>>toUseSerilogRequestLogging, as above. Inline options take precedence. - From the container — register
Configure<RequestLoggerOptions<MyRequest, MyResponse>>(...)inConfigureServicesand call the parameterlessUseSerilogRequestLogging(). The middleware resolves them asIOptions<T>.
Call the parameterless overload with nothing registered and the middleware runs on the defaults baked into RequestLoggerOptions.
- RequestLoggerOptions — the full options surface: level, message template, enrichment, exception handling
-
Request lifecycle —
RequestContext,Elapsed,Id, and the cancellation token the middleware honors -
Middleware —
Use<T>registration and pipeline ordering -
Building a pipeline —
ConfigureServicesand the builder surface
Documents Plumber v4.x · Repository · MIT License · Report an issue
Getting Started
Pipeline (core)
Testing
Serilog Extensions
Diagnostics
Recipes
- AWS Lambda — API Gateway
- AWS Lambda — SQS
- Azure Functions — HTTP
- SQS polling console
- ASP.NET Core integration
- BackgroundService worker
- Webhook receiver
- Multi-command CLI
- File watcher
- Configuration reload
Repo · NuGet · NuGet — Testing · NuGet — Serilog · NuGet — Diagnostics