Severity: Info
File: src/Servy.Core/Logging/Logger.cs (lines 289-324)
Code:
private static void Log(LogLevel level, string? message)
{
if (_writer == null) return;
if (string.IsNullOrEmpty(message)) return;
try
{
lock (_lock)
{
// ...
_writer.WriteLine(logEntry);
}
}
catch
{
// Fail-silent
}
}
Explanation:
Logger.Initialize already has a thoughtful fallback (lines 113-128): if init fails, the exception is appended to a LoggerInitializationErrors.log sidecar file. The write path on line 320-323 has no such fallback — it just swallows.
In production these write-path failures are exactly the ones an operator most needs to see:
IOException because the disk filled up (the rotation engine in RotatingStreamWriter would also be unhappy, but the visible symptom is silent loss).
UnauthorizedAccessException if ACLs on %ProgramData%\Servy\logs were ever clobbered (the project itself manipulates ACLs in SecurityHelper.CreateSecureDirectory, so a bug there would be invisible from the logger).
ObjectDisposedException from a race between Shutdown() (line 329) and a concurrent Log — the double-checked-locking if (_writer == null) return mitigates but does not eliminate this for callers that already passed the early return.
In every case, the only signal Servy emits is "logs stopped appearing, no obvious reason". Even an event-log fallback or a write to a sidecar (mirroring the init-time LoggerInitializationErrors.log) would be enough.
Suggested fix:
Mirror the initialization fallback path:
catch (Exception ex)
{
try
{
var logDir = Path.Combine(AppConfig.ProgramDataPath, "logs");
var now = _useLocalTimeForRotation ? DateTime.Now : DateTime.UtcNow;
File.AppendAllText(Path.Combine(logDir, "LoggerWriteErrors.log"),
$"[{now:yyyy-MM-dd HH:mm:ss}] Failed to write log entry: {ex.Message}{Environment.NewLine}");
}
catch { /* truly fail-silent only as last resort */ }
}
For services that already have access to EventLog (the AppConfig.EventSource is registered at install time), a write to event log on Critical is also defensible.
Severity: Info
File:
src/Servy.Core/Logging/Logger.cs(lines 289-324)Code:
Explanation:
Logger.Initializealready has a thoughtful fallback (lines 113-128): if init fails, the exception is appended to aLoggerInitializationErrors.logsidecar file. The write path on line 320-323 has no such fallback — it just swallows.In production these write-path failures are exactly the ones an operator most needs to see:
IOExceptionbecause the disk filled up (the rotation engine inRotatingStreamWriterwould also be unhappy, but the visible symptom is silent loss).UnauthorizedAccessExceptionif ACLs on%ProgramData%\Servy\logswere ever clobbered (the project itself manipulates ACLs inSecurityHelper.CreateSecureDirectory, so a bug there would be invisible from the logger).ObjectDisposedExceptionfrom a race betweenShutdown()(line 329) and a concurrentLog— the double-checked-lockingif (_writer == null) returnmitigates but does not eliminate this for callers that already passed the early return.In every case, the only signal Servy emits is "logs stopped appearing, no obvious reason". Even an event-log fallback or a write to a sidecar (mirroring the init-time
LoggerInitializationErrors.log) would be enough.Suggested fix:
Mirror the initialization fallback path:
For services that already have access to
EventLog(theAppConfig.EventSourceis registered at install time), a write to event log onCriticalis also defensible.