Skip to content

Commit a29e95e

Browse files
authored
RichTextBoxTarget - Batch BeginInvoke to avoid mesage pump starvation (#198)
1 parent abfdefe commit a29e95e

File tree

1 file changed

+76
-4
lines changed

1 file changed

+76
-4
lines changed

NLog.Windows.Forms/RichTextBoxTarget.cs

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,21 @@ public RichTextBoxTarget()
188188
InternalLogger.Warn(ex, "{0}: Failed to append RichTextBox", this);
189189
}
190190
});
191+
_sendTheMessagesToRichTextBox = new DelSendTheMessagesToRichTextBox((txtbox, msgs) =>
192+
{
193+
foreach (var msg in msgs)
194+
{
195+
if (msg.LogEvent != null)
196+
_sendTheMessageToRichTextBox.Invoke(txtbox, msg.Message, msg.Rule, msg.LogEvent);
197+
}
198+
});
191199
}
192200

193-
194201
private delegate void DelSendTheMessageToRichTextBox(RichTextBox textBox, string logMessage, RichTextBoxRowColoringRule rule, LogEventInfo logEvent);
202+
private delegate void DelSendTheMessagesToRichTextBox(RichTextBox textBox, MessageInfo[] messages);
195203

196204
private readonly DelSendTheMessageToRichTextBox _sendTheMessageToRichTextBox;
205+
private readonly DelSendTheMessagesToRichTextBox _sendTheMessagesToRichTextBox;
197206

198207
private delegate void FormCloseDelegate();
199208

@@ -740,6 +749,65 @@ protected override void CloseTarget()
740749
DetachFromControl();
741750
}
742751

752+
/// <inheritdoc />
753+
protected override void Write(IList<AsyncLogEventInfo> logEvents)
754+
{
755+
var textbox = TargetRichTextBox;
756+
if (logEvents.Count < 10 || textbox is null || textbox.IsDisposed || !textbox.InvokeRequired)
757+
{
758+
base.Write(logEvents);
759+
}
760+
else
761+
{
762+
// Single array-allocation instead of flooding the message-pump with BeginInvoke-calls
763+
var logMessages = new MessageInfo[logEvents.Count];
764+
for (int i = 0; i < logEvents.Count; i++)
765+
{
766+
var logEvent = logEvents[i];
767+
try
768+
{
769+
string logMessage = RenderLogEvent(Layout, logEvent.LogEvent);
770+
RichTextBoxRowColoringRule matchingRule = FindMatchingRule(logEvent.LogEvent);
771+
logMessages[i] = new MessageInfo(logMessage, matchingRule, logEvent.LogEvent);
772+
}
773+
catch (Exception ex)
774+
{
775+
InternalLogger.Warn(ex, "{0}: Failed to render log event", this);
776+
if (LogManager.ThrowExceptions)
777+
throw;
778+
logEvent.Continuation(ex);
779+
}
780+
}
781+
782+
bool messageSent = false;
783+
784+
try
785+
{
786+
// Single BeginInvoke with single method-parameters-allocation
787+
textbox.BeginInvoke(_sendTheMessagesToRichTextBox, textbox, logMessages);
788+
messageSent = true;
789+
for (int i = 0; i < logEvents.Count; i++)
790+
logEvents[i].Continuation(null);
791+
}
792+
catch (Exception ex)
793+
{
794+
InternalLogger.Warn(ex, "{0}: Failed to append RichTextBox", this);
795+
if (LogManager.ThrowExceptions)
796+
throw;
797+
for (int i = 0; i < logEvents.Count; i++)
798+
logEvents[i].Continuation(ex);
799+
}
800+
finally
801+
{
802+
foreach (var logMessage in logMessages)
803+
{
804+
if (logMessage.LogEvent != null)
805+
HandleMessageRetension(textbox, logMessage.LogEvent, logMessage.Message, logMessage.Rule, messageSent);
806+
}
807+
}
808+
}
809+
}
810+
743811
/// <summary>
744812
/// Log message to RichTextBox.
745813
/// </summary>
@@ -766,9 +834,13 @@ protected override void Write(LogEventInfo logEvent)
766834

767835
string logMessage = RenderLogEvent(Layout, logEvent);
768836
RichTextBoxRowColoringRule matchingRule = FindMatchingRule(logEvent);
769-
770837
bool messageSent = DoSendMessageToTextbox(logMessage, matchingRule, logEvent);
771838

839+
HandleMessageRetension(textbox, logEvent, logMessage, matchingRule, messageSent);
840+
}
841+
842+
private void HandleMessageRetension(RichTextBox? textbox, LogEventInfo logEvent, string logMessage, RichTextBoxRowColoringRule matchingRule, bool messageSent)
843+
{
772844
if (messageSent)
773845
{
774846
//remember last logged text box
@@ -892,8 +964,8 @@ private void SendTheMessageToRichTextBox(RichTextBox textBox, string logMessage,
892964
{
893965
var wordRulePattern = wordRule.Regex?.Render(logEvent) ?? string.Empty;
894966
var wordRuleText = wordRule.Text?.Render(logEvent) ?? string.Empty;
895-
var wordRuleWholeWords = wordRule.WholeWords.RenderValue(logEvent);
896-
var wordRuleIgnoreCase = wordRule.IgnoreCase.RenderValue(logEvent);
967+
var wordRuleWholeWords = wordRule.WholeWords?.RenderValue(logEvent) ?? false;
968+
var wordRuleIgnoreCase = wordRule.IgnoreCase?.RenderValue(logEvent) ?? false;
897969

898970
var matches = wordRule.ResolveRegEx(wordRulePattern, wordRuleText, wordRuleWholeWords, wordRuleIgnoreCase).Matches(textBox.Text, startIndex);
899971
foreach (Match? match in matches)

0 commit comments

Comments
 (0)