Serilog文件翻譯系列(六) - 可用的接收器、增強器、格式化輸出

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

01、提供的接收器

Serilog 使用接收器將日誌事件以各種格式寫入儲存。許多接收器由更廣泛的 Serilog 社群開發和支援;可以透過在 NuGet 上搜尋 serilog 標籤找到。

02、增強器

日誌事件可以透過多種方式增強屬性。透過 NuGet 提供了一些預構建的增強器:

Install-Package Serilog.Enrichers.Thread

增強配置是透過 Enrich 配置物件進行的:

var log = new LoggerConfiguration()
    .Enrich.WithThreadId()
    .WriteTo.Console()
    .CreateLogger();

透過日誌寫入的所有事件將攜帶一個名為 ThreadId 的屬性,表示寫入它們的託管執行緒的 ID。(根據約定,Enrich 上的任何 .WithXyz() 方法都會建立名為 Xyz 的屬性。)

1、日誌上下文

Serilog.Context.LogContext 可以用來動態新增和移除來自環境“執行上下文”的屬性;例如,在一個事務期間寫入的所有訊息可能會攜帶該事務的 ID,等等。

此功能必須在配置時透過 .FromLogContext() 新增到日誌記錄器中:

var log = new LoggerConfiguration()
    .Enrich.FromLogContext()

然後,可以使用 LogContext.PushProperty() 向上下文新增和移除屬性:

log.Information("No contextual properties");
using (LogContext.PushProperty("A", 1))
{
    log.Information("Carries property A = 1");
    using (LogContext.PushProperty("A", 2))
    using (LogContext.PushProperty("B", 1))
    {
        log.Information("Carries A = 2 and B = 1");
    }
    log.Information("Carries property A = 1, again");
}

將屬性推送到上下文中會覆蓋任何具有相同名稱的現有屬性,直到從 PushProperty() 返回的物件被釋放,如示例中的屬性 A 所示。

重要提示:必須按照新增的確切順序從上下文中彈出屬性。否則,行為是未定義的。

2、可用的增強器包

Serilog 專案提供:

  • Serilog.Enrichers.Environment - WithMachineName() 和
    WithEnvironmentUserName()
  • Serilog.Enrichers.Process - WithProcessId()
  • Serilog.Enrichers.Thread - WithThreadId()

其他有趣的增強器:

  • Serilog.Web.Classic - WithHttpRequestId() 和許多其他在經典 ASP.NET 應用程式中有用的增強器
  • Serilog.Exceptions - WithExceptionDetails() 新增來自異常的額外結構化屬性
  • Serilog.Enrichers.Demystify - WithDemystifiedStackTraces()
  • Serilog.Enrichers.ClientInfo - WithClientIp()、WithCorrelationId() 和 WithRequestHeader("header-name") 將新增具有客戶端 IP、關聯 ID 和 HTTP 請求頭值的屬性
  • Serilog.Enrichers.ExcelDna - WithXllPath() 和許多其他在 Excel-DNA 外掛中有用的增強器
  • Serilog.Enrichers.Sensitive - WithSensitiveDataMasking() 在日誌事件中掩蓋敏感資料
  • Serilog.Enrichers.GlobalLogContext - FromGlobalLogContext() 動態新增來自“全域性上下文”的屬性

03、格式化輸出

Serilog 提供了多種輸出格式機制。

1、格式化純文字

寫入純文字輸出的接收器,例如控制檯和基於檔案的接收器,通常接受輸出模板以控制日誌事件資料的格式。

這些接收器寫入的事件格式可以使用 outputTemplate 配置引數進行修改。例如,要控制控制檯接收器:

Log.Logger = new LoggerConfiguration()
    .WriteTo.Console(outputTemplate:
        "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
    .CreateLogger();

輸出模板中可以出現多個內建屬性:

  • Exception - 完整的異常訊息和堆疊跟蹤,以多行格式顯示。如果事件沒有關聯的異常,則為空。
  • Level - 日誌事件級別,以完整級別名稱格式化。要使用更緊湊的級別名稱,可以使用格式如 {Level:u3} 或 {Level:w3} 來分別表示三個字元的大寫或小寫級別名稱。
  • Message - 日誌事件的訊息,呈現為純文字。:l 格式說明符可以關閉字串的引用,:j 則使用 JSON 風格渲染任何嵌入的結構化資料。
  • NewLine - 屬性值為 System.Environment.NewLine。
  • Properties - 所有在輸出中未出現的事件屬性值。使用 :j 格式可以進行 JSON 渲染。
  • Timestamp - 事件的時間戳,型別為 DateTimeOffset。
  • TraceId - 建立事件時活動的追蹤 ID(如果有)。
  • SpanId - 建立事件時活動的跨度 ID(如果有)。

透過增強器附加的事件屬性也可以出現在輸出模板中。

2、格式化 JSON

許多接收器會將日誌事件記錄為 JSON,或者可以配置為這樣做。要輸出 JSON 而不是純文字,可以指定格式化程式。以下示例使用來自 Serilog.Formatting.Compact 的格式化程式配置檔案接收器。

Log.Logger = new LoggerConfiguration()
    .WriteTo.File(new CompactJsonFormatter(), "log.txt")
    .CreateLogger();

Serilog 專案提供了三種 JSON 格式化程式:

  • Serilog.Formatting.Json.JsonFormatter - 這是 Serilog 包中歷史預設的格式化程式。它生成完整的日誌事件渲染,並支援一些配置選項。
  • Serilog.Formatting.Compact.CompactJsonFormatter - 這是一個較新、更節省空間的 JSON 格式化程式,隨 Serilog.Formatting.Compact 一起提供。
  • Serilog.Formatting.Compact.RenderedCompactJsonFormatter - 也是隨 Serilog.Formatting.Compact 提供的,該格式化程式將訊息模板預先渲染為文字。

3、靈活的的格式化與 ExpressionTemplate

Serilog.Expressions 包含了 ExpressionTemplate 類,用於更復雜的文字和 JSON 格式化。表示式模板可以包含條件塊、重複部分、對事件屬性的計算以及自定義格式化函式。

ExpressionTemplate 實現了 ITextFormatter 介面,因此它可以與任何基於文字的 Serilog 接收器一起使用,包括控制檯(帶 ANSI 顏色主題)、檔案、除錯和電子郵件。

4、義格式化程式

純文字和 JSON 格式化都是透過 ITextFormatter 介面實現的。該介面的實現可以將日誌事件格式化為任何基於文字的格式。

自定義 JSON 格式化程式可以圍繞 Serilog 中包含的 JsonValueFormatter 類構建。

格式提供程式

有多種選項可用於格式化單個型別的輸出,例如日期。一個例子是大多數接收器接受的格式提供程式。

下面是一個使用 Serilog.Sinks.Console 接收器的簡單控制檯示例。這使用了預設的日期渲染行為。

class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime Created { get; set; }
}
 
public class Program
{
    public static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
            .CreateLogger();
 
        var exampleUser = new User { Id = 1, Name = "Adam", Created = DateTime.Now };
        Log.Information("Created {@User} on {Created}", exampleUser, DateTime.Now);
 
        Log.CloseAndFlush();
    }
}

這將以下內容寫入控制檯。

[18:46:45 INF] Created {"Id": 1, "Name": "Adam", "Created": "2018-05-17T18:46:45.9064879+10:00", "$type": "User"} on 05/17/2018 18:46:45

在某些情況下,可能希望重寫或指定 DateTime 的格式。可以透過實現 IFormatProvider 來實現這一點。這種策略適用於您傳遞給 Serilog 的任何型別。

class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime Created { get; set; }
}
 
class CustomDateFormatter : IFormatProvider
{
    readonly IFormatProvider basedOn;
    readonly string shortDatePattern;
    public CustomDateFormatter(string shortDatePattern, IFormatProvider basedOn)
    {
        this.shortDatePattern = shortDatePattern;
        this.basedOn = basedOn;
    }
    public object GetFormat(Type formatType)
    {
        if (formatType == typeof(DateTimeFormatInfo))
        {
            var basedOnFormatInfo = (DateTimeFormatInfo)basedOn.GetFormat(formatType);
            var dateFormatInfo = (DateTimeFormatInfo)basedOnFormatInfo.Clone();
            dateFormatInfo.ShortDatePattern = this.shortDatePattern;
            return dateFormatInfo;
        }
        return this.basedOn.GetFormat(formatType);
    }
}
 
public class Program
{
    public static void Main(string[] args)
    {
        var formatter = new CustomDateFormatter("dd-MMM-yyyy", new CultureInfo("en-AU"));
        Log.Logger = new LoggerConfiguration() 
            .WriteTo.Console(formatProvider: new CultureInfo("en-AU")) // Console 1
            .WriteTo.Console(formatProvider: formatter)                // Console 2
            .CreateLogger();
 
        var exampleUser = new User { Id = 1, Name = "Adam", Created = DateTime.Now };
        Log.Information("Created {@User} on {Created}", exampleUser, DateTime.Now);
 
        Log.CloseAndFlush();
    }
}

以下是上述示例的輸出,配置了兩個控制檯接收器。

[13:57:12 INF] Created {"Id": 1, "Name": "Adam", "Created": "2020-09-01T13:56:59.7803740-05:00", "$type": "User"} on 1/09/2020 1:57:12 PM
[13:57:12 INF] Created {"Id": 1, "Name": "Adam", "Created": "2020-09-01T13:56:59.7803740-05:00", "$type": "User"} on 01-Sep-2020 1:57:12 PM

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

相關文章