只有累積,沒有奇蹟

2019年5月13日 星期一

[NETCore] 在 ASP.NET Core Web API 中使用 Serilog

前言
近期專案都在嘗試 Serilog,對於使用上有點小小心得,因此整理這篇文章分享 Serilog 在 ASP.NET Core API 上的使用與設定,也接續之前 Serilog 的系列介紹文 : 傳送門 的實際應用心得,希望可以幫到有需要的朋友若有問題或是錯誤的地方歡迎提出來一起討論或是給予指導

ASP.NET Core logging
首先先建立新的 ASP.NET Core Web Application 專案,開啟 Visual Studio 2019 選擇建立新專案,專案名稱輸入 SerilogWebAppLab,模板部分選擇 API,然後按下確定送出
新增完專案之後,可以看到專案中 program.cs 內建 CreateWebHostBuilder 方法,此方法會在 Application 啟動時,使用預設方法也會一併註冊內建 logging,接著我們來看一下內建 logging 輸出樣式,在 ValueController 中建構式加入 _Logger 並在 GET 方法中使用 log.Information、Warning 以及 Error
public class ValuesController : ControllerBase
{
    private readonly ILogger _logger;

    public ValuesController(ILogger<ValuesController> logger)
    {
        _logger = logger;
    }

    // GET api/values
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        _logger.LogInformation("This is LogInformation");
        _logger.LogWarning("This is LogWarning");
        _logger.LogError("This is LogError");

        return new[] { "value1", "value2" };
    }
...
執行專案按下 F5,輸出內容如下
從預設 logging 內容可以發現紀錄了除了自己紀錄的 log 之外資料,紀錄了 Application 以及 Request 的內容還有執行的時間,CreateWebHostBuilder 方法預設的情況下使用的 Config 為專案檔底下的 appsettings.json 及 appsettings.Development.json (依設定環境決定),之前有撰寫過一篇關於設定環境變數的文章,有興趣可以參考 : 傳送門。在此如果希望不啟用內建的 logging 紀錄資訊,可以在 CreateWebHostBuilder 方法中加上  config.ClearProviders()  刪除預設的 logging 提供者
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .ConfigureLogging((hostingContext, config) =>
        {
            config.ClearProviders();
        })
        .UseStartup<Startup>();
在重新執行一次 Application,就會看到 Console output 僅剩三個 log。

Serilog
接著輪到今天的重頭戲 Serilog 登場,首先先透過 Nuget 下載 Serilog for .NET Core 套件
Install-Package Serilog.AspNetCore
Serilog 核心負責紀錄 Log 事件的內容,要將 Log 輸出則是透過 Sink,如果想瞭解更多細節可以參考 結構化日誌 Serilog 初體驗,這裡就不在多加介紹,這裡範例是使用 Console 與寫入實體檔案作為輸出,因此需要另外透過 Nuget 下載相關套件 Sinks.Console 與 Sinks.File 兩種,如果有其他需
Install-Package Serilog.Sinks.Console 
Install-Package Serilog.Sinks.File
下載完 Serilog 相關 Package,接著就是在 WebHost 啟動時設定 Serilog 資訊也就是 Program.cs 中的 main 方法加下以下代碼
public class Program
{
    public static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .WriteTo.Console()
            .WriteTo.File("logs/log_.txt", rollingInterval: RollingInterval.Day)
            .CreateLogger();

        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureLogging((hostingContext, config) =>
            {
                config.ClearProviders();
            })
            .UseStartup<Startup>();
}
程式說明

  • MinimumLevel.Information : 定義 Log 輸出 Level 
  • WriteTo.Console : 設定使用 Console 輸出 
  • WriteTo.File : 設定使用 File 檔案輸出,輸出位置及檔名為 log & log_txt 
  • 上述是在 Program.cs 中加上 Serilog 設定組態設定,在 Serilog 中也支援使用 Config 檔案來設定的動作,如果想要透過定義檔則需要至 Nuget 下載 Settings library
    Install-Package Serilog.Settings.Configuration
    在 appSettings.json 加以下 config 定義內容,設定目的與內容與剛剛在 Program 寫 Log 方式相同
    {
      "Serilog": {
        "MinimumLevel": "Information",
        "WriteTo": [
          {
            "Name": "Console",
            "Args": {
              "outputTemplate": "{Timestamp:yyyy/MM/dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"
            }
          },
          {
            "Name": "File",
            "Args": {
              "Path": "logs/log_.txt",
              "rollingInterval": "Day"
            }
          }
        ]
      }
    }
    在來修改 Program.cs 中的代碼,要調整新增 Configuration 時以檔案的內容為主
    public class Program
    {
        private static string _envName;
        public static void Main(string[] args)
        {
            var configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")
                .AddJsonFile($"appsettings.{_envName}.json", optional: true, reloadOnChange: true)
                .Build();
    
            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(configuration)
                .CreateLogger();
    
            CreateWebHostBuilder(args).Build().Run();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureLogging((hostingContext, config) =>
                {
                    config.ClearProviders();
                    _envName = hostingContext.HostingEnvironment.EnvironmentName;
                })
                .UseStartup<Startup>();
    }
    configuration 部分代碼為定義設定檔的來源,也就是使用建立專案時內建的 appsettings.json,指定 Config 會隨不同環境取得不同的 appsettings.json,其中 CreateLogger 時用  ReadFrom.Configuation()  指定用 檔案內容指定取代原先落落長的代碼。
    下一步就需要在 Startup.cs 中的  ConfigureService()  新增 Serilog 至服務中,這裡使用的是內建的 DI Framework,如果用習慣 Autofac 的朋友也可以下載 autofac-serilog-integration
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        services.AddLogging(loggingBuilder =>
            loggingBuilder.AddSerilog()
        );
    }
    以上設定 Serilgo 完畢,接著重新執行 Application 並觀察其輸出內容,可以看到 logging 紀錄內容已透過 Console 與檔案輸出如下
    也成功寫入檔案,預設會在指定檔名 File 後加上 日期,log_ 變成 log_20190101.txt 
    2019-05-13 13:00:06.279 +08:00 [INF] User profile is available. Using 'C:\Users\marcustung\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.
    2019-05-13 13:00:08.112 +08:00 [INF] Request starting HTTP/1.1 GET https://localhost:5001/api/values  
    2019-05-13 13:00:08.178 +08:00 [INF] Executing endpoint 'SerilogWebAppLab.Controllers.ValuesController.Get (SerilogWebAppLab)'
    2019-05-13 13:00:08.202 +08:00 [INF] Route matched with {action = "Get", controller = "Values"}. Executing action SerilogWebAppLab.Controllers.ValuesController.Get (SerilogWebAppLab)
    2019-05-13 13:00:08.216 +08:00 [INF] Executing action method SerilogWebAppLab.Controllers.ValuesController.Get (SerilogWebAppLab) - Validation state: "Valid"
    2019-05-13 13:00:08.221 +08:00 [INF] This is LogInformation
    2019-05-13 13:00:08.222 +08:00 [WRN] This is LogWarning
    2019-05-13 13:00:08.224 +08:00 [ERR] This is LogError
    2019-05-13 13:00:08.230 +08:00 [INF] Executed action method SerilogWebAppLab.Controllers.ValuesController.Get (SerilogWebAppLab), returned result Microsoft.AspNetCore.Mvc.ObjectResult in 5.7992ms.
    2019-05-13 13:00:08.240 +08:00 [INF] Executing ObjectResult, writing value of type 'System.String[]'.
    2019-05-13 13:00:08.340 +08:00 [INF] Executed action SerilogWebAppLab.Controllers.ValuesController.Get (SerilogWebAppLab) in 131.7199ms
    2019-05-13 13:00:08.344 +08:00 [INF] Executed endpoint 'SerilogWebAppLab.Controllers.ValuesController.Get (SerilogWebAppLab)'
    2019-05-13 13:00:08.351 +08:00 [INF] Request finished in 245.3211ms 200 application/json; charset=utf-8
    成功紀錄 Log 在 Console 與 File 檔案,如果想要的輸出不只是檔案在 Serilog 提供多種 Provider,詳細可以參考官方網站所列的 Provided Sinks : 傳送門

    感想
    透過以上的說明,希望可以讓對 Serilog 有興趣的的朋友可以快速入門,之前也花了點時間介紹 Serilog 相關的入門 & 基本設定方式,若有興趣想了解細節的也可以了解看看,系列文連結 : 傳送門 :)

    參考
    Structured logging concepts in .NET Series
    Serilog series post
    Loggly in ASP.NET Core using Serilog

    0 意見:

    張貼留言

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

    Design by Anders Noren | Blogger Theme by NewBloggerThemes.com