Skip to content

Commit 8bbe83b

Browse files
authored
Add thread for message processing (#14)
1 parent c6302c5 commit 8bbe83b

File tree

1 file changed

+81
-14
lines changed

1 file changed

+81
-14
lines changed

src/Serilog.Sinks.RichTextBox.Wpf/Sinks/RichTextBox/RichTextBoxSink.cs

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,21 @@
1515
#endregion
1616

1717
using System;
18+
using System.Collections.Concurrent;
19+
using System.Collections.Generic;
1820
using System.ComponentModel;
21+
using System.Diagnostics;
1922
using System.IO;
2023
using System.Text;
24+
using System.Threading;
2125
using System.Windows.Threading;
2226
using Serilog.Core;
2327
using Serilog.Events;
2428
using Serilog.Formatting;
2529
using Serilog.Sinks.RichTextBox.Abstraction;
2630

31+
32+
2733
namespace Serilog.Sinks.RichTextBox
2834
{
2935
internal sealed class RichTextBoxSink : ILogEventSink, IDisposable
@@ -36,42 +42,103 @@ internal sealed class RichTextBoxSink : ILogEventSink, IDisposable
3642
private readonly RenderAction _renderAction;
3743
private const int _defaultWriteBufferCapacity = 256;
3844

45+
private const int _batchSize = 200;
46+
private Thread _consumerThread;
47+
private ConcurrentQueue<LogEvent> _messageQueue;
48+
3949
public RichTextBoxSink(IRichTextBox richTextBox, ITextFormatter formatter, DispatcherPriority dispatcherPriority, object syncRoot)
4050
{
4151
_richTextBox = richTextBox ?? throw new ArgumentNullException(nameof(richTextBox));
4252
_formatter = formatter ?? throw new ArgumentNullException(nameof(formatter));
4353

4454
if (!Enum.IsDefined(typeof(DispatcherPriority), dispatcherPriority))
4555
{
46-
throw new InvalidEnumArgumentException(nameof(dispatcherPriority), (int) dispatcherPriority,
56+
throw new InvalidEnumArgumentException(nameof(dispatcherPriority), (int)dispatcherPriority,
4757
typeof(DispatcherPriority));
4858
}
4959

5060
_dispatcherPriority = dispatcherPriority;
5161
_syncRoot = syncRoot ?? throw new ArgumentNullException(nameof(syncRoot));
5262

5363
_renderAction = Render;
54-
}
5564

56-
public void Emit(LogEvent logEvent)
57-
{
58-
var buffer = new StringWriter(new StringBuilder(_defaultWriteBufferCapacity));
59-
_formatter.Format(logEvent, buffer);
65+
_messageQueue = new ConcurrentQueue<LogEvent>();
6066

61-
var formattedLogEventText = buffer.ToString();
67+
_consumerThread = new Thread(new ThreadStart(ProcessMessages)) { IsBackground = true };
68+
_consumerThread.Start();
69+
}
6270

63-
var xamlParagraphText =
64-
$"<Paragraph xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xml:space=\"preserve\">{formattedLogEventText}</Paragraph>";
71+
private enum States
72+
{
73+
Init,
74+
Dequeue,
75+
Log,
76+
}
6577

66-
var richTextBox = _richTextBox;
78+
private void ProcessMessages()
79+
{
80+
StringBuilder sb = new();
81+
Stopwatch sw = Stopwatch.StartNew();
82+
States state = States.Init;
83+
int msgCounter = 0;
6784

68-
if (!richTextBox.CheckAccess())
85+
while (true)
6986
{
70-
richTextBox.BeginInvoke(_dispatcherPriority, _renderAction, xamlParagraphText);
71-
return;
87+
switch (state)
88+
{
89+
//prepare the string builder and data
90+
case States.Init:
91+
sb.Clear();
92+
sb.Append($"<Paragraph xmlns =\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xml:space=\"preserve\">");
93+
msgCounter = 0;
94+
state = States.Dequeue;
95+
break;
96+
97+
case States.Dequeue:
98+
if (sw.Elapsed.TotalMilliseconds >= 25 || msgCounter >= _batchSize)
99+
{
100+
if (msgCounter == 0)
101+
{
102+
//no messages, retick
103+
sw.Restart();
104+
}
105+
else
106+
{
107+
//valid log condition
108+
state = States.Log;
109+
break;
110+
}
111+
}
112+
113+
if (_messageQueue.TryDequeue(out LogEvent logEvent) == false)
114+
{
115+
Thread.Sleep(1);
116+
continue;
117+
}
118+
119+
StringWriter writer = new();
120+
_formatter.Format(logEvent, writer);
121+
122+
//got a message from the queue, retick
123+
sw.Restart();
124+
125+
msgCounter++;
126+
sb.Append(writer.ToString());
127+
break;
128+
129+
case States.Log:
130+
sb.Append("</Paragraph>");
131+
string xamlParagraphText = sb.ToString();
132+
_richTextBox.BeginInvoke(_dispatcherPriority, _renderAction, xamlParagraphText);
133+
state = States.Init;
134+
break;
135+
}
72136
}
137+
}
73138

74-
Render(xamlParagraphText);
139+
public void Emit(LogEvent logEvent)
140+
{
141+
_messageQueue.Enqueue(logEvent);
75142
}
76143

77144
private void Render(string xamlParagraphText)

0 commit comments

Comments
 (0)