| layout | default |
|---|
CHDSharp is silent by default. It integrates with Microsoft.Extensions.Logging so you can route internal diagnostics to any compatible provider.
Set the static Chd.LoggerFactory before performing library operations:
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Extensions.Logging;
var serilogLogger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.CreateLogger();
Chd.LoggerFactory = new SerilogLoggerFactory(serilogLogger);
// All subsequent Chd/ChdFile operations log through Serilog
var result = Chd.CheckFile(File.OpenRead("game.chd"), "game.chd", deepCheck: true);Any ILoggerFactory-compatible provider works:
- Serilog (
Serilog.Extensions.Logging) - NLog (
NLog.Extensions.Logging) Microsoft.Extensions.Logging.Console- your own
ILoggerFactoryimplementation
| Area | Level | Examples |
|---|---|---|
| Verification | Information / Debug | progress percentages, array-pool statistics, compression-type statistics per CHD |
| Metadata | Debug | tag + length + ASCII payload of every metadata entry |
| Errors | Warning / Error | failed metadata reads, precache failures, decompression exceptions (with the inner exception and hunk number) |
| Per-codec | Debug | block summaries, repeated-block counts |
Because every log call is a pre-compiled LoggerMessage.Define delegate, the overhead is negligible when logging is disabled.
To disable logging again (e.g. in tests):
Chd.LoggerFactory = null;Chd.LoggerFactory = new SerilogLoggerFactory(
new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.File("chdsharp.log", rollingInterval: RollingInterval.Day)
.CreateLogger());The library stays silent unless you opt in, but the two front ends (CHDSharpCli, CHDSharpTester) always configure Serilog at startup and route all logging through it.
Both apps build the pipeline the same way:
MinimumLevel.Debug()— everything is captured; what the user sees vs. what is stored depends on the sink.Chd.LoggerFactory = new SerilogLoggerFactory(Log.Logger)— library diagnostics flow into the same pipeline.- Logger is flushed on exit (
Log.CloseAndFlush()in the CLIfinallyblock,App.OnExitin the Tester).
| App | Sinks |
|---|---|
CHDSharpCli (Program.Main) |
Console ({Message}{NewLine}{Exception}) + File (rolling day) + BugReportSink |
CHDSharpTester (App.OnStartup) |
Debug + File (rolling day) + BugReportSink |
Rolling-day files under %LocalAppData%:
- CLI:
%LocalAppData%\CHDSharp\logs\chdsharp-<date>.log - Tester:
%LocalAppData%\CHDSharpTester\logs\chdsharp-tester-<date>.log
File template: {Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}, InvariantCulture.
- No direct
Console/Debuglogging for diagnostics. The onlyConsolewrites left in the CLI arechdman-parity report output (e.g.info) and the double-click "Press any key to exit" pause; the onlyDebug.WriteLinecalls left in the Tester are fallbacks for failures thrown before the logger exists (OnStartup) or while it is being flushed (OnExit). The Tester's on-screen log (MainViewModel.AddLog) also forwards each entry toLog.Information, so the file log mirrors the UI. - Top-level and public entry points are wrapped in try/catch +
Log: CLIMain(Log.Fatal, exit code 3), TesterOnStartup/OnExit,RunAsync,ExportPdfAsync,RelayCommand.Execute, and the publicChdmanWrappermethods (GetInfo,Verify,ExtractRaw,Copy,CopyVerbosereturn safe fallbacks on failure). - Existing
catchblocks log with the exception attached where one is available (Log.Warning(ex, …)/Log.Error(ex, …)). Expected-failure probes log atDebugso they stay out of bug reports: codec-default detection, source-header reads, file-size stats,GetHunkCodecNameprobes, parent IDENT/GDDD reads, temp-file cleanup, and cancellation (OperationCanceledExceptionisInformation/Debug, never an error).
Both apps attach a BugReportSink (CHDSharpCli/BugReportSink.cs, CHDSharpTester/Services/BugReportSink.cs) that POSTs every log event at Warning or above to https://www.purelogiccode.com/bugreport/api/send-bug-report (X-API-KEY header, JSON body).
- Fire-and-forget (
Task.Run, 10 sHttpClienttimeout): delivery never blocks or throws into the logging pipeline. OperationCanceledException/TaskCanceledExceptionevents are skipped (user cancellation is not a bug).- Server throttling (
HTTP 429) and any transport failure are silently tolerated.
Each report embeds the same sections:
=== Environment Details ===— Date, Application Name, Application Version, OS Version, Architecture, Bitness, Windows Version, Processor Count, Base Directory, Temp Path (plus Runtime/Session/Elevated context in the CLI sink).=== Error Details ===— the rendered log message.=== Exception Details ===— Type, Message, Source, StackTrace (plus inner exceptions;(none)placeholders when the event carries no exception, e.g. a usage warning).- The JSON payload also carries
applicationName,version,environment, andstackTraceper the Bug Report API.
LoggerFactoryis read lazily per operation, so you can swap providers at runtime; for predictable behavior, set it once at startup.- The logging package (
Microsoft.Extensions.Logging.Abstractions) is the library's only non-Zstd dependency and is marked optional in the sense that the library functions perfectly with it never set.