歡迎光臨
每天分享高質量文章

ASP.NET Core 沉思錄 – Logging 的兩種介入方法

ASP.NET Core 中依賴註入是一個很重要的環節。因為幾乎所有的物件都是由它建立的(相關文章請參見《ASP.NET Core 沉思錄 – ServiceProvider 的二度出生》)。因此整個日誌記錄的相關型別也被直接新增到了 IServiceCollection 中。今天我們將介紹各個介面/型別之間的關係,並找到介入日誌記錄功能的兩個主要的入口。

ASP.NET Core 的日誌功能結構

為什麼當我們恰當對日誌進行配置之後就可以記錄日誌呢。那是因為 Framework 一定已經將最關鍵的型別新增到了 IServiceCollection 中。在 ASP.NET Core 中,應用程式的啟動一定會建立 WebHost 而建立 WebHost 一般會用到 WebHostBuilder。在 WebHostBuilder 建立過程中就將一些核心的日誌記錄相關型別新增到了 IServiceCollection 中。

前面我們介紹過,IServiceProvider 有兩次建立過程,一次是在呼叫 WebHostBuilder.Build 時建立的 Hosting 相關的 IServiceProvider,另一次是在 WebHost.StartXxx 方法時建立的應用程式使用的 IServiceProvider。而日誌相關型別第一次的 IServiceProvider 建立之前就已經新增到 IServiceCollection 中了。

在本文寫作時,第一次 IServiceCollection 實體的建立是在 WebHostBuilder.BuildCommonServices 方法中,大概的流程是:

  • 建立 ServiceCollection

  • 呼叫 AddLogging 擴充套件方法

  • IOptions<>; 及其它形式、ILoggerFactoryILogger<>IConfiguratorIConfigureOptions 新增到 ServiceCollection 中。

  • 如果在配置 IWebHostBuilder 過程中呼叫過 ConfigureLogging 則呼叫相關委託新增或替換相關日誌記錄的型別。

程式碼請參見:WebHostBuilder.cs (https://github.com/aspnet/AspNetCore/blob/master/src/Hosting/Hosting/src/WebHostBuilder.cs) 以及LoggingServiceCollectionExtensions.cs (https://github.com/aspnet/Extensions/blob/master/src/Logging/Logging/src/LoggingServiceCollectionExtensions.cs)。

因此,以上提到的型別就是日誌功能的核心型別了。梳理一下這些型別的依賴關係就可以弄清 ASP.NET Core 的日誌功能結構了。

弄清一個結構需要關註兩個部分的內容,第一個部分是宣告上的依賴關係(靜態),另一個部分是呼叫上的依賴關係(動態)。因此我們也會採用這種方式進行梳理。首先宣告上的依賴關係如下:

以上結構在執行時會建立三層 ILogger 實現

  • 最外面的一層就是我們使用的 ILogger<> 實現。它是由 IServiceProvider 直接建立的。

  • 第二層是 LoggerFactory 建立的 Logger,它是一個組合 Logger。

  • 第三層是由 ILoggerProvider 實現建立的負責具體記錄日誌的 ILogger 實現。這些 Logger 都會新增到第二層的組合 Logger 中。

而後,在日誌記錄時,正是按照這三層結構進行任務分發的。

介入日誌功能的幾個入口

在瞭解上述結構之後不難使用我們的具體實現替換預設的 .NET 日誌記錄結構。首先在使用上 ASP.NET Core 上使用的日誌記錄介面有兩種,第一種即 ILoggerFactory,進而建立 ILogger。例如 這裡。而另外一種則是直接使用 ILogger<>。因此我們的介入點有兩個:

  • 直接替換 ILoggerFactory 的實現,這樣可以完全定義自己的 Logger -> Sink 結構和過濾邏輯;但工作量較大。
  • 實現 ILoggerProvider,並將其新增到 IServiceCollection 中。這樣可以復用現有的日誌邏輯。

很多第三方日誌庫就是有選擇的採用了上述一種或者兩種方式。例如,以 Serilog 為例,它支援上述兩種介面:

首先、我們可以使用 webHostBuilder.UseSerilog(...) 的方式將其納入應用程式中。而這種方式使用第一種介入方法。具體程式碼請看:https://github.com/serilog/serilog-aspnetcore/blob/dev/src/Serilog.AspNetCore/SerilogWebHostBuilderExtensions.cs。

其次、我們可以使用 loggerBuilder.AddSerilog(...) 的方式將其納入應用程式中。而這種方式使用第二種介入方法。具體程式碼請看:https://github.com/serilog/serilog-extensions-logging/blob/dev/src/Serilog.Extensions.Logging/SerilogLoggingBuilderExtensions.cs。

總結

日誌記錄有很多可以思考的地方,今天我們只關註 ASP.NET Core 中日誌介入的入口。總結起來有兩個主要入口:

  • 第一、直接替換 ILoggerFactory 實現;
  • 第二、實現具體的 ILoggerProvider 並將其新增到 IServiceCollection 中。

如果您覺得本文對您有幫助,也歡迎分享給其他的人。我們一起進步。歡迎關註我的部落格(https://clrdaily.com)和微信公眾號:

 

    贊(0)

    分享創造快樂