只有累積,沒有奇蹟

2019年5月1日 星期三

[NETCore] 結構化日誌 Serilog 初體驗

前言
在 .NET 使用日誌框架第一時間會想到 NLog 或是 Log4Net 兩種 Log 常使用的 Library,Serilog 是這幾年快速崛起的 Log 框架之一,Serilog 是以 Structured logging 為基礎進行設計,透過 logging API 可以輕鬆的記錄應用程式中對象屬性,方便快速進行 logging 內容進行查詢與分析,並將其紀錄內容透過 json (可指定) 的方式輸出,這篇就介紹 Serilog 在 ASP.NET Core 中如何的安裝與基本應用使用若有問題或是錯誤的地方歡迎網路的高手大大給予指導

安裝
Serilog 支援 NET Framework 與 NET Core 版本,使用前需要透過 Nuget 進行下載的動作,首先先建立一個名稱為 SerilogLab 的 Console 專案,接著開啟 Nuget Package Manager (快速打開方法: Ctrl + Q ) 輸入 "Serilog" 搜尋,安裝最新版的 serilog 套件
或是在 Nuget Package Console 輸入指令,下載核心項目 Serilog 與需要用到的 Logging Sinks 
  1. PM> Install-Package Serilog
  2. PM> Install-Package Serilog.Sinks.Console
確認是否有安裝成功,可以點擊專案檔內容是否包含以下 package
  1. <PackageReference Include="Serilog" Version="2.8.0" />
  2. <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />

Logging Sinks
Serilog 核心負責紀錄 Log 事件的內容,如果要將 Log 輸出則是透過 Snik (槽),Serilog 最常見的是 console 與 file 檔案兩種 sink,另外提供不同的輸出方式如Amazon、Azure、Elasticsearch、Slack等多樣需要使用時要在 nuget 下載 Sinks library 另外官方也有整理目前支援的 sinks 清單 : 傳送門,有興趣可以自行查閱

使用
接著在 Console 專案 Program 啟動加入下列代碼
  1. using System;
  2. using Serilog;
  3.  
  4. namespace SerilogLab
  5. {
  6. class Program
  7. {
  8. static void Main(string[] args)
  9. {
  10. var log = new LoggerConfiguration()
  11. .WriteTo.Console()
  12. .CreateLogger();
  13.  
  14. log.Information("Hello, Serilog!");
  15. log.Debug("This is debug");
  16. log.Error("Something error");
  17. log.Fatal("This is fatal");
  18.  
  19. Console.ReadKey();
  20. }
  21. }
  22. }
程式說明

  • LoggerConfiguration : 使用 LoggerConfiguration 建立 ILogger 物件
  • WriteTo.Console : 使用 Console 輸出至主控台
  • CreateLogger : 使用配置的 sink 接收器也就是 Console,新增 Logger 物件
  • 採用 Fluent Interface 流利介面的設計 ( LINQ 很常見),讓代碼看起來更簡潔。以上代碼輸出如下

    Log
    在 Serilog 中提供靜態 Log 讓開發者使用,有時在開發時會在建構子注入 logging 物件方便記錄,舉例來說常常可以看到在 Controller、service 或是 repository 上建構子注入 ILog 的 interface,可以透過以下方式統一建立 Log 實體存放在 Serilog Log 的 Static Logger 中,代碼如下 
    1. Log.Logger = new LoggerConfiguration()
    2. .WriteTo.Console()
    3. .CreateLogger();
    4.  
    5. Log.Information("Hello, Serilog by Log!");
    輸出如下,與一般輸出是相同的
    注意 : 使用 Static 的方式缺點就是在測試時會造成不便,因此可以依據需求來決定是否需要使用

    結構化日誌
    為了瞭解 Serilog 背後的設計理念與原由,作者 Nicholas Blumhardt 在個人部落格寫了一系列相關文章來說明設計概念,以下為小弟粗淺的整理文章重點,想了解更多的朋友也請透過文章傳送門自行服用內容 : Structured logging concepts in .NET Series ,在應用程式紀錄 Log 時,大致來說紀錄方式可以分為 Text logging 也是一般常見的 log 檔記錄方式 與 Structured logging 與結構化的方式記錄 Log
    Text logging :
    1. 12:23:10 [INF] Service "loyalty-card-printer" starting up on host 8fd342hkg22u
    2. 12:23:11 [INF] Listening on http://8fd342hkg22u.example.com:1234
    3. 12:40:55 [INF] Card replacement request received for customer-98048
    內容清楚且容易閱讀,清楚紀錄發生的時間點、問題層級以及內容資訊,呈現格式對開發者閱讀是方便地但如果搜尋 Log 內容時則需使用全文檢索或是正規表達式進行 parse 的動作,才可以找到正確的資訊。
    Structured logging : 
    1. time=12:23:11, level=INF, endpoint=http://8fd342hkg22u.example.com:1234, activity=listening
    2. time=12:23:20, level=INF, customer=customers-1099972, activity=replacement
    3. time=12:40:55, level=INF, customer=customer-98048, activity=replacement
    時間戳記加上其屬性值 key / value 的組合,透過結構化的方式可以讓 Log 更容易得讓機器閱讀,更方便於大規模的搜尋與分析。其 logging 規範名為 message template,同時滿足開發者閱讀方便性與機器可解讀格式,下圖為 message template 概念的示意圖
    碎碎念 : 好的 Log 設計與監控可以讓問題快速被定位,而不是讓 oncall 同仁透過觀落陰解決。

    結構化數據
    一開始有輸出 Hello Serilog 簡單提到 serilog 基本使用方式,接著在說明 serilog 結構化資料的方法,下面範例是使用 Serilog information 方法紀錄 var 與集合 fruit 內容
    1. // var
    2. var count = 456;
    3. log.Information("Retrieved {Count} records", count);
    4.  
    5. // Collections
    6. var fruit = new[] { "Apple", "Pear", "Orange" };
    7. log.Information("In my bowl I have {Fruit}", fruit);
    上面代碼 Console 輸出如下
    1. [11:30:59 INF] Retrieved 456 records
    2. [11:30:59 INF] In my bowl I have ["Apple", "Pear", "Orange"]
    Serilog 可以將事件的屬性記錄到 Log 中,舉例來說如果希望輸出為 Json 格式取代既有的 txt 檔案 (也可輸出其他格式),可以指定其 formatter 並載入  Serilog.Formatting.Compact  設定格式化設定,即可將輸出內容轉為 json 檔案
    1. var log = new LoggerConfiguration()
    2. .WriteTo.Console()
    3. .WriteTo.File(new CompactJsonFormatter(), "log.txt")
    4. .CreateLogger();
    原本範例 count 會加上屬性,時間會加上@t,並輸出定義的模板(message template) @mt 及參數內容
    1. {
    2. "@t": "2019-05-01T03:30:59.7633809Z",
    3. "@mt": "Retrieved {Count} records",
    4. "Count": 456
    5. }
    另一個範例 fruit 輸出如下
    1. {
    2. "@t": "2019-05-01T03:30:59.8247590Z",
    3. "@mt": "In my bowl I have {Fruit}",
    4. "Fruit": [
    5. "Apple",
    6. "Pear",
    7. "Orange"
    8. ]
    9. }
    關於 Serilog 的輸出格式就先介紹到這裡,詳細更多細節可以參考官方網站詳細介紹 : Formatting Output

    感想
    這篇針對 Serilog 的設計概念與基本使用進行了簡單的介紹,相信在使用上對大家來說難度都不高,自己在新專案上也有導入,之後有時間會在介紹一些關於設定與實作的細節部分,最後推薦對於結構化紀錄有興趣的可以參考作者的部落格介紹 Structured logging concepts in .NET Series,相信可以對於相關知識有更進一步的了解,也可以在.NET Framework 或是 ASP.NET Core 選擇 Logging 時有不一樣的選擇 :)

    參考
    Structured logging concepts in .NET Series

    Related Posts:

    • [NETCore] ASP.NET Core 啟動失敗 - 嘗試存取通訊端被拒絕,因為存取權限不足問題  接獲同事詢問專案無法正常啟用,專案是使用 ASP.NET Core 2.2 開發並搭配 Kestrel 使用,在過去開發時都正常運作但今天忽然就遭遇啟動異常的狀況,在啟用時會跳出錯誤訊息為 'Unable to bind to http://localhost:5000 on the IPv4 loopback interface: '嘗試存取通訊端被拒絕,因為存取權限不足。''  ,這篇… Read More
    • [NETCore] ASP.NET Core 中的排程利器 - Coravel 前言 在 ASP.NET 中相信大家都會有過開發 Scheduler 排程的需求,過去可能會使用 ASP.NET 中較有名的框架像是 Quartz.NET 或是 Hangfire,兩種框架各有優缺點小弟不才剛好都有碰過,兩種排程框架各有喜好者可以依據自己的愛好來選用。今天所要介紹的是另一套 Schedule Job 框架 Coravel,作者在設計 API 時用 Fluent interface 方式進行設計,因此在使用上相當直覺與方便… Read More
    • [NET] 探索 OpenTelemetry Auto-Instrumentation 的核心技術前言 Observability 是手段,不是目的。透過 Auto-Instrumentation,我們更接近「讓系統自己說話」的願景。 在 COSCUP 2024 我有幸(不要臉) 再次參與並分享這一年來我在可觀測性實踐上最有趣的內容:「OpenTelemetry 的 Auto-Instrumentation 技術核心與應用實戰」。這篇文章,我會完整拆解 OpenTelemetry SDK 的 Auto-Instrumentation 的… Read More
    • [NETCore] ASP.NET Core 3.0 Worker Service 搭配 Coravel 建立排程服務前言 如果一直有在 follow 消息的朋友可以發現在 ASP.NET 3.0 有新增 Work Services 專案範本,可以透過幾個簡單的步驟使用 Workers with Windows Services 服務,詳細可以參考微軟官網對於 worker Service 的介紹文章 .NET Core Workers as Windows Services,在上一篇介紹了 ASP.NET Core 中的輕量級排程… Read More
    • [NETCore] ASP.NET Core 建立與解析 QueryString 參數說明 之前介紹過在 .NET 中可以使用 Utility.ParseQueryString 處理 Url 中的參數,傳送門 : 使用 ParseQueryString 取得網址參數,但所使用的 System.Web 命名空間僅存在於 ASP.NET Framework 不支援 ASP.NET Core,在搜尋更好的解決方案中發現了在 ASP.NET Core 提供新的 API - QueryHelpers 可以達到同樣效果,此… Read More

    0 意見:

    張貼留言

    Copyright © 2025 m@rcus 學習筆記 | Powered by Blogger

    Design by Anders Noren | Blogger Theme by NewBloggerThemes.com