fix(logging): #561 — SelfLog to file+stderr and a startup file-sink growth self-check
Production ran six weeks with a healthy process and a 0-byte log because Serilog isolates per-sink failures: a file sink whose every write fails is invisible from anywhere but SelfLog, which was not enabled. Two instruments: - LogPipelineDiagnostics.EnableSelfLog (before the first logger builds): SelfLog to logs/serilog-selflog.txt (rotated at 5 MB) + stderr — the only channel that carries the exception the sink swallows. - CheckFileSinkGrowth (after the startup banner): verifies each configured, unbuffered file sink's rolled-file family physically grew across a marker event; a silent sink is reported at boot via SelfLog/stderr and the console sink instead of discovered months later. Growth-across-marker, not existence — a previous run's bytes must not mask a silent sink (the false pass an existence check would have given on wonder-app-vd03). Never throws: both instruments swallow their own failures — a diagnostics channel that can fail startup is worse than the defect it watches for. The load-bearing test is the failure case (a sink that writes nothing IS reported); a check that can only pass is indistinguishable from no check.
This commit is contained in:
@@ -122,6 +122,13 @@ await using (var secretsProvider = new ServiceCollection()
|
||||
// untouched. UseWindowsService already roots the content root at the base dir, so this only affects sinks.
|
||||
Directory.SetCurrentDirectory(AppContext.BaseDirectory);
|
||||
|
||||
// #561 — Serilog SelfLog to logs/serilog-selflog.txt + stderr, enabled before the first logger
|
||||
// builds. Serilog isolates per-sink failures, so a file sink whose writes fail leaves a 0-byte
|
||||
// log and a healthy process with no signal anywhere; SelfLog is the only channel that sees the
|
||||
// swallowed exception. Placed after the CWD anchor above so the relative path lands in the
|
||||
// install dir.
|
||||
LogPipelineDiagnostics.EnableSelfLog();
|
||||
|
||||
// Serilog — shared ZB.MOM.WW.Telemetry bootstrap. Sinks (Console + rolling daily file)
|
||||
// now live in appsettings.json (ReadFrom.Configuration); AddZbSerilog layers in the
|
||||
// shared NodeHostname / TraceContext / Redaction enrichers and trace correlation.
|
||||
@@ -777,6 +784,17 @@ app.MapOtOpcUaMetrics();
|
||||
Log.Information("OtOpcUa.Host starting with roles=[{Roles}] (admin={HasAdmin}, driver={HasDriver})",
|
||||
string.Join(",", roles), hasAdmin, hasDriver);
|
||||
|
||||
// #561 — startup growth self-check: the banner above went through the live pipeline; verify each
|
||||
// configured file sink physically grew. A sink whose writes silently fail (the wonder-app-vd03
|
||||
// 0-byte-log incident) is reported at boot — through SelfLog + stderr, which don't depend on the
|
||||
// broken sink, and through the normal logger for the console sink's benefit.
|
||||
if (LogPipelineDiagnostics.CheckFileSinkGrowth(app.Configuration,
|
||||
() => Log.Information("Log-pipeline self-check marker")) is { } logSelfCheckWarning)
|
||||
{
|
||||
LogPipelineDiagnostics.ReportFailure(logSelfCheckWarning);
|
||||
Log.Warning("{LogSelfCheckWarning}", logSelfCheckWarning);
|
||||
}
|
||||
|
||||
await app.RunAsync();
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Host
|
||||
|
||||
Reference in New Issue
Block a user