Skip to content

Commit

Permalink
Add thread for message processing
Browse files Browse the repository at this point in the history
  • Loading branch information
Skaptor authored and augustoproiete committed Oct 18, 2021
1 parent 6bed7a8 commit cdcbf4f
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
- name: Build
run: ${{ matrix.job.build }} --verbosity=diagnostic --target=pack
- name: Publish artifacts
if: matrix.job.push && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/'))
if: matrix.job.push
uses: actions/[email protected]
with:
if-no-files-found: warn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,21 @@
#endregion

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Threading;
using Serilog.Core;
using Serilog.Events;
using Serilog.Formatting;
using Serilog.Sinks.RichTextBox.Abstraction;



namespace Serilog.Sinks.RichTextBox
{
internal sealed class RichTextBoxSink : ILogEventSink, IDisposable
Expand All @@ -36,42 +42,103 @@ internal sealed class RichTextBoxSink : ILogEventSink, IDisposable
private readonly RenderAction _renderAction;
private const int _defaultWriteBufferCapacity = 256;

private const int _batchSize = 200;
private Thread _consumerThread;
private ConcurrentQueue<LogEvent> _messageQueue;

public RichTextBoxSink(IRichTextBox richTextBox, ITextFormatter formatter, DispatcherPriority dispatcherPriority, object syncRoot)
{
_richTextBox = richTextBox ?? throw new ArgumentNullException(nameof(richTextBox));
_formatter = formatter ?? throw new ArgumentNullException(nameof(formatter));

if (!Enum.IsDefined(typeof(DispatcherPriority), dispatcherPriority))
{
throw new InvalidEnumArgumentException(nameof(dispatcherPriority), (int) dispatcherPriority,
throw new InvalidEnumArgumentException(nameof(dispatcherPriority), (int)dispatcherPriority,
typeof(DispatcherPriority));
}

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

_renderAction = Render;
}

public void Emit(LogEvent logEvent)
{
var buffer = new StringWriter(new StringBuilder(_defaultWriteBufferCapacity));
_formatter.Format(logEvent, buffer);
_messageQueue = new ConcurrentQueue<LogEvent>();

var formattedLogEventText = buffer.ToString();
_consumerThread = new Thread(new ThreadStart(ProcessMessages)) { IsBackground = true };
_consumerThread.Start();
}

var xamlParagraphText =
$"<Paragraph xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xml:space=\"preserve\">{formattedLogEventText}</Paragraph>";
private enum States
{
Init,
Dequeue,
Log,
}

var richTextBox = _richTextBox;
private void ProcessMessages()
{
StringBuilder sb = new();
Stopwatch sw = Stopwatch.StartNew();
States state = States.Init;
int msgCounter = 0;

if (!richTextBox.CheckAccess())
while (true)
{
richTextBox.BeginInvoke(_dispatcherPriority, _renderAction, xamlParagraphText);
return;
switch (state)
{
//prepare the string builder and data
case States.Init:
sb.Clear();
sb.Append($"<Paragraph xmlns =\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xml:space=\"preserve\">");
msgCounter = 0;
state = States.Dequeue;
break;

case States.Dequeue:
if (sw.Elapsed.TotalMilliseconds >= 25 || msgCounter >= _batchSize)
{
if (msgCounter == 0)
{
//no messages, retick
sw.Restart();
}
else
{
//valid log condition
state = States.Log;
break;
}
}

if (_messageQueue.TryDequeue(out LogEvent logEvent) == false)
{
Thread.Sleep(1);
continue;
}

StringWriter writer = new();
_formatter.Format(logEvent, writer);

//got a message from the queue, retick
sw.Restart();

msgCounter++;
sb.Append(writer.ToString());
break;

case States.Log:
sb.Append("</Paragraph>");
string xamlParagraphText = sb.ToString();
_richTextBox.BeginInvoke(_dispatcherPriority, _renderAction, xamlParagraphText);
state = States.Init;
break;
}
}
}

Render(xamlParagraphText);
public void Emit(LogEvent logEvent)
{
_messageQueue.Enqueue(logEvent);
}

private void Render(string xamlParagraphText)
Expand Down

0 comments on commit cdcbf4f

Please sign in to comment.