Fix/reduce event loss on reconfigurationreduce silent log event loss during XmlConfigurator reconfiguration#287
Open
N0tre3l wants to merge 3 commits intoapache:masterfrom
Conversation
Add method to atomically replace all appenders with a new collection.
…nderWarning in ResetConfigurationittedNoAppenderWarning Reset the warning flag to allow diagnostics during reconfiguration.
…ize null window Previously, ParseChildrenOfLoggerElement called RemoveAllAppenders() before adding new ones one-by-one, creating a window (equal to the full XML parse duration, typically 10-50 ms) during which the logger had no appenders and log events were silently dropped. This change resolves the race by: 1. Collecting all incoming appenders into a local List<IAppender> first. 2. Calling Logger.ReplaceAppenders() to perform the swap in a single writer lock, reducing the zero-appender window to microseconds.
FreeAndNil
requested changes
Apr 8, 2026
Contributor
There was a problem hiding this comment.
@N0tre3l thanks for your contribution.
Could you please add some unit tests and fix the compiler errors?
| // Reset the warning flag so diagnostics can fire during the next | ||
| // reconfiguration cycle. Without this, the "no appender" warning is | ||
| // silenced permanently after the first configuration. | ||
| EmittedNoAppenderWarning = false; |
Contributor
There was a problem hiding this comment.
Please move to
| /// event loss during reconfiguration. | ||
| /// </para> | ||
| /// </remarks> | ||
| public virtual void ReplaceAppenders(IEnumerable<IAppender> appenders) |
Contributor
There was a problem hiding this comment.
please adjust the indentation
|
|
||
| // Phase 1: resolve all new appenders from XML *before* touching the | ||
| // live logger. This avoids the window where the logger has no appenders. | ||
| var newAppenders = new List<IAppender>(); |
Contributor
There was a problem hiding this comment.
Suggested change
| var newAppenders = new List<IAppender>(); | |
| List<IAppender> newAppenders = new(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
During reconfiguration (
XmlConfigurator.Configurein Merge mode),XmlHierarchyConfigurator.ParseChildrenOfLoggerElementcalledRemoveAllAppenders()first, then parsed the XML and re-added appendersone by one. Any log event fired during the XML parse window (10-50 ms in
typical applications) was silently dropped because
CallAppendersfound_appenderAttachedImpl == null.Measured impact in a reproducible test: 95.9 % of events lost during a
50 ms simulated reconfiguration window.
Changes
Logger.cs- newReplaceAppenders(IEnumerable<IAppender>)methodRemoves the old appender collection and adds all new appenders inside a
single writer lock, so the logger is never in a zero-appender state for
more than a few microseconds (the lock acquisition time).
XmlHierarchyConfigurator.cs- collect-then-swap inParseChildrenOfLoggerElementAll new appenders are resolved from XML into a
List<IAppender>beforethe live logger is touched. Then
Logger.ReplaceAppenders()is called onceto perform the atomic swap, rather than the previous remove-then-add-one-by-one
pattern.
XmlHierarchyConfigurator.cs- resetEmittedNoAppenderWarninginConfigureThe "no appender" warning is intentionally designed to fire once per
application lifetime. However, with the appender swap window now reduced to
microseconds, an unlucky event hitting that window would permanently suppress
the diagnostic for the rest of the application lifetime. Resetting the flag at
the start of each configuration pass restores the intended behavior: one
warning per reconfiguration cycle if events are lost.
The reset is placed in
Configure()rather thanHierarchy.ResetConfiguration()because
ResetConfiguration()is only called in Overwrite mode, which wouldleave Merge mode - the default and the affected mode - without the reset.
Testing
Manually verified that:
XmlConfigurator.Configurestill attaches the correct appenders afterreconfiguration in both Merge and Overwrite modes.