Skip to content

Replace custom ILogger with Serilog + Microsoft.Extensions.Logging #64

Description

@mcpolo99

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 / --quiet CLI flags
  • No timestamps on individual log lines
  • No file output — users must redirect stdout
  • No structured logging
  • 5 bare catch blocks 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

  1. net461 compatibility: Microsoft.Extensions.Logging.Abstractions supports 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.

  2. Name collision: Both our custom Confuser.Core.ILogger and M.E.L define ILogger. During migration (Phases 1-3), both will coexist. Callers will need using aliases or fully-qualified names. This is temporary but annoying.

  3. 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 ProtectTabVM logger implementation — net reduction.

  4. Progress reporting: Serilog doesn't have a native "progress" concept. We'd keep the Progress(int, int) / EndProgress() methods as a separate IProgressReporter interface, or use a Serilog enricher. This needs design thought.

  5. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestneeds-evaluationRequires further analysis before implementationpriority: highHigh priority

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions