add log message broker sink

This commit is contained in:
ikpil 2023-04-23 14:03:35 +09:00
parent 6300a24a81
commit 188b9e619e
5 changed files with 74 additions and 40 deletions

View File

@ -0,0 +1,26 @@
using System;
using System.IO;
using Serilog.Core;
using Serilog.Events;
using Serilog.Formatting;
namespace DotRecast.Recast.Demo.Logging.Sinks;
public class LogMessageBrokerSink : ILogEventSink
{
public static event Action<int, string> OnEmitted;
private readonly ITextFormatter _formatter;
public LogMessageBrokerSink(ITextFormatter formatter)
{
_formatter = formatter;
}
public void Emit(LogEvent logEvent)
{
using var writer = new StringWriter();
_formatter.Format(logEvent, writer);
OnEmitted?.Invoke((int)logEvent.Level, writer.ToString());
}
}

View File

@ -0,0 +1,18 @@
using Serilog;
using Serilog.Configuration;
using Serilog.Events;
using Serilog.Formatting.Display;
namespace DotRecast.Recast.Demo.Logging.Sinks;
public static class SerilogSinkExtensions
{
public static LoggerConfiguration LogMessageBroker(
this LoggerSinkConfiguration sinkConfiguration,
LogEventLevel restrictedToMinimumLevel = LogEventLevel.Verbose,
string outputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
{
var formatter = new MessageTemplateTextFormatter(outputTemplate);
return sinkConfiguration.Sink(new LogMessageBrokerSink(formatter));
}
}

View File

@ -1,5 +1,6 @@
using System.IO; using System.IO;
using DotRecast.Core; using DotRecast.Core;
using DotRecast.Recast.Demo.Logging.Sinks;
using Serilog; using Serilog;
using Serilog.Enrichers; using Serilog.Enrichers;
@ -9,7 +10,6 @@ public static class Program
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
var path = Loader.ToRPath("dungeon.obj"); var path = Loader.ToRPath("dungeon.obj");
path = Path.GetDirectoryName(path); path = Path.GetDirectoryName(path);
if (!string.IsNullOrEmpty(path)) if (!string.IsNullOrEmpty(path))
@ -25,6 +25,7 @@ public static class Program
.Enrich.WithThreadId() .Enrich.WithThreadId()
.Enrich.WithThreadName() .Enrich.WithThreadName()
.Enrich.WithProperty(ThreadNameEnricher.ThreadNamePropertyName, "main") .Enrich.WithProperty(ThreadNameEnricher.ThreadNamePropertyName, "main")
.WriteTo.LogMessageBroker(outputTemplate: format)
.WriteTo.Console(outputTemplate: format) .WriteTo.Console(outputTemplate: format)
.WriteTo.File( .WriteTo.File(
"logs/log.log", "logs/log.log",

View File

@ -1,9 +1,12 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Numerics; using System.Numerics;
using System.Text; using System.Text;
using DotRecast.Recast.Demo.Logging.Sinks;
using DotRecast.Recast.Demo.Tools; using DotRecast.Recast.Demo.Tools;
using DotRecast.Recast.Demo.UI.ViewModels;
using ImGuiNET; using ImGuiNET;
namespace DotRecast.Recast.Demo.UI; namespace DotRecast.Recast.Demo.UI;
@ -13,29 +16,25 @@ public class RcLogView : IRcView
private RecastDemoCanvas _canvas; private RecastDemoCanvas _canvas;
private bool _mouseInside; private bool _mouseInside;
private List<string> _lines = new(); private readonly List<LogMessageItem> _lines;
private readonly ConcurrentQueue<string> _output = new(); private readonly ConcurrentQueue<LogMessageItem> _queues;
private readonly StringBuilder _outputStringBuilder = new();
private readonly ConcurrentQueue<string> _error = new();
private readonly StringBuilder _errorStringBuilder = new();
public RcLogView() public RcLogView()
{ {
Console.SetOut(new ConsoleTextWriterHook(OnOut)); _lines = new();
Console.SetError(new ConsoleTextWriterHook(OnError)); _queues = new();
LogMessageBrokerSink.OnEmitted += OnOut;
} }
private void OnOut(string log) private void OnOut(int level, string message)
{ {
_output.Enqueue(log); var lines = message
} .Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries)
.Select(x => new LogMessageItem { Level = level, Message = x });
private void OnError(string log)
{ _lines.AddRange(lines);
_error.Enqueue(log);
} }
public void Clear() public void Clear()
@ -43,23 +42,6 @@ public class RcLogView : IRcView
_lines.Clear(); _lines.Clear();
} }
private void MergeLines(ConcurrentQueue<string> queue, StringBuilder builder)
{
while (queue.TryDequeue(out var s))
{
if (s != "\r\n")
{
builder.Append(s);
}
else
{
_lines.Add(builder.ToString());
builder.Clear();
}
}
}
public void Bind(RecastDemoCanvas canvas) public void Bind(RecastDemoCanvas canvas)
{ {
_canvas = canvas; _canvas = canvas;
@ -67,16 +49,16 @@ public class RcLogView : IRcView
public void Update(double dt) public void Update(double dt)
{ {
MergeLines(_output, _outputStringBuilder); while (_queues.TryDequeue(out var item))
MergeLines(_error, _errorStringBuilder); _lines.Add(item);
// buffer // buffer
if (10240 < _lines.Count) if (10240 < _lines.Count)
{ {
_lines.RemoveRange(0, _lines.Count - 8196); _lines.RemoveRange(0, _lines.Count - 8196);
} }
} }
public bool IsMouseInside() => _mouseInside; public bool IsMouseInside() => _mouseInside;
public void Draw(double dt) public void Draw(double dt)
@ -97,7 +79,7 @@ public class RcLogView : IRcView
if (ImGui.BeginChild("scrolling", Vector2.Zero, false, ImGuiWindowFlags.HorizontalScrollbar)) if (ImGui.BeginChild("scrolling", Vector2.Zero, false, ImGuiWindowFlags.HorizontalScrollbar))
{ {
_mouseInside = ImGui.IsWindowHovered(); _mouseInside = ImGui.IsWindowHovered();
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
unsafe unsafe
@ -108,7 +90,7 @@ public class RcLogView : IRcView
{ {
for (int lineNo = clipper.DisplayStart; lineNo < clipper.DisplayEnd; lineNo++) for (int lineNo = clipper.DisplayStart; lineNo < clipper.DisplayEnd; lineNo++)
{ {
ImGui.TextUnformatted(_lines[lineNo]); ImGui.TextUnformatted(_lines[lineNo].Message);
} }
} }

View File

@ -0,0 +1,7 @@
namespace DotRecast.Recast.Demo.UI.ViewModels;
public class LogMessageItem
{
public required int Level { get; init; }
public required string Message { get; init; }
}