Serilog文件翻譯系列(七) - 應用設定、除錯和診斷、開發接收器

IT规划师發表於2024-10-09

01、應用設定

Serilog 支援在 App.config 和 Web.config 檔案中使用簡單的 配置語法,以設定最低日誌級別、為事件新增額外屬性以及控制日誌輸出。

Serilog 主要透過程式碼進行配置,設定支援旨在作為補充功能。雖然不是全面的,但大多數日誌記錄配置任務都可以透過它實現。

1、啟用 配置

需要從 NuGet 安裝 支援包:

Install-Package Serilog.Settings.AppSettings

要從 讀取配置,可以在 LoggerConfiguration 上使用 ReadFrom.AppSettings() 擴充套件方法:

Log.Logger = new LoggerConfiguration()
  .ReadFrom.AppSettings()
  ... // Other configuration here, then
  .CreateLogger()

你可以組合使用 XML 和基於程式碼的配置,但每個接收器(sink)必須透過 XML 或程式碼進行配置 - 透過程式碼新增的接收器不能透過應用程式設定進行修改。

2、配置日誌記錄器

要配置日誌記錄器,應在程式的 App.config 或 Web.config 檔案中包含一個 元素。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add **key**="serilog:minimum-level" **value**="Verbose" />
    <!-- More settings here -->

設定最低日誌級別

要為應用程式設定日誌級別,請使用 serilog:minimum-level 設定鍵。

<add **key**="serilog:minimum-level" **value**="Verbose" />

有效值是 LogEventLevel 列舉中定義的值:Verbose、Debug、Information、Warning、Error、Fatal。

新增接收器

接收器透過 serilog:write-to 鍵新增。設定名稱與在程式碼中使用的配置方法名稱相匹配,因此以下兩者是等效的:

  .WriteTo.LiterateConsole()

在 XML 中:

  <add **key**="serilog:write-to:LiterateConsole" />

注意:使用 serilog:* 鍵時需要確保唯一性。

接收器程式集必須使用 serilog:using 語法進行指定。例如,要配置:

  <add **key**="serilog:using:LiterateConsole" **value**="Serilog.Sinks.Literate" />
  <add **key**="serilog:write-to:LiterateConsole"/>

如果接收器接受引數,則透過將引數名稱附加到設定後面來指定這些引數。

  .WriteTo.RollingFile(@"C:\Logs\myapp-{Date}.txt", retainedFileCountLimit: 10)

在 XML 中:

  <add **key**="serilog:using:RollingFile" **value**="Serilog.Sinks.RollingFile" />
  <add **key**="serilog:write-to:RollingFile.pathFormat" **value**="C:\Logs\myapp-{Date}.txt" />
  <add **key**="serilog:write-to:RollingFile.retainedFileCountLimit" **value**="10" />

在設定值中指定的任何環境變數(例如 %TEMP%)在讀取時將被適當地展開。

使用來自額外程式集的接收器擴充套件

要使用來自額外程式集的接收器和豐富器,請透過 serilog:using 鍵進行指定。

例如,要使用來自 Serilog.Sinks.EventLog 程式集的配置:

  <add **key**="serilog:using:EventLog" **value**="Serilog.Sinks.EventLog" />
  <add **key**="serilog:write-to:EventLog.source" **value**="Serilog Demo" />

透過屬性豐富日誌

要向日志事件附加額外的屬性,請使用 serilog:enrich:with-property 指令進行指定。

例如,要將屬性 Release 新增到所有事件,並賦值為 "1.2-develop":

  <add **key**="serilog:enrich:with-property:Release" **value**="1.2-develop" />

新增最小級別覆蓋

自 Serilog 2.1 起,可以新增最小級別覆蓋,以更改某些特定名稱空間的最小級別。這是透過設定鍵 serilog:minimum-level:override: 後跟源上下文字首來實現的。

例如,以下兩者是等效的:

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
    .MinimumLevel.Override("Microsoft.AspNetCore.Mvc", LogEventLevel.Error)

在 XML 中:

    <add **key**="serilog:minimum-level" **value**="Information" />
    <add **key**="serilog:minimum-level:override:Microsoft" **value**="Warning" />
    <add **key**="serilog:minimum-level:override:Microsoft.AspNetCore.Mvc" **value**="Error" />

02、除錯和診斷

當 Serilog 的行為不符合你的預期時,這可能是由於內部異常或配置問題引起的。以下是幾種解決問題的方法。

1、SelfLog

首先,如果提供了使用者指定的輸出,Serilog 將會寫入簡單的診斷訊息。在程式啟動時呼叫 SelfLog.Enable():

Serilog.Debugging.SelfLog.Enable(msg => Debug.WriteLine(msg));

系統控制檯、檔案或記憶體中的 StringWriter 都可以透過提供一個 TextWriter 來收集 Serilog 的輸出,而不是使用委託:

Serilog.Debugging.SelfLog.Enable(Console.Error);

Serilog 不會將自己的事件寫入使用者定義的接收器。

警告: SelfLog 不會對提供的 TextWriter 執行任何同步。對於大多數實現,您應該使用 TextWriter.Synchronized() 方法,以確保傳入的物件可以從多個執行緒寫入:

var file = File.CreateText(...);
Serilog.Debugging.SelfLog.Enable(TextWriter.Synchronized(file));

2、除錯符號

大多數 Serilog 包在 symbolsource 上包含除錯符號(_.PDB) - 在 Visual Studio 中將其新增為符號伺服器可以幫助確定來自接收器的異常原因。

3、Serilog 分析器

這是一個基於 Roslyn 的分析工具,用於使用 Serilog 日誌庫的程式碼。它檢查常見錯誤和使用問題。您可以在這裡找到更多資訊。

03、開發接收器

以下示例使用 dotnet 命令建立一個專案。

1、建立專案

mkdir SimpleSink
cd SimpleSink
dotnet new console

新增依賴項

從 NuGet 新增 Serilog 包:

dotnet add package serilog

2、構建一個簡單的接收器

包含以下 using 語句。這些語句用於接收器類以及配置 Serilog。

using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Configuration;

建立接收器

接收器只是實現了 ILogEventSink 介面的類。以下示例將每條訊息(無論日誌級別如何)渲染到控制檯。

public class MySink : ILogEventSink
{
    private readonly IFormatProvider _formatProvider;
    public MySink(IFormatProvider formatProvider)
    {
        _formatProvider = formatProvider;
    }
    public void Emit(LogEvent logEvent)
    {
        var message = logEvent.RenderMessage(_formatProvider);
        Console.WriteLine(DateTimeOffset.Now.ToString() + " "  + message);
    }
}

配置擴充套件

在配置接收器時,通常會使用一種模式,為 LoggerSinkConfiguration 提供一個擴充套件方法類。以下程式碼透過在配置 Serilog 時暴露 MySink 選項來說明這種方法。

public static class MySinkExtensions
{
    public static LoggerConfiguration MySink(
              this LoggerSinkConfiguration loggerConfiguration,
              IFormatProvider formatProvider = null)
    {
        return loggerConfiguration.Sink(new MySink(formatProvider));
    }
}

使用接收器

如在配置基礎知識中所示,可以按如下方式配置新的接收器。

var log = new LoggerConfiguration()
    .MinimumLevel.Information()
    .WriteTo.MySink()
    .CreateLogger();

釋放資源

如果接收器實現了 IDisposable,當呼叫 Log.CloseAndFlush()(使用靜態 Log 類時)或者直接釋放寫入接收器的 Logger 時,Serilog 將呼叫其 Dispose() 方法。

處理錯誤和異常

如果接收器無法接受或成功處理事件,它可以(並且應該)從 Emit() 中丟擲異常,以通知 Serilog。除非接收器明確配置為審計,Serilog 將抑制該異常並向 SelfLog 寫入標準診斷訊息。

接收器還可以將診斷訊息寫入 SelfLog,但應謹慎使用,以避免對效能產生不良影響。

執行緒安全

接收器構造完成後必須完全執行緒安全,並接受來自任何執行緒的 Emit() 呼叫。Serilog 將併發呼叫 Emit()。

3、完整示例

以下是作為控制檯應用程式的完整示例程式碼。

using System;
using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Configuration;
namespace SimpleSink
{
    class Program
    {
        static void Main(string[] args)
        {
            var log = new LoggerConfiguration()
                .MinimumLevel.Information()
                .WriteTo.MySink()
                .CreateLogger();
            var position = new { Latitude = 25, Longitude = 134 };
            var elapsedMs = 34;
            log.Information("Processed {@Position} in {Elapsed:000} ms.", position, elapsedMs);
        }
    }
    public class MySink : ILogEventSink
    {
        private readonly IFormatProvider _formatProvider;
        public MySink(IFormatProvider formatProvider)
        {
            _formatProvider = formatProvider;
        }
        public void Emit(LogEvent logEvent)
        {
            var message = logEvent.RenderMessage(_formatProvider);
            Console.WriteLine(DateTimeOffset.Now.ToString() + " "  + message);
        }
    }
    public static class MySinkExtensions
    {
        public static LoggerConfiguration MySink(
                  this LoggerSinkConfiguration loggerConfiguration,
                  IFormatProvider formatProvider = null)
        {
            return loggerConfiguration.Sink(new MySink(formatProvider));
        }
    }
}

示例輸出

17/01/2017 3:10:26 PM +10:00 Processed { Latitude: 25, Longitude: 134 } in 034 ms.

:相關原始碼都已經上傳至程式碼庫,有興趣的可以看看。https://gitee.com/hugogoos/Planner

相關文章