Enigma.Logging.Serilog
1.0.0
dotnet add package Enigma.Logging.Serilog --version 1.0.0
NuGet\Install-Package Enigma.Logging.Serilog -Version 1.0.0
<PackageReference Include="Enigma.Logging.Serilog" Version="1.0.0" />
<PackageVersion Include="Enigma.Logging.Serilog" Version="1.0.0" />
<PackageReference Include="Enigma.Logging.Serilog" />
paket add Enigma.Logging.Serilog --version 1.0.0
#r "nuget: Enigma.Logging.Serilog, 1.0.0"
#:package Enigma.Logging.Serilog@1.0.0
#addin nuget:?package=Enigma.Logging.Serilog&version=1.0.0
#tool nuget:?package=Enigma.Logging.Serilog&version=1.0.0
Enigma.Logging.Serilog
Enigma.Logging.Serilog builds Serilog-backed
Microsoft.Extensions.Logging
loggers through a small fluent builder. You add one or more Serilog sinks, then build a disposable
handle that owns the underlying Serilog logger and hands you a ready-to-use ILogger.
Built on Serilog 4.x. The handle implements the shared
Enigma.Logging.Abstractions contract
(ILoggerHandle), so consuming code can stay provider-neutral.
What's new in 1.0 — first release of the Enigma.Logging umbrella: Serilog-backed MEL loggers via a fluent sink builder + DI helper. See the release notes.
Install
dotnet add package Enigma.Logging.Serilog
Quick start
Add sinks, then build a logger. The Build* methods return a LoggerHandle — dispose it at
application shutdown so buffered sinks are flushed and closed (see Dispose).
using Enigma.Logging.Serilog;
using var handle = new LoggerProviderBuilder()
.AddConsole()
.AddFile("Logs/app.log")
.BuildLogger("myLogger");
ILogger logger = handle.Logger;
logger.LogInformation("Hello from Enigma.Logging.Serilog");
Each typed sink applies LoggerProviderBuilder.DefaultOutputTemplate by default — a ready-made
output template including timestamp, level, source context, message, and exception details. Pass your
own outputTemplate to override it.
Getting loggers from the handle
LoggerHandle gives you three ways to obtain loggers, all routed through the same owned
SerilogLoggerProvider:
// The logger built with the name passed to BuildLogger(...)
ILogger logger = handle.Logger;
// A categorized logger by type — category is typeof(T).FullName
ILogger<MyService> typed = handle.CreateLogger<MyService>();
// The underlying ILoggerFactory, e.g. for a category name
ILogger byName = handle.Factory.CreateLogger("Custom.Category");
The logger category name becomes Serilog's SourceContext, which drives
logger name scoping. Factory and CreateLogger<T> throw
ObjectDisposedException once the handle has been disposed.
Available sink extensions
Each extension takes an optional outputTemplate and the optional minLevel / maxLevel /
loggerNamePattern parameters described below:
| Method | Serilog sink | Package |
|---|---|---|
AddConsole |
themed console | Serilog.Sinks.Console |
AddFile |
file (takes a path) |
Serilog.Sinks.File |
AddDebug |
debug output | Serilog.Sinks.Debug |
For any other Serilog sink, use the generic AddSink methods directly — the analog of
Serilog's own WriteTo:
using Serilog.Core; // ILogEventSink
using Serilog.Configuration; // LoggerSinkConfiguration
// Configure any sink through a LoggerSinkConfiguration delegate:
builder.AddSink(writeTo => writeTo.File("Logs/buffered.log", buffered: true),
minLevel, maxLevel, loggerNamePattern);
// Or register a sink instance you already have:
builder.AddSink(myLogEventSink, minLevel, maxLevel, loggerNamePattern);
Building from configuration
To build from an IConfiguration instead of adding sinks in code, use
BuildLoggerFromConfiguration. It configures the logger entirely from the Serilog section via
Serilog.Settings.Configuration
(sinks added in code are ignored on this path):
using var handle = new LoggerProviderBuilder()
.BuildLoggerFromConfiguration("myLogger", configuration);
handle.Logger.LogInformation("Configured from IConfiguration");
Log level semantics
minLevel (default Trace) and maxLevel (default Critical) bound the
Microsoft.Extensions.Logging.LogLevel range a sink receives — they map to a Serilog
LogEventLevel range enforced by the sink's inclusion filter. So
minLevel: LogLevel.Warning, maxLevel: LogLevel.Error sends a sink only Warning and Error
entries. The mapping is:
LogLevel |
LogEventLevel |
|---|---|
Trace |
Verbose |
Debug |
Debug |
Information |
Information |
Warning |
Warning |
Error |
Error |
Critical |
Fatal |
None |
(disabled) |
Serilog has no "Off" level, so LogLevel.None (or an out-of-range value) used as a bound
disables the sink — its filter rejects every event.
Logger name scoping
By default a sink matches every logger name ("*"). Pass loggerNamePattern to scope a sink to
specific logger names. The pattern uses NLog-style wildcards (* = any run of characters,
? = one character) and is matched case-insensitively against the event's SourceContext (the
logger category name):
using var handle = new LoggerProviderBuilder()
// Only loggers whose name starts with "MyApp.Payments" write to this sink
.AddFile("Logs/payments.log", loggerNamePattern: "MyApp.Payments.*")
.BuildLogger("MyApp.Payments.Processor");
Dispose
LoggerHandle owns the underlying Serilog logger. Buffered sinks (file/async) may hold entries in
memory, so you must dispose the handle to avoid losing logs:
Dispose()— flushes and closes the Serilog sinks, then tears the logger factory down. Idempotent (safe to call more than once). Prefer ausingstatement, or dispose it explicitly at application shutdown.
Serilog has no flush-without-close operation, so — unlike a buffering target you might checkpoint
mid-run — the handle exposes Dispose only; there is no separate Flush. That is why it implements
ILoggerHandle but not IFlushableLoggerHandle (which the NLog adapter's handle does).
using var handle = new LoggerProviderBuilder()
.AddFile("Logs/app.log")
.BuildLogger("myLogger");
handle.Logger.LogInformation("buffered entry");
// handle disposed here → flush + close sinks
Single-use builder
A builder is single-use: add every sink first, then call one Build* method exactly once.
After a logger is built the builder is sealed — any further AddSink call, or a second Build*
call, throws InvalidOperationException. Calling BuildLogger with no sinks added also throws
InvalidOperationException. To build another logger, create a new LoggerProviderBuilder.
All public methods throw ArgumentNullException for null arguments (name, configuration,
sink, configureSink, path, loggerNamePattern).
Thread safety
The built ILogger and the Serilog logger behind the handle are thread-safe for logging — share
the handle's loggers freely across threads. The LoggerProviderBuilder itself is not designed
for concurrent use: it is a single-use, add-then-build object, so configure and build it on one
thread before sharing the resulting loggers.
Using with Microsoft.Extensions.DependencyInjection
AddSerilogLoggerBuilder(name, configure) builds the logger and wires it into the container in one
call:
using Enigma.Logging.Serilog;
services.AddSerilogLoggerBuilder("MyApp", builder => builder
.AddConsole()
.AddFile("Logs/app.log"));
What you get:
ILogger<T>injection routes through Serilog — the built provider is registered in theMicrosoft.Extensions.Loggingpipeline, so ordinary constructor injection just works:public sealed class OrderService(ILogger<OrderService> logger) { /* … */ }The handle is resolvable as
ILoggerHandle, for direct access toLogger,Factory, andCreateLogger<T>(). (It is not registered asIFlushableLoggerHandle— see Dispose.)The container owns the handle's lifetime — disposing the service provider (application shutdown) disposes the handle, which flushes and closes the Serilog sinks. No manual
usingneeded.
Prefer the standalone builder when the logger must outlive, or exist without, a DI container.
Supported frameworks
netstandard2.0 · net8.0 · net10.0
The effective Microsoft.Extensions.Logging floor is 9.0.0 on every target framework, resolved
transitively from Serilog.Extensions.Logging — the integration package that targets Serilog 4.x.
(The NLog adapter keeps a lower MEL baseline; this one is deliberately Serilog-4-aligned.)
Related packages
Enigma.Logging.Abstractions— the shared handle contract this package implements (readme).Enigma.Logging.NLog— the same builder → handle shape on NLog, with flush-without-close (readme).- Enigma.Logging on GitHub — the umbrella readme.
License
Licensed under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Enigma.Logging.Abstractions (>= 1.0.0)
- Serilog (>= 4.4.0)
- Serilog.Extensions.Logging (>= 9.0.2)
- Serilog.Settings.Configuration (>= 9.0.0)
- Serilog.Sinks.Console (>= 6.1.1)
- Serilog.Sinks.Debug (>= 3.0.0)
- Serilog.Sinks.File (>= 7.0.0)
-
net10.0
- Enigma.Logging.Abstractions (>= 1.0.0)
- Serilog (>= 4.4.0)
- Serilog.Extensions.Logging (>= 9.0.2)
- Serilog.Settings.Configuration (>= 9.0.0)
- Serilog.Sinks.Console (>= 6.1.1)
- Serilog.Sinks.Debug (>= 3.0.0)
- Serilog.Sinks.File (>= 7.0.0)
-
net8.0
- Enigma.Logging.Abstractions (>= 1.0.0)
- Serilog (>= 4.4.0)
- Serilog.Extensions.Logging (>= 9.0.2)
- Serilog.Settings.Configuration (>= 9.0.0)
- Serilog.Sinks.Console (>= 6.1.1)
- Serilog.Sinks.Debug (>= 3.0.0)
- Serilog.Sinks.File (>= 7.0.0)
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 |
|---|---|---|
| 1.0.0 | 76 | 7/31/2026 |
Enigma.Logging.Serilog 1.0.0 — initial release. Build Serilog-backed Microsoft.Extensions.Logging loggers with a fluent sink builder and a disposable LoggerHandle (console/file/debug sinks, configuration-driven build, level-range + logger-name-pattern gating, IServiceCollection DI helper). Supersedes the retired SerilogLoggerBuilder package (new identity, no upgrade path). See RELEASENOTES.md for the full details.