ASP.NET Core擴充套件庫之日誌

xfrog發表於2021-03-10
    上一篇我們對Xfrogcn.AspNetCore.Extensions擴充套件庫功能進行了簡單的介紹,從這一篇文章開始,我將逐步介紹擴充套件庫中的核心功能。
    日誌作為非業務的通用領域基礎功能,有非常多的技術實現,這些第三方庫避免了我們花費時間去重複實現,不過,很多日誌庫配置複雜,不易於使用,入手較難,而有些庫可能與ASP.NET Core的結合並不好。
    如果我們沒有對所使用的日誌庫進行詳細瞭解,日誌庫也可能產生嚴重的問題,在我的開發生涯中,曾經遇到過多次因為日誌庫而導致的生產事故。
    擴充套件庫日誌模組致力於將日誌相關的最佳實踐進行封裝,簡化日誌庫的使用,讓我們真正從非業務程式碼中解放出來。

一、簡介

    ASP.NET Core擴充套件庫中日誌功能是對Serilog的進一步封裝,之所以選擇Serilog,源於我們在開發工程中的實踐,我們的日誌庫經歷了自己開發、選擇使用NLog,最後定格在使用Serilog庫上。
    Serilog日誌庫也並不是非常易於使用,而且可能也缺少一些必要功能,這就是我們需要進一步封裝的原因。
    日誌功能預設提供了Console及File兩種日誌目標,他們都分別支援文字和Json格式。
    我們也新增了日誌的分類、日誌記錄層級的動態修改、本地檔案日誌的定時清理、本地日誌檔案的按目錄儲存、對容器化下EFK日誌架構的支援、以及日誌在測試中的支援功能等。

二、使用

    日誌庫是隨著擴充套件庫一起啟用的,最簡單的情況是啟用擴充套件庫即可,預設配置將開啟檔案日誌目標,日誌存入應用下Logs目錄,以日期為資料夾,以日誌名稱為檔名稱。
    開啟擴充套件庫有兩種方式,可以在IHostBuilder上通過UseExtensions方法,或者在Startup啟動類ConfigureServices方法中通過IServiceCollection的AddExtensions方法。
    // 通過IHostBuilder上的UseExtensions方法
    // Program.cs  .NET 5.0 
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseExtensions(args);
                    webBuilder.UseStartup<Startup>();
                });
    }
或者:
    // 在Startup類中
    public class Startup
    {

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddExtensions(Configuration);
        }
    }

三、配置

    日誌的配置可以通過程式碼方式或者通過配置檔案方式。
    採用程式碼方式,在UseExtensions方法或者AddExtensions中傳入配置物件委託即可:
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseExtensions(args, config=>
                    {
                        config.AppLogLevel = Serilog.Events.LogEventLevel.Verbose;
                        config.SystemLogLevel = Serilog.Events.LogEventLevel.Verbose;
                    });
                    webBuilder.UseStartup<Startup>();
                });

如果採用配置檔案方式,只需在配置源(如appsettings.json)中設定相關的配置欄位:

{
  "AppLogLevel": "Verbose",
  "AllowedHosts": "*"
}
    如果都採用,程式碼方式將會覆蓋配置檔案方式。
    除此之外,如果你需要對Serilog配置進行更詳細的控制,那麼可以直接在UseExtensions方法或者AddExtensions中傳入Serilog的日誌配置委託。此項委託的設定將覆蓋上述的自動配置。

四、配置日誌級別

    為了簡化配置,在擴充套件庫中,我們根據日誌名稱將日誌分為系統日誌、應用日誌以及EFCore日誌,他們分別通過配置中的AppLogLevel、SystemLogLevel及EFCoreCommandLevel屬性來控制。日誌級別的配置都支援執行時動態修改,無需重啟應用。
日誌分類
對應日誌名
對應配置欄位
預設級別
系統日誌
Microsoft.* 以及 System.*
SystemLogLevel
Warning
EFCore日誌
Microsoft.EntityFrameworkCore.Database.Command
EFCoreCommandLevel
Information
應用日誌
除開系統日誌及EFCore日誌之外的日誌
AppLogLevel
Information

五、日誌級別的動態修改

    如果你是通過配置源來配置的日誌級別,那麼當配置源更新時(一般通過配置物件的Reload方法),日誌級別將自動修改。
    如果需要採用程式碼方式,你可以通過全域性的WebApiConfig例項進行配置:
    // 動態修改日誌級別
    var apiConfig = host.Services.GetRequiredService<WebApiConfig>();
    apiConfig.AppLogLevel = Serilog.Events.LogEventLevel.Error;

六、本地檔案日誌配置

    針對本地日誌的配置,包含日誌檔案的路徑模板、日誌檔案的定時清理、日誌的自動壓縮等。
    本地檔案日誌路徑通過LogPathTemplate設定來配置,預設為LogPathTemplates.DayFolderAndLoggerNameFile,表示以每天作為子目錄,以日誌名稱作為日誌檔名。通過LogPathTemplates也內建了其他的路徑模板:
路徑模板名
說明
DayFolderAndLoggerNameFile
以每天日期為目錄,日誌名稱為檔名
DayFile
以每天日期為日誌名稱
LoggerNameAndDayFile
以[日誌名稱_每天日誌]為日誌檔名稱
LevelFile
以日誌級別縮寫為日誌檔名稱
DayFolderAndLevelFile
以每天日期為目錄,日誌級別縮寫為日誌名稱
    由於LogPathTemplate為字串配置,你也可以配置其他的路徑模板。
    關於日誌的定時清理,可以通過MaxLogDays配置來指定日誌保留的天數,如果設定為0,表示不清理,這是預設配置。
    通過MaxLogFileSize以及RetainedFileCount配置可以設定日誌檔案的自動壓縮策略,MaxLogFileSize預設設定為100mb,超過此大小後,日誌將寫到新的檔案,RetainedFileCount為可旋轉的日誌檔案數量,預設為31個,超過此數量後的日誌將被自動壓縮。

七、容器化支援

    在容器化環境下,日誌一般會採用EFK的架構,在k8s中,我們推薦F採用fluent-bit而不是filebeat。這種框架下,我們只需將日誌輸出到控制檯,容器將控制檯輸出定位到Docker宿主機,然後通過fluent-bit掃描日誌檔案,進行解析處理,傳送給ES。
    在這種模式下,你需要將ConsoleJsonLog設定為true來開啟JSON格式的控制檯日誌目標。同時,由於控制檯單行字數有限制,可能導致日誌被擷取,故可能需要通過MaxLogLength來設定單條日誌的長度限制,此設定預設為8kb,適合大多數場景。超出長度的日誌並不會被忽略,而是會拆分成多條日誌,以此來保證日誌的完整性。
    // 要支援容器化EFK日誌模式,一般只需要設定ConsoleJsonLog為true即可
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseExtensions(args, config=>
                {
                    config.ConsoleJsonLog = true;
                });
                webBuilder.UseStartup<Startup>();
            });

八、測試支援

    有時我們可能需要在單元測試中檢查日誌的輸出,這時,我們可以使用擴充套件庫在ILoggingBuilder上的擴充套件方法來新增測試日誌目標。隨後,你可以通過IServiceProvider上的GetTestLogContent方法獲取已記錄的日誌內容列表。
    IServiceCollection services = new ServiceCollection()
        .AddExtensions()
        .AddLogging(logBuilder =>
        {
            // 新增測試日誌記錄器
            logBuilder.AddTestLogger();
        });
        
    IServiceProvider provider = services.BuildServiceProvider();
    // 獲取日誌內容
    var logContent = provider.GetTestLogContent();

九、禁用Serilog

    如果你覺得上述所有功能都不太適合你的場景,但是你又需要使用擴充套件庫的其他功能,那怎麼辦呢? 非常簡單,你只需要將EnableSerilog設定為false,即可完全禁用上述日誌功能。
 
有關日誌的詳細配置,可參考[文件]
 
Xfrogcn.AspNetCore.Extensions地址:[GitHub] [Gitee]

相關文章