Severity: Warning
File: src/Servy.Core/IO/RotatingStreamWriter.cs
Lines: 40, 234, 429, 470-475, 482
Code snippet:
private bool _rotationDisabled;
...
private void CheckRotation()
{
if (_rotationDisabled || _writer == null) return;
...
}
private void Rotate()
{
if (_rotationDisabled || _timeProvider() < _rotationCooldownUntil) return;
...
catch (Exception ex)
{
Logger.Error($"Log rotation critical failure: {ex.Message}. Rotation will be disabled until service restart.", ex);
_rotationDisabled = true;
break;
}
...
if (success)
{
_rotationCooldownUntil = DateTime.MinValue;
_rotationDisabled = false; // <-- only reset path
EnforceMaxRotations();
}
}
Explanation:
_rotationDisabled is a circuit breaker that opens on any non-IOException during File.Move (transient permission glitch, AV scanner holding a handle with a non-IO error, network share blip on a UNC log path). Once set to true, every subsequent CheckRotation and Rotate immediately returns. The only path that resets it (_rotationDisabled = false) is inside if (success) after a successful File.Move — but Rotate returns early on line 429 before File.Move is ever attempted. So the breaker is one-way until process restart.
The error log promises "until service restart", but the consequence is unbounded log file growth — for a service designed to manage long-running child processes producing logs, this defeats the purpose of having rotation at all.
Suggested fix:
Either add a time-based half-open state (e.g. attempt rotation again after N minutes/hours of being disabled), or move the reset out of the success branch and put it under a separate "trip count below threshold + cooldown elapsed" condition. At minimum, log a periodic reminder so the operator notices a service whose rotation has been silently dead for days.
🤖 Generated with Claude Code
Severity: Warning
File:
src/Servy.Core/IO/RotatingStreamWriter.csLines: 40, 234, 429, 470-475, 482
Code snippet:
Explanation:
_rotationDisabledis a circuit breaker that opens on any non-IOException duringFile.Move(transient permission glitch, AV scanner holding a handle with a non-IO error, network share blip on a UNC log path). Once set totrue, every subsequentCheckRotationandRotateimmediately returns. The only path that resets it (_rotationDisabled = false) is insideif (success)after a successfulFile.Move— butRotatereturns early on line 429 beforeFile.Moveis ever attempted. So the breaker is one-way until process restart.The error log promises "until service restart", but the consequence is unbounded log file growth — for a service designed to manage long-running child processes producing logs, this defeats the purpose of having rotation at all.
Suggested fix:
Either add a time-based half-open state (e.g. attempt rotation again after N minutes/hours of being disabled), or move the reset out of the success branch and put it under a separate "trip count below threshold + cooldown elapsed" condition. At minimum, log a periodic reminder so the operator notices a service whose rotation has been silently dead for days.
🤖 Generated with Claude Code