Repository navigation
Replace custom ILogger with Serilog + Microsoft.Extensions.Logging #64
Description
Goal
Replace the hand-rolled Confuser.Core.ILogger interface and its 5 custom implementations with the industry-standard Microsoft.Extensions.Logging abstraction backed by Serilog as the logging provider. The objective is to eliminate custom logging maintenance, gain battle-tested features for free, and align with .NET ecosystem conventions.
Why — The Problem with Custom Logging
We currently maintain a custom ILogger interface (13 methods) with 5 separate implementations:
| Implementation | Location | Maintenance concern |
|---|---|---|
ConsoleLogger |
CLI/Program.cs | No progress display, no level filtering, no file output |
ProtectTabVM |
GUI ViewModel | Tightly coupled to WPF FlowDocument rendering |
MSBuildLogger |
MSBuild.Tasks | Probable bug in Finish() — HasError = false when !successful |
PackerLogger |
Core/Packer.cs | Decorator wrapping another ILogger |
NullLogger |
Core/NullLogger.cs | Contains dead code (BeginModule/EndModule) |
Every improvement we want (level filtering, timestamps, file output, verbosity flags) requires manual implementation across all 5. This is ongoing maintenance burden for solved problems.
Current limitations (all would need DIY implementation):
- No log level filtering — cannot suppress Debug in production
- No
--verbose/--quietCLI flags - No timestamps on individual log lines
- No file output — users must redirect stdout
- No structured logging
- 5 bare
catchblocks swallowing exceptions silently - CLI has no progress display (Progress/EndProgress are no-ops)
- No log context/scope — callers manually embed module/phase names
What This Would Improve
| Improvement | Current (DIY) | After (built-in) |
|---|---|---|
| Log level filtering | Not possible | LogLevel.Debug, LogLevel.Warning, etc. — one-line config |
CLI verbosity (-v/-vv/-vvv) |
Not implemented | Maps directly to LogEventLevel (Verbose, Debug, Information, Warning) |
| File output | Not implemented | Serilog.Sinks.File — one line of config |
| Timestamps | Not implemented | Built into every sink's formatter |
| Structured logging | Not possible | Native to Serilog — Log.Information("Loading {Module}", name) |
| Console formatting | Basic color only | Serilog.Sinks.Console with templates, themes |
| MSBuild integration | Buggy custom impl | Clean adapter to TaskLoggingHelper |
| GUI integration | Tightly coupled | Custom WPF sink (~30 lines), cleanly decoupled |
Net result: delete 5 logger implementations, replace with ~30 lines of Serilog configuration.
Proposed Approach
Library Choice: M.E.L abstraction + Serilog provider
Microsoft.Extensions.Logging.Abstractions — the interface (ILogger<T>)
Serilog.Extensions.Logging — bridges M.E.L to Serilog
Serilog.Sinks.Console — console output
Serilog.Sinks.File — file output (optional)
Why M.E.L + Serilog (not just Serilog alone):
- M.E.L is the .NET standard logging abstraction — built into .NET 10 (no extra package after retarget Retarget GUI and CLI to .NET 10 #53)
- Serilog provides the actual output engine with rich formatting and sinks
- Any future .NET library we consume or expose will expect M.E.L
- Separates the "what to log" (M.E.L interface) from "where to log" (Serilog sinks)
Why not NLog: Less modern API, XML-based config, less ecosystem momentum.
Why not Serilog alone: No standard abstraction — locks us into Serilog's API surface.
Why not M.E.L alone: Needs separate provider packages for actual output. Serilog is the best provider.
CLI Verbosity Design
--quiet / -q → Warning level (Warn + Error only)
(default) → Information level (Info + Warn + Error)
-v / --verbose → Debug level
-vv → Verbose/Trace level (resolver paths, method-level detail)
-vvv → Everything including internal diagnostics
Migration Path
Phase 1: Add packages, create thin adapter (old ILogger → Serilog)
Existing code keeps working, zero breaking changes.
Phase 2: New code uses M.E.L ILogger<T> directly.
Old ILogger calls still work through adapter.
Phase 3: Incrementally replace old ILogger calls across 27 files.
Each file is a small, reviewable PR.
Phase 4: Remove Confuser.Core.ILogger interface and all custom implementations.
Adapter deleted. Migration complete.
Possible Caveats
-
net461 compatibility:
Microsoft.Extensions.Logging.Abstractionssupports netstandard2.0, so it works on net461. However, it adds ~3 NuGet packages to what has been a deliberately lean dependency tree. After the .NET 10 retarget (Retarget GUI and CLI to .NET 10 #53), M.E.L ships with the framework and the extra packages go away. -
Name collision: Both our custom
Confuser.Core.ILoggerand M.E.L defineILogger. During migration (Phases 1-3), both will coexist. Callers will needusingaliases or fully-qualified names. This is temporary but annoying. -
GUI sink: No off-the-shelf Serilog sink writes to a WPF FlowDocument. We'll need a small custom sink (~30 lines) that marshals log events to the UI thread. This replaces the current 80+ line
ProtectTabVMlogger implementation — net reduction. -
Progress reporting: Serilog doesn't have a native "progress" concept. We'd keep the
Progress(int, int)/EndProgress()methods as a separateIProgressReporterinterface, or use a Serilog enricher. This needs design thought. -
Timing: This work overlaps significantly with Retarget GUI and CLI to .NET 10 #53 (Retarget to .NET 10). Doing both together reduces churn — M.E.L becomes a built-in dependency on net10.0. Doing logging first on net461 means carrying extra NuGet packages temporarily.
Recommendation
Implement as part of #53 (.NET 10 retarget) to minimize dependency churn. Phase 1 (adapter) can land earlier if needed for immediate debugging improvements.
Related Issues
- Retarget GUI and CLI to .NET 10 #53 — Retarget GUI and CLI to .NET 10 (natural pairing)
- Integrate Roslyn code analysis into build pipeline #46 — Roslyn code analysis (analyzers can flag direct Console.Write calls)
Activity
refactor: extract IProgressReporter from ILogger (#64)
github-actions commentedon Jun 11, 2026
Lint Results
feature: add M.E.L abstraction and MelLoggerAdapter (#64)
feature: replace CLI ConsoleLogger with Serilog (#64)
feature: replace GUI logger with Serilog FlowDocument sink (#64)
refactor: replace Confuser.Core.ILogger with Microsoft.Extensions.Log…
chore: fix import ordering to pass CI lint (#64)
fix: dispose GUI logger factory after async protection completes (#64)
test: fix flaky GUI protect test — deterministic tab navigation (#64)
refactor: replace custom ILogger with Serilog + Microsoft.Extensions.…
mcpolo99 commentedon Jul 2, 2026
Resolved by #85, merged into
developas squash commitdb23a67.The custom
Confuser.Core.ILogger(13 methods, 5 implementations) is fully replaced byMicrosoft.Extensions.Logging.ILoggerwith Serilog as the provider:--verbose/--quietlevel flagsFlowDocumentSinkfor the log panelOld
ILogger,NullLogger, andMelLoggerAdapterdeleted. Also fixed the invertedMSBuildLogger.Finishbug (was settingHasError = falseon failure).Verified at runtime: level filtering, structured templates, error path (exception + stack trace), and CLI exit codes all working. 29/29 tests pass.
Will formally close on GitHub once
develop→mainships in the next release.