Skip to content

perf: gate AvaloniaNLogSink at Warning, cache loggers#195

Open
fuzzzerd wants to merge 1 commit intomasterfrom
fuzzz/avalonia-log-perf
Open

perf: gate AvaloniaNLogSink at Warning, cache loggers#195
fuzzzerd wants to merge 1 commit intomasterfrom
fuzzz/avalonia-log-perf

Conversation

@fuzzzerd
Copy link
Copy Markdown
Owner

@fuzzzerd fuzzzerd commented Apr 25, 2026

Summary

Avalonia framework code emits high-volume Verbose/Debug/Info events during layout, input, and rendering. nlog.config already blackholes Avalonia* events at those levels via a final="true" rule, so they have nowhere to go — but AvaloniaNLogSink.IsEnabled returning true unconditionally meant Avalonia still formatted arguments and called Log() before NLog discarded the event.

A dotnet-trace capture during a script-editor typing session showed this sink consuming ~318ms of inclusive CPU over a 30-second window — more than any other app-attributed path, and a noticeable fraction of UI-thread budget per keystroke.

Changes

  • IsEnabled now returns false below Warning. Avalonia short-circuits before formatting arguments, matching the intent of the existing Avalonia* blackhole rule in nlog.config.
  • Per-source ILogger lookups go through a ConcurrentDictionary<Type, ILogger> instead of LogManager.GetLogger(string) on each call. Smaller win once number1 is in place but cheap enough to land together.

Warning/Error/Fatal events flow through unchanged and still reach the console + logfile targets.

Avalonia framework code emits high-volume Verbose/Debug/Info events
during layout, input, and rendering. nlog.config blackholes
Avalonia* events at those levels with a final="true" rule, so
they have nowhere to go — but IsEnabled returning true unconditionally
made Avalonia format arguments and call Log() before NLog discarded
them. dotnet-trace on a script-editor typing session showed the
sink consuming ~318ms of inclusive CPU over 30s, more than any
other app-attributed path.

Two changes:

1. IsEnabled now returns false below Warning. Avalonia short-circuits
   before formatting arguments, matching the intent of the existing
   nlog.config Avalonia* blackhole rule.
2. Per-source ILogger lookups go through a ConcurrentDictionary
   keyed by Type instead of LogManager.GetLogger(string) on each
   call. Smaller win after #1 since most calls don't reach Log
   anymore, but cheap enough to land together.

Surviving Warning/Error/Fatal events flow through unchanged.
@github-actions
Copy link
Copy Markdown

Test Results

✔️ Tests 1177 / 1177 - passed in 11s
✔️ Coverage 78.46% - passed with 70% threshold
📏 13413 / 15637 lines covered 🌿 4652 / 7387 branches covered
🔍 click here for more details

✏️ updated for commit 4711543

@fuzzzerd fuzzzerd enabled auto-merge (squash) April 25, 2026 19:15
@fuzzzerd fuzzzerd disabled auto-merge April 25, 2026 19:22
@fuzzzerd fuzzzerd enabled auto-merge (rebase) April 25, 2026 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant