在Windows Forms应用中实现Serilog日志实时展示到WinForms控件的方案咨询
实现方案
直接开发自定义的Serilog Sink是最优方案,不需要轮询读取日志文件,日志输出时会直接推送到UI控件,完全实现实时展示。
步骤1:实现自定义Sink类
Serilog的Sink可以直接接收所有日志事件,我们只需要在Sink中完成日志格式化、跨线程UI更新的逻辑即可:
using Serilog.Core; using Serilog.Events; using System.Windows.Forms; public class ListBoxSink : ILogEventSink { private readonly ListBox _targetListBox; private readonly IFormatProvider _formatProvider; // 控制控件最多保留的日志条数,避免内容过多卡顿 private const int MaxLogCount = 100; public ListBoxSink(ListBox targetListBox, IFormatProvider formatProvider = null) { _targetListBox = targetListBox ?? throw new ArgumentNullException(nameof(targetListBox)); _formatProvider = formatProvider; } public void Emit(LogEvent logEvent) { // 格式化日志展示内容,可根据需求调整格式 var logContent = logEvent.RenderMessage(_formatProvider); var displayText = $"[{logEvent.Timestamp:HH:mm:ss}] [{logEvent.Level}] {logContent}"; // 日志输出线程可能不是UI线程,需要用Invoke安全更新控件 if (_targetListBox.InvokeRequired) { _targetListBox.Invoke(new Action(() => AppendLog(displayText))); return; } AppendLog(displayText); } private void AppendLog(string displayText) { if (_targetListBox.Items.Count >= MaxLogCount) { _targetListBox.Items.RemoveAt(0); } _targetListBox.Items.Add(displayText); // 自动滚动到最新日志 _targetListBox.SelectedIndex = _targetListBox.Items.Count - 1; } }
步骤2:扩展Serilog配置方法
为了方便注册Sink,可以写个配置扩展方法:
using Serilog; using Serilog.Configuration; using System.Windows.Forms; public static class ListBoxSinkExtensions { public static LoggerConfiguration ListBox( this LoggerSinkConfiguration sinkConfig, ListBox targetListBox, IFormatProvider formatProvider = null, LogEventLevel minLevel = LogEventLevel.Verbose) { return sinkConfig.Sink(new ListBoxSink(targetListBox, formatProvider), minLevel); } }
步骤3:在WinForms中注册Sink
要等主窗体的ListBox控件初始化完成后再配置Serilog,推荐写在主窗体的Load事件中:
private void MainForm_Load(object sender, EventArgs e) { Log.Logger = new LoggerConfiguration() .MinimumLevel.Verbose() // 保留原有的文件写入Sink .WriteTo.File("logs/app-.log", rollingInterval: RollingInterval.Day) // 新增ListBox输出Sink .WriteTo.ListBox(yourListBoxName) .CreateLogger(); }
可选调整
- 只需要展示最近1-2条日志的话,把
MaxLogCount参数改成对应数值即可 - 需要过滤日志级别的话,注册Sink时传入
minLevel参数,比如传LogEventLevel.Information就只会展示Info及以上级别的日志 - 需要展示异常堆栈的话,在
Emit方法中判断logEvent.Exception不为空时,把异常信息拼接到展示文本中即可
内容的提问来源于stack exchange,提问作者Fritz45
相关产品推荐
相关产品推荐

