动态

详情 返回 返回

Serilog基於Seq開源框架實現日誌分析 - 动态 详情

Serilog 是.NET 的日誌記錄庫,核心是結構化日誌;Seq 是開源的日誌服務器,專注於集中管理和分析日誌,接收、存儲、查詢和可視化日誌,是獨立於應用的 “日誌管理中心”。

日誌記錄庫 Serilog

  1. 以鍵值對形式記錄結構化日誌
  2. 可靈活配置日誌輸出目的地,支持控制枱、文件、數據庫等多種 “接收器”。
  3. 支持異步記錄,性能較好,能適應高併發的.NET 應用場景。

日誌服務器 Seq

  1. 專為結構化日誌設計,能完美解析 Serilog 生成的鍵值對日誌。
  2. 提供實時查詢功能,可快速篩選、分析日誌數據,不用手動翻找日誌文件。
  3. 支持日誌可視化,能通過圖表直觀展示日誌趨勢,適合排查問題和監控應用。

一、NuGet 包管理器中下載相關包

  1. Serilog
  2. Serilog.Sinks.Console(控制枱輸出)
  3. Serilog.Sinks.File(輸出到文件)
  4. Serilog.Sinks.Seq(輸出到Seq服務)
  5. Seq.Api(Seq.Api HTTP服務)

image

二、搭建 Seq 日誌服務

Docker命令行快速啓動
// 啓動項【將卷掛載到宿主機,配置數據持久化存儲,可避免容器或服務重啓後丟失數據】
docker run -d --name seq -e ACCEPT_EULA=Y   -v  /data/SeqData:/data -e SEQ_FIRSTRUN_ADMINUSERNAME=admin  -e SEQ_FIRSTRUN_ADMINPASSWORD="123456" -p 5341:5341 -p 8081:80 datalust/seq:2025.2
瀏覽器輸入地址查看是否部署成功(http://localhost:8081/)

image

三、創建Serilog接口以及實現接口

點擊查看代碼
 /// <summary>
 /// Serilog 日誌接口
 /// </summary>
 public interface ISerilogLogger
 {
     /// <summary>
     /// 配置Seq服務日誌記錄器
     /// </summary>
     /// <returns>Seq日誌記錄器實例</returns>
     ILogger ConfigureSeqLogger();

     /// <summary>
     /// 配置控制枱日誌記錄器
     /// </summary>
     /// <returns>控制枱日誌記錄器實例</returns>
     ILogger ConfigureConsoleLogger();

     /// <summary>
     /// 配置文件日誌記錄器
     /// </summary>
     /// <returns>文件日誌記錄器實例</returns>
     ILogger ConfigureFileLogger();

     /// <summary>
     /// 獲取默認日誌記錄器實例
     /// </summary>
     /// <returns>Seq日誌記錄器實例</returns>
     ILogger GetLogger();
 }
點擊查看代碼
  /// <summary>
 /// Serilog 記錄日誌
 /// </summary>
 public class SerilogLogger : ISerilogLogger
 {
     /// <summary>
     /// Seq服務 URL地址
     /// </summary>
     private readonly string _connectionString;

     /// <summary>
     /// 啓動程序
     /// </summary>
     private readonly string _applicationName;

     /// <summary> 
     /// 輸出模板 
     /// </summary>
     private readonly string _outputTemplate;

     /// <summary>
     /// 日誌實例
     /// </summary>
     private ILogger _logger;

     /// <summary>
     /// 構造函數
     /// </summary>
     /// <param name="connectionString">Seq服務 URL地址</param> 
     public SerilogLogger(string connectionString)
     {
         this._connectionString = connectionString ?? string.Empty;
         this._applicationName = Assembly.GetEntryAssembly()?.GetName().Name ?? string.Empty;
         this._outputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u4}] [LogType:{LogType}] [{ApplicationName}] [{SourceContext}] [{Module}]  {Message:lj}{NewLine}{Exception}";
         this._logger = ConfigureSeqLogger(); // 默認配置Seq日誌記錄器 
     }

     /// <summary>
     /// 配置Seq服務日誌記錄器
     /// </summary>
     /// <returns>Seq日誌記錄器實例</returns>
     public ILogger ConfigureSeqLogger()
     {
         try
         {
             // 若連接字符串為空,則使用控制枱日誌
             if (string.IsNullOrWhiteSpace(_connectionString))
             {
                 return ConfigureConsoleLogger();
             }

             // 配置 Seq 日誌記錄器
             return new LoggerConfiguration()
                 .WriteTo.Seq(_connectionString)  // 接入Seq日誌服務
                 .Enrich.WithProperty("ApplicationName", _applicationName)
                 .Enrich.With(new UuidEnricher()) // 添加 UUID 
                 .MinimumLevel.Verbose()          // 設置最低日誌級別為 Verbose
                 .CreateLogger();
         }
         catch
         {
             // 若配置失敗,創建控制枱日誌
             return ConfigureConsoleLogger();
         }
     }

     /// <summary>
     /// 配置控制枱日誌記錄器
     /// </summary>
     /// <returns>控制枱日誌記錄器實例</returns>
     public ILogger ConfigureConsoleLogger()
     {
         try
         {
             return new LoggerConfiguration()
                 .WriteTo.Console(outputTemplate: _outputTemplate)
                 .Enrich.WithProperty("ApplicationName", _applicationName)
                 .Enrich.With(new UuidEnricher())
                 .MinimumLevel.Verbose()
                 .CreateLogger();
         }
         catch
         {
             // 若配置失敗,創建基礎控制枱日誌
             return new LoggerConfiguration()
                 .WriteTo.Console()
                 .CreateLogger();
         }
     }

     /// <summary>
     /// 配置文件日誌記錄器
     /// </summary>
     /// <returns>文件日誌記錄器實例</returns>
     public ILogger ConfigureFileLogger()
     {
         try
         {
             return new LoggerConfiguration()
                 .WriteTo.File(
                      path: "logs\\defaultLogs.log",
                      rollingInterval: RollingInterval.Day,
                      retainedFileCountLimit: 30,     // 保留30天
                      fileSizeLimitBytes: 5_000_000, // 單文件最大5MB
                      outputTemplate: _outputTemplate
                  )
                 .Enrich.WithProperty("ApplicationName", _applicationName)
                 .Enrich.With(new UuidEnricher())
                 .MinimumLevel.Verbose()
                 .CreateLogger();
         }
         catch
         {
             // 若配置失敗,創建控制枱日誌
             return ConfigureConsoleLogger();
         }
     }

     /// <summary>
     /// 獲取默認日誌記錄器實例
     /// </summary>
     /// <returns>Seq日誌記錄器實例</returns>
     public ILogger GetLogger()
     {
         return _logger ?? ConfigureConsoleLogger();
     }
 }

四、創建Logger拓展類以及日誌類型枚舉類

點擊查看代碼
  /// <summary>
  /// Serilog Logger Extensions
  /// Provides extended logging methods with LogType and Module support
  /// </summary>
  public static class LoggerExtensions
  {
      #region Debug Methods

      /// <summary>
      /// Writes a debug log message with specified log type and module
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="message">Log message template</param>
      public static void Debug(this ILogger logger, LogType logType, string module, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Debug(message);
      }

      /// <summary>
      /// Writes a debug log message with specified log type, module and parameters
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Debug(this ILogger logger, LogType logType, string module, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Debug(message, propertyValues);
      }

      #endregion

      #region Information Methods

      /// <summary>
      /// Writes an information log message with specified log type and module
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="message">Log message template</param>
      public static void Information(this ILogger logger, LogType logType, string module, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Information(message);
      }

      /// <summary>
      /// Writes an information log message with specified log type, module and parameters
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Information(this ILogger logger, LogType logType, string module, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Information(message, propertyValues);
      }

      #endregion

      #region Warning Methods

      /// <summary>
      /// Writes a warning log message with specified log type and module
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="message">Log message template</param>
      public static void Warning(this ILogger logger, LogType logType, string module, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Warning(message);
      }

      /// <summary>
      /// Writes a warning log message with specified log type, module and parameters
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Warning(this ILogger logger, LogType logType, string module, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Warning(message, propertyValues);
      }

      #endregion

      #region Error Methods

      /// <summary>
      /// Writes an error log message with specified log type and module
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="message">Log message template</param>
      public static void Error(this ILogger logger, LogType logType, string module, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Error(message);
      }

      /// <summary>
      /// Writes an error log message with specified log type, module and parameters
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Error(this ILogger logger, LogType logType, string module, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Error(message, propertyValues);
      }

      /// <summary>
      /// Writes an error log message with specified log type, module and exception
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="exception">The exception to log</param>
      /// <param name="message">Log message template</param>
      public static void Error(this ILogger logger, LogType logType, string module, Exception exception, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Error(exception, message);
      }

      /// <summary>
      /// Writes an error log message with specified log type, module, exception and parameters
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="exception">The exception to log</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Error(this ILogger logger, LogType logType, string module, Exception exception, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Error(exception, message, propertyValues);
      }

      #endregion

      #region Fatal Methods

      /// <summary>
      /// Writes a fatal log message with specified log type and module
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="message">Log message template</param>
      public static void Fatal(this ILogger logger, LogType logType, string module, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Fatal(message);
      }

      /// <summary>
      /// Writes a fatal log message with specified log type, module and parameters
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Fatal(this ILogger logger, LogType logType, string module, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Fatal(message, propertyValues);
      }

      /// <summary>
      /// Writes a fatal log message with specified log type, module and exception
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="exception">The exception to log</param>
      /// <param name="message">Log message template</param>
      public static void Fatal(this ILogger logger, LogType logType, string module, Exception exception, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Fatal(exception, message);
      }

      /// <summary>
      /// Writes a fatal log message with specified log type, module, exception and parameters
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="exception">The exception to log</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Fatal(this ILogger logger, LogType logType, string module, Exception exception, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Fatal(exception, message, propertyValues);
      }

      #endregion

      #region Verbose Methods

      /// <summary>
      /// Writes a verbose log message with specified log type and module
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="message">Log message template</param>
      public static void Verbose(this ILogger logger, LogType logType, string module, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Verbose(message);
      }

      /// <summary>
      /// Writes a verbose log message with specified log type, module and parameters
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="module">Module name where the log originates</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Verbose(this ILogger logger, LogType logType, string module, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", module ?? string.Empty)
                .Verbose(message, propertyValues);
      }

      #endregion

      #region Backward Compatibility Methods

      /// <summary>
      /// Writes a debug log message with specified log type (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="message">Log message template</param>
      public static void Debug(this ILogger logger, LogType logType, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Debug(message);
      }

      /// <summary>
      /// Writes a debug log message with specified log type and parameters (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Debug(this ILogger logger, LogType logType, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Debug(message, propertyValues);
      }

      /// <summary>
      /// Writes an information log message with specified log type (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="message">Log message template</param>
      public static void Information(this ILogger logger, LogType logType, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Information(message);
      }

      /// <summary>
      /// Writes an information log message with specified log type and parameters (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Information(this ILogger logger, LogType logType, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Information(message, propertyValues);
      }

      /// <summary>
      /// Writes a warning log message with specified log type (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="message">Log message template</param>
      public static void Warning(this ILogger logger, LogType logType, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Warning(message);
      }

      /// <summary>
      /// Writes a warning log message with specified log type and parameters (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Warning(this ILogger logger, LogType logType, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Warning(message, propertyValues);
      }

      /// <summary>
      /// Writes an error log message with specified log type (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="message">Log message template</param>
      public static void Error(this ILogger logger, LogType logType, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Error(message);
      }

      /// <summary>
      /// Writes an error log message with specified log type and parameters (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Error(this ILogger logger, LogType logType, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Error(message, propertyValues);
      }

      /// <summary>
      /// Writes an error log message with specified log type and exception (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="exception">The exception to log</param>
      /// <param name="message">Log message template</param>
      public static void Error(this ILogger logger, LogType logType, Exception exception, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Error(exception, message);
      }

      /// <summary>
      /// Writes an error log message with specified log type, exception and parameters (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="exception">The exception to log</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Error(this ILogger logger, LogType logType, Exception exception, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Error(exception, message, propertyValues);
      }

      /// <summary>
      /// Writes a fatal log message with specified log type (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="message">Log message template</param>
      public static void Fatal(this ILogger logger, LogType logType, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Fatal(message);
      }

      /// <summary>
      /// Writes a fatal log message with specified log type and parameters (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Fatal(this ILogger logger, LogType logType, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Fatal(message, propertyValues);
      }

      /// <summary>
      /// Writes a fatal log message with specified log type and exception (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="exception">The exception to log</param>
      /// <param name="message">Log message template</param>
      public static void Fatal(this ILogger logger, LogType logType, Exception exception, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Fatal(exception, message);
      }

      /// <summary>
      /// Writes a fatal log message with specified log type, exception and parameters (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="exception">The exception to log</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Fatal(this ILogger logger, LogType logType, Exception exception, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Fatal(exception, message, propertyValues);
      }

      /// <summary>
      /// Writes a verbose log message with specified log type (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="message">Log message template</param>
      public static void Verbose(this ILogger logger, LogType logType, string message)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Verbose(message);
      }

      /// <summary>
      /// Writes a verbose log message with specified log type and parameters (module will be empty)
      /// </summary>
      /// <param name="logger">The logger instance</param>
      /// <param name="logType">Type of the log entry</param>
      /// <param name="message">Log message template</param>
      /// <param name="propertyValues">Parameters for the message template</param>
      public static void Verbose(this ILogger logger, LogType logType, string message, params object[] propertyValues)
      {
          logger.ForContext("LogType", logType)
                .ForContext("Module", string.Empty)
                .Verbose(message, propertyValues);
      }

      #endregion
  }
點擊查看代碼
/// <summary>
/// 日誌類型(可選或自定義)
/// </summary>
public enum LogType
{
    /// <summary>
    /// 系統日誌 - 系統啓動、關閉、配置變更等系統級操作
    /// </summary>
    System = 1,

    /// <summary>
    /// 操作日誌 - 用户業務操作、業務流程記錄
    /// </summary>
    Operation = 2,

    /// <summary>
    /// 硬件日誌 - 設備狀態、硬件交互、傳感器等
    /// </summary>
    Hardware = 3,

    /// <summary>
    /// 安全日誌 - 登錄認證、權限變更、安全事件等
    /// </summary>
    Security = 4,

}

五、寫入Prism容器,方便其它地方調用

點擊查看代碼
// protected override void RegisterTypes(IContainerRegistry containerRegistry) 方法
#region 註冊單例:通過 Prism 容器管理 日誌實例   
// 獲取 Seq服務URL 
string connectionString = ConnectionString["Sequrl"]?["ConnectionString"]?.ToString() ?? string.Empty;
// 註冊時先初始化日誌配置
var loggerInstance = new SerilogLogger(connectionString);
containerRegistry.RegisterSingleton<ISerilogLogger>(() => loggerInstance);
#endregion
點擊查看代碼
// 示例:記錄調試日誌
// 從容器獲取日誌實例:GetLogger 輸出方式,MainWindowViewModel調用上下文
ILogger logger = container.Resolve<ISerilogLogger>().GetLogger().ForContext<MainWindowViewModel>();
// 一、基本用法(等級 + 模塊 + 記錄文本)
logger.Debug(LogType.System, "Seq日誌", "初始化日誌模塊成功。");
// 二、參數用法(等級 + 模塊 + 消息模板 + 消息參數) 
logger.Information(LogType.Operation, "訂單模塊", "購買{Product}成功!總計金額:{Amount}美元", "海康工業相機", "$6888.99");

六、Seq日誌分析平台

image

image

七、Seq服務申請 API Keys授權

image

八、基於 Seq.Api 實現自定義日誌操作

點擊查看代碼
/// <summary>
/// Seq日誌查詢接口
/// </summary>
public interface ISeqQueryService
{
    /// <summary>
    /// 按時間範圍查詢日誌
    /// </summary>
    /// <param name="startTime">開始時間</param>
    /// <param name="endTime">結束時間</param>
    /// <param name="count">返回數據條數</param>
    /// <returns>日誌事件列表</returns>
    Task<List<EventEntity>> QueryByTimeRangeAsync(DateTime startTime, DateTime endTime, int count = 1000);

    /// <summary>
    /// 按天數查詢日誌(查詢最近N天的日誌)
    /// </summary>
    /// <param name="days">天數</param>
    /// <param name="count">返回數據條數</param>
    /// <returns>日誌事件列表</returns>
    Task<List<EventEntity>> QueryByDaysAsync(int days, int count = 1000);

    /// <summary>
    /// 按屬性值查詢日誌
    /// </summary>
    /// <param name="propertyName">屬性名</param>
    /// <param name="propertyValue">屬性值</param>
    /// <param name="count">返回數據條數</param>
    /// <returns>日誌事件列表</returns>
    Task<List<EventEntity>> QueryByPropertyAsync(string propertyName, string propertyValue, int count = 1000);

    /// <summary>
    /// 按日誌等級查詢
    /// </summary>
    /// <param name="level">日誌等級</param>
    /// <param name="count">返回數據條數</param>
    /// <returns>日誌事件列表</returns>
    Task<List<EventEntity>> QueryByLevelAsync(LogEventLevel level, int count = 1000);

    /// <summary>
    /// 組合查詢(時間範圍 + 日誌等級 + 屬性值)
    /// </summary>
    /// <param name="startTime">開始時間</param>
    /// <param name="endTime">結束時間</param>
    /// <param name="level">日誌等級</param>
    /// <param name="propertyName">屬性名</param>
    /// <param name="propertyValue">屬性值</param>
    /// <param name="count">返回數據條數</param>
    /// <returns>日誌事件列表</returns>
    Task<List<EventEntity>> QueryByTimeLevelAndPropertyAsync(DateTime startTime, DateTime endTime, LogEventLevel level, string propertyName, string propertyValue, int count = 1000);

    /// <summary>
    /// 組合查詢(時間範圍 + 屬性值)
    /// </summary>
    /// <param name="startTime">開始時間</param>
    /// <param name="endTime">結束時間</param>
    /// <param name="propertyName">屬性名</param>
    /// <param name="propertyValue">屬性值</param>
    /// <param name="count">返回數據條數</param>
    /// <returns>日誌事件列表</returns>
    Task<List<EventEntity>> QueryByTimeAndPropertyAsync(DateTime startTime, DateTime endTime, string propertyName, string propertyValue, int count = 1000);

    /// <summary>
    /// 組合查詢(日誌等級 + 屬性值)
    /// </summary>
    /// <param name="level">日誌等級</param>
    /// <param name="propertyName">屬性名</param>
    /// <param name="propertyValue">屬性值</param>
    /// <param name="count">返回數據條數</param>
    /// <returns>日誌事件列表</returns>
    Task<List<EventEntity>> QueryByLevelAndPropertyAsync(LogEventLevel level, string propertyName, string propertyValue, int count = 1000);

    /// <summary>
    /// 基礎查詢方法(僅使用filter條件)
    /// </summary>
    /// <param name="filter">過濾條件</param>
    /// <param name="count">返回數據條數</param>
    /// <returns>日誌事件列表</returns>
    Task<List<EventEntity>> QueryLogsAsync(string filter, int count);
}
點擊查看代碼
 /// <summary>
 /// Seq 日誌查詢
 /// 提供按時間、天數、屬性值、日誌等級、返回數據條數的查詢功能
 /// </summary>
 public class SeqQueryService : IDisposable, ISeqQueryService
 {
     private readonly SeqConnection _connection;
     private bool _disposed = false;

     /// <summary>
     /// 初始化Seq查詢服務
     /// </summary>
     /// <param name="serverUrl">Seq服務地址</param>
     /// <param name="apiKey">API密鑰</param>
     public SeqQueryService(string serverUrl, string apiKey)
     {
         _connection = new SeqConnection(serverUrl, apiKey);
     }

     /// <summary>
     /// 按時間範圍查詢日誌
     /// </summary>
     /// <param name="startTime">開始時間</param>
     /// <param name="endTime">結束時間</param>
     /// <param name="count">返回數據條數</param>
     /// <returns>日誌事件列表</returns>
     public async Task<List<EventEntity>> QueryByTimeRangeAsync(DateTime startTime, DateTime endTime, int count = 1000)
     {
         // 確保時間轉換為UTC(Seq存儲的是UTC時間)
         var fromTimeUtc = startTime.Kind == DateTimeKind.Utc ? startTime : startTime.ToUniversalTime();
         var toTimeUtc = endTime.Kind == DateTimeKind.Utc ? endTime : endTime.ToUniversalTime();

         // 使用Seq API專用的時間參數,避免filter拼接問題
         var resultSet = _connection.Events.EnumerateAsync(
             fromDateUtc: fromTimeUtc,  // 專用的開始時間參數
             toDateUtc: toTimeUtc,      // 專用的結束時間參數
             count: count,
             render: true);

         var logs = new List<EventEntity>();
         await foreach (var logEvent in resultSet)
         {
             logs.Add(logEvent);
         }
         return logs;
     }

     /// <summary>
     /// 按天數查詢日誌(查詢最近N天的日誌)
     /// </summary>
     /// <param name="days">天數</param>
     /// <param name="count">返回數據條數</param>
     /// <returns>日誌事件列表</returns>
     public async Task<List<EventEntity>> QueryByDaysAsync(int days, int count = 1000)
     {
         // 計算開始時間(當前時間往前推days天)
         var startTime = DateTime.Now.AddDays(-days);

         // 確保時間轉換為UTC
         var fromTimeUtc = startTime.Kind == DateTimeKind.Utc ? startTime : startTime.ToUniversalTime();

         // 使用Seq API專用的時間參數
         var resultSet = _connection.Events.EnumerateAsync(
             fromDateUtc: fromTimeUtc,  // 專用的開始時間參數
             count: count,
             render: true);

         var logs = new List<EventEntity>();
         await foreach (var logEvent in resultSet)
         {
             logs.Add(logEvent);
         }
         return logs;
     }

     /// <summary>
     /// 按屬性值查詢日誌
     /// </summary>
     /// <param name="propertyName">屬性名</param>
     /// <param name="propertyValue">屬性值</param>
     /// <param name="count">返回數據條數</param>
     /// <returns>日誌事件列表</returns>
     public async Task<List<EventEntity>> QueryByPropertyAsync(string propertyName, string propertyValue, int count = 1000)
     {
         var filter = $"{propertyName} = '{propertyValue}'";
         return await QueryLogsAsync(filter, count);
     }

     /// <summary>
     /// 按日誌等級查詢
     /// </summary>
     /// <param name="level">日誌等級(如:Information、Error、Warning等)</param>
     /// <param name="count">返回數據條數</param>
     /// <returns>日誌事件列表</returns>
     public async Task<List<EventEntity>> QueryByLevelAsync(LogEventLevel level, int count = 1000)
     {
         var filter = $"@Level = '{level}'";
         return await QueryLogsAsync(filter, count);
     }

     /// <summary>
     /// 組合查詢(時間範圍 + 日誌等級 + 屬性值)
     /// </summary>
     /// <param name="startTime">開始時間</param>
     /// <param name="endTime">結束時間</param>
     /// <param name="level">日誌等級</param>
     /// <param name="propertyName">屬性名</param>
     /// <param name="propertyValue">屬性值</param>
     /// <param name="count">返回數據條數</param>
     /// <returns>日誌事件列表</returns>
     public async Task<List<EventEntity>> QueryByTimeLevelAndPropertyAsync(DateTime startTime, DateTime endTime, LogEventLevel level, string propertyName, string propertyValue, int count = 1000)
     {
         // 確保時間轉換為UTC
         var fromTimeUtc = startTime.Kind == DateTimeKind.Utc ? startTime : startTime.ToUniversalTime();
         var toTimeUtc = endTime.Kind == DateTimeKind.Utc ? endTime : endTime.ToUniversalTime();

         // 構建屬性過濾條件
         var filter = $"@Level = '{level}' and {propertyName} = '{propertyValue}'";

         // 使用Seq API專用的時間參數和filter組合
         var resultSet = _connection.Events.EnumerateAsync(
             fromDateUtc: fromTimeUtc,
             toDateUtc: toTimeUtc,
             filter: filter,
             count: count,
             render: true);

         var logs = new List<EventEntity>();
         await foreach (var logEvent in resultSet)
         {
             logs.Add(logEvent);
         }
         return logs;
     }

     /// <summary>
     /// 組合查詢(時間範圍 + 屬性值)
     /// </summary>
     /// <param name="startTime">開始時間</param>
     /// <param name="endTime">結束時間</param>
     /// <param name="propertyName">屬性名</param>
     /// <param name="propertyValue">屬性值</param>
     /// <param name="count">返回數據條數</param>
     /// <returns>日誌事件列表</returns>
     public async Task<List<EventEntity>> QueryByTimeAndPropertyAsync(DateTime startTime, DateTime endTime, string propertyName, string propertyValue, int count = 1000)
     {
         // 確保時間轉換為UTC
         var fromTimeUtc = startTime.Kind == DateTimeKind.Utc ? startTime : startTime.ToUniversalTime();
         var toTimeUtc = endTime.Kind == DateTimeKind.Utc ? endTime : endTime.ToUniversalTime();

         // 構建屬性過濾條件
         var filter = $"{propertyName} = '{propertyValue}'";

         // 使用Seq API專用的時間參數和filter組合
         var resultSet = _connection.Events.EnumerateAsync(
             fromDateUtc: fromTimeUtc,
             toDateUtc: toTimeUtc,
             filter: filter,
             count: count,
             render: true);

         var logs = new List<EventEntity>();
         await foreach (var logEvent in resultSet)
         {
             logs.Add(logEvent);
         }
         return logs;
     }

     /// <summary>
     /// 組合查詢(日誌等級 + 屬性值)
     /// </summary>
     /// <param name="level">日誌等級</param>
     /// <param name="propertyName">屬性名</param>
     /// <param name="propertyValue">屬性值</param>
     /// <param name="count">返回數據條數</param>
     /// <returns>日誌事件列表</returns>
     public async Task<List<EventEntity>> QueryByLevelAndPropertyAsync(LogEventLevel level, string propertyName, string propertyValue, int count = 1000)
     {
         var filter = $"@Level = '{level}' and {propertyName} = '{propertyValue}'";
         return await QueryLogsAsync(filter, count);
     }

     /// <summary>
     /// 基礎查詢方法(僅使用filter條件)
     /// </summary>
     /// <param name="filter">過濾條件,如:"PropertyName = 'Value'"</param>
     /// <param name="count">返回數據條數</param>
     /// <returns>日誌事件列表</returns>
     public async Task<List<EventEntity>> QueryLogsAsync(string filter, int count)
     {
         var logs = new List<EventEntity>();
         var resultSet = _connection.Events.EnumerateAsync(
             render: true,
             count: count,
             filter: filter);

         await foreach (var logEvent in resultSet)
         {
             logs.Add(logEvent);
         }

         return logs;
     }

     /// <summary>
     /// 釋放資源
     /// </summary>
     public void Dispose()
     {
         if (!_disposed)
         {
             _connection?.Dispose();
             _disposed = true;
         }
     }
 }

九、參考資料

Seq官方文檔:https://datalust.co/
Seq.Api文檔:https://github.com/datalust/seq-api

Add a new 评论

Some HTML is okay.