From 188b9e619ef00de37e5cd7a4fc10e3b8a7534c9c Mon Sep 17 00:00:00 2001 From: ikpil Date: Sun, 23 Apr 2023 14:03:35 +0900 Subject: [PATCH] add log message broker sink --- .../Logging/Sinks/LogMessageBrokerSink.cs | 26 ++++++++ .../Logging/Sinks/SerilogSinkExtensions.cs | 18 ++++++ src/DotRecast.Recast.Demo/Program.cs | 3 +- src/DotRecast.Recast.Demo/UI/RcLogView.cs | 60 +++++++------------ .../UI/ViewModels/LogMessageItem.cs | 7 +++ 5 files changed, 74 insertions(+), 40 deletions(-) create mode 100644 src/DotRecast.Recast.Demo/Logging/Sinks/LogMessageBrokerSink.cs create mode 100644 src/DotRecast.Recast.Demo/Logging/Sinks/SerilogSinkExtensions.cs create mode 100644 src/DotRecast.Recast.Demo/UI/ViewModels/LogMessageItem.cs diff --git a/src/DotRecast.Recast.Demo/Logging/Sinks/LogMessageBrokerSink.cs b/src/DotRecast.Recast.Demo/Logging/Sinks/LogMessageBrokerSink.cs new file mode 100644 index 0000000..63a917d --- /dev/null +++ b/src/DotRecast.Recast.Demo/Logging/Sinks/LogMessageBrokerSink.cs @@ -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 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()); + } +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Logging/Sinks/SerilogSinkExtensions.cs b/src/DotRecast.Recast.Demo/Logging/Sinks/SerilogSinkExtensions.cs new file mode 100644 index 0000000..b9da9e0 --- /dev/null +++ b/src/DotRecast.Recast.Demo/Logging/Sinks/SerilogSinkExtensions.cs @@ -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)); + } +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Demo/Program.cs b/src/DotRecast.Recast.Demo/Program.cs index 74c5f3b..e8a49b2 100644 --- a/src/DotRecast.Recast.Demo/Program.cs +++ b/src/DotRecast.Recast.Demo/Program.cs @@ -1,5 +1,6 @@ using System.IO; using DotRecast.Core; +using DotRecast.Recast.Demo.Logging.Sinks; using Serilog; using Serilog.Enrichers; @@ -9,7 +10,6 @@ public static class Program { public static void Main(string[] args) { - var path = Loader.ToRPath("dungeon.obj"); path = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(path)) @@ -25,6 +25,7 @@ public static class Program .Enrich.WithThreadId() .Enrich.WithThreadName() .Enrich.WithProperty(ThreadNameEnricher.ThreadNamePropertyName, "main") + .WriteTo.LogMessageBroker(outputTemplate: format) .WriteTo.Console(outputTemplate: format) .WriteTo.File( "logs/log.log", diff --git a/src/DotRecast.Recast.Demo/UI/RcLogView.cs b/src/DotRecast.Recast.Demo/UI/RcLogView.cs index 8bba290..bfebcd9 100644 --- a/src/DotRecast.Recast.Demo/UI/RcLogView.cs +++ b/src/DotRecast.Recast.Demo/UI/RcLogView.cs @@ -1,9 +1,12 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using System.Numerics; using System.Text; +using DotRecast.Recast.Demo.Logging.Sinks; using DotRecast.Recast.Demo.Tools; +using DotRecast.Recast.Demo.UI.ViewModels; using ImGuiNET; namespace DotRecast.Recast.Demo.UI; @@ -13,29 +16,25 @@ public class RcLogView : IRcView private RecastDemoCanvas _canvas; private bool _mouseInside; - private List _lines = new(); - private readonly ConcurrentQueue _output = new(); - private readonly StringBuilder _outputStringBuilder = new(); - - private readonly ConcurrentQueue _error = new(); - private readonly StringBuilder _errorStringBuilder = new(); - + private readonly List _lines; + private readonly ConcurrentQueue _queues; public RcLogView() { - Console.SetOut(new ConsoleTextWriterHook(OnOut)); - Console.SetError(new ConsoleTextWriterHook(OnError)); + _lines = new(); + _queues = new(); + + LogMessageBrokerSink.OnEmitted += OnOut; } - private void OnOut(string log) + private void OnOut(int level, string message) { - _output.Enqueue(log); - } - - private void OnError(string log) - { - _error.Enqueue(log); + var lines = message + .Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries) + .Select(x => new LogMessageItem { Level = level, Message = x }); + + _lines.AddRange(lines); } public void Clear() @@ -43,23 +42,6 @@ public class RcLogView : IRcView _lines.Clear(); } - private void MergeLines(ConcurrentQueue 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) { _canvas = canvas; @@ -67,16 +49,16 @@ public class RcLogView : IRcView public void Update(double dt) { - MergeLines(_output, _outputStringBuilder); - MergeLines(_error, _errorStringBuilder); - + while (_queues.TryDequeue(out var item)) + _lines.Add(item); + // buffer if (10240 < _lines.Count) { _lines.RemoveRange(0, _lines.Count - 8196); } } - + public bool IsMouseInside() => _mouseInside; public void Draw(double dt) @@ -97,7 +79,7 @@ public class RcLogView : IRcView if (ImGui.BeginChild("scrolling", Vector2.Zero, false, ImGuiWindowFlags.HorizontalScrollbar)) { _mouseInside = ImGui.IsWindowHovered(); - + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); unsafe @@ -108,7 +90,7 @@ public class RcLogView : IRcView { for (int lineNo = clipper.DisplayStart; lineNo < clipper.DisplayEnd; lineNo++) { - ImGui.TextUnformatted(_lines[lineNo]); + ImGui.TextUnformatted(_lines[lineNo].Message); } } diff --git a/src/DotRecast.Recast.Demo/UI/ViewModels/LogMessageItem.cs b/src/DotRecast.Recast.Demo/UI/ViewModels/LogMessageItem.cs new file mode 100644 index 0000000..7ff365b --- /dev/null +++ b/src/DotRecast.Recast.Demo/UI/ViewModels/LogMessageItem.cs @@ -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; } +} \ No newline at end of file