<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [WPF]在WPF中使用ObservableCollections顯示Microsoft.Extensions.Logging的日志信息

      背景

      先前一段時間用RichTextBox實現了Microsoft.Extension.Logger的日志顯示。雖然是用RichTextBox總感覺哪里不對勁,想要添加過濾顯得非常復雜。最近了解并學習了ObservableCollection這個庫(有點火星救援了啊),遂想到了一個更好的實現方式。

      引入ObservableCollections庫

      1. 在包管理中引入ObservableCollections庫

      可觀察的日志

      1. 首先定義一個Log實體LogMessage。為了后面更好實現Filiter功能,添加LogLevel,EventId等屬性。
      2. 在應用程序運行期間,需要有個存儲LogMessage的地方,這里定義接口ILogMessageHolder, 使用ObservableFixedSizeRingBuffer做容器(環形數組,可以使用指定大小的size),整個Observable Logs就是這個ObservableCollections庫里的容器。
      
      public struct LogMessage
      {
          public LogLevel LogLevel { get; set;}
          public EventId EventId { get; set;}
          public string Category { get; set;}
          public DateTime Time { get; set;}
          public string Message { get; set;}
      }
      
      public interface ILoggerMessageHolder
      {
          public ObservableFixedSizeRingBuffer<LogMessage> LogMessages {get;}
      }
      

      實現Logger等其他東西

      1. 實現LogMessageProcessor, 這里依然參照ConsoleLoggerProcessor的實現。(有個疑問,直接往LogMessage容器里添加新項,性能能開銷應該不大,這里還需要使用工作線程來執行Enqueue操作嗎?)
      internal class LogMessageProcessor
      {
          //... 省略字段和其余方法實現
      
          public LogMessageProcessor(ILogMessageHolder logMessageHolder, LoggerQueueFullMode fullMode, int maxQueueLength)
          {
              _logMessageHolder = logMessageHolder;
              _messageQueue = new();
              FullMode = fullMode;
              MaxQueueLength = maxQueueLength;
              _outputThread = new Thread(ProcessMessageQueue)
              {
                  IsBackground = true,
                  Name = "LogMessage queue processing thread"
              };
              _outputThread.Start();
          }
      
          //將 WriteMessage 中寫入Console的部分修改為往LogMessage容器里添加LogMessage
          internal void WriteMessage(LogMessage message)
          {
              try
              {
                  _logMessageHolder.LogMessages.AddLast(message);
              }
              catch
              {
                  CompleteAdding();
              }
          }
      }
      
      1. 實現Logger。其實這里的LogFormatter屬性可要可不要,因為這里的Formatter只對TState做格式化,可以直接做成一個內部的格式化器。當然,這里使用LogFormatter方便后期直接在配置中直接替換實現
      internal class Logger : ILogger
      {
          private readonly string _category;
          private readonly LogMessageProcessor _processor;
          private StringWriter? t_stringWriter;
          internal IExternalScopeProvider ScopeProvider { get; set; }
          public Logger(string category, LogMessageProcessor processor, LogFormatter formatter,IExternalScopeProvider scopeProvider)
          {
              _category = category;
              _processor = processor;
              Formatter = formatter;
              ScopeProvider = scopeProvider;
          }
      
          public LogFormatter Formatter { get; set; }
      
          public IDisposable? BeginScope<TState>(TState state) where TState : notnull
          {
              return ScopeProvider.Push(state) ?? NullScope.Instance;
          }
      
          public bool IsEnabled(LogLevel logLevel)
          {
              return true;
          }
      
          public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
          {
              t_stringWriter ??= new StringWriter();
              var entry = new LogEntry<TState>(logLevel, _category, eventId, state, exception, formatter);
      
              Formatter.Write(entry, t_stringWriter);
      
              var sb = t_stringWriter.GetStringBuilder();
              var computedString = sb.ToString();
              sb.Clear();
              _processor.WriteMessage(new LogMessage()
              {
                  Time = DateTime.Now,
                  Id = eventId,
                  Level = logLevel,
                  Category = _category,
                  Message = computedString,
              });
          }
      }
      
      1. 實現LoggerProvider和LoggingBuilderExtension
      internal class LoggerProvider : ILoggerProvider
      {
          private readonly LogFormatter _formatter;
          private readonly ConcurrentDictionary<string, Logger> _loggers = [];
          private readonly LogMessageProcessor _processor;
      
          public LoggerProvider(ILogMessageHolder holder, LogFormatter formatter)
          {
              _formatter = formatter;
              _processor = new LogMessageProcessor(holder, LoggerQueueFullMode.Wait, 2500);
          }
      
          public ILogger CreateLogger(string categoryName)
          {
              return _loggers.GetOrAdd(categoryName, new Logger(categoryName, _processor, _formatter));
          }
      
          public void Dispose()
          {
              _processor.Dispose();
          }
      }
      
      public static class LoggingBuilderExtension
      {
          public static ILoggingBuilder AddObservableLogs(this ILoggingBuilder builder)
          {
              builder.Services.AddSingleton<ILoggerProvider, LoggerProvider>();
              builder.Services.AddSingleton<IMfgLoggerProvider, LoggerProvider>();
              builder.Services.AddTransient<LogFormatter, SimpleLogFormatter>();
              builder.Services.AddSingleton<ILogMessageHolder, LogMessageHolder>();
              return builder;
          }
      }
      
      • 至此,Logger的核心已經完成,接下來是在View中顯示Log

      簡單實現LogViewer

      1. 創建LogWindow,使用ItemsControl顯示LogMessage。
        實際上,LogMessage的Formatter,是下文的LogMessageConverter。
      public class LogMessageConverter : IValueConverter
      {
      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
      {
          if (value is not LogMessage message)
          {
              return "";
          }
          return $"{message.Time:yyyy-MM-dd HH:mm:ss,fff} {GetLogLevelString(message.LogLevel)}: {message.Category} [{message.EventId}]\r\n{message.Message}";
      }
      
      public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
      {
          throw new NotImplementedException();
      }
      
      private static string GetLogLevelString(LogLevel logLevel) => logLevel switch
      {
          LogLevel.Trace => "trce",
          LogLevel.Debug => "dbug",
          LogLevel.Information => "info",
          LogLevel.Warning => "warn",
          LogLevel.Error => "fail",
          LogLevel.Critical => "crit",
          _ => throw new ArgumentOutOfRangeException(nameof(logLevel))
      };
      }
      
      <!--省略Window的命名空間和其余屬性-->
      <ItemsControl ItemsSource="{Binding LogMessages}">
          <ItemsControl.ItemTemplate>
              <DataTemplate>
                  <!--如果想要顯示日志等級的顏色,需要其他TextBlock和添加trigger-->
                  <TextBlock Text="{Binding ., Converter={StaticResource LogMessageConverter}}"></TextBlock>
              </DataTemplate>
          </ItemsControl.ItemTemplate>
      </ItemsControl>
      
      1. 創建LogWindow的DataContext
        這里就涉及到ObservableCollections庫的知識了,最后綁定到View上的是LogMessages屬性。如果想對LogMessages進行過濾,比如選取LogLevel.Information等,使用_viewList的AttachFiliter就好啦。
      public class LogWindowViewModel
      {
          private readonly ISynchronizedView<LogMessage, LogMessage> _viewList;
          private readonly ILogMessageHolder _logMessageHolder;
            
          public LogWindowViewModel(ILogMessageHolder logMessageHolder)
          {
              _logMessageHolder = logMessageHolder;
              _viewList = logMessageHolder.LogMessages.CreateView(x => x);
              LogMessages = _viewList.ToNotifyCollectionChanged();
          }
      
          public INotifyCollectionChangedSynchronizedViewList<LogMessage> LogMessages { get; }
      }
      

      結尾

      使用ObservableCollections可以非常簡單的將LogMessage顯示到某個UI上,并且LogMessages的生命周期是跟隨應用程序,隨時可以打開查看應用程序的日志。由于ObservableCollections是純C#實現,理論上是可以在Avalonia中使用的。

      posted @ 2025-07-21 13:49  Echo_HR910  閱讀(506)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久久久综合中文字幕| 亚洲首页一区任你躁xxxxx| 亚洲欧洲日产国产av无码| 亚洲一区二区三区在线观看精品中文| 人妻无码中文字幕| 亚洲av不卡电影在线网址最新| 亚洲国产成人va在线观看天堂 | 国产视频最新| 久久国语对白| 婷婷五月综合丁香在线| 亚洲av成人一区二区| 欧美和黑人xxxx猛交视频| 中文字幕乱码视频32| 亚洲老熟女一区二区三区| 亚洲偷自拍另类一区二区| 国产老头多毛Gay老年男| 国产精品美女一区二三区| 亚洲av中文一区二区| 最新国产精品拍自在线观看| 日韩av日韩av在线| 国产亚洲欧洲av综合一区二区三区 | 无码毛片一区二区本码视频| 欧美激情a∨在线视频播放| 亚洲国产成人综合自在线| 欧美和黑人xxxx猛交视频| 国产亚洲精品久久777777| 九九热在线观看视频精品| 中文字幕精品人妻丝袜| 三男一女吃奶添下面视频| 亚洲天堂精品一区二区| 亚洲AV成人片不卡无码| 诏安县| 色综合久久久久综合体桃花网| 成人无码区免费视频| 高密市| 91老肥熟女九色老女人| 鲁鲁网亚洲站内射污| 亚洲国产午夜福利精品| 免费看欧美日韩一区二区三区| 国产初高中生粉嫩无套第一次 | 亚洲热线99精品视频|