第三十八節:SeriLog日志的各種用法以及與Core MVC封裝集成


一. 簡介

1. 說明

 Serilog是一個用於.net應用程序的診斷日志庫。它易於設置,擁有簡介的API,並且可以在所有最新的.net平台上運行。雖然它甚至在最簡單的應用程序中也很有用,但Serilog對結構化日志記錄的支持在檢測復雜、分布式和異步的應用程序和系統時非常出色。 和其它日志類庫一樣,Serilog可以輸出到控制台、文件、數據庫等多種載體。

2. 各種輸出載體

 下面是各種載體對應的程序集(很多,下面僅列出部分,可去Nuget上查找),本節重點介紹:控制台、各種文件(同步和異步)、SQLServer的寫入。

 【Serilog.Sinks.Console】

 【Serilog.Sinks.File】

 【Serilog.Sinks.Async】 異步寫入文件,需要配合File程序集一塊使用

 【Serilog.Sinks.MSSqlServer】

 【Serilog.Sinks.MySQL】

 【Serilog.Sinks.Seq】

 【Serilog.Sinks.Elasticsearch】

-----下面是Core Mvc專用的,內含多個程序集

 【Serilog.AspNetCore】

3. 參考地址

 (1).GitHub: https://github.com/serilog/serilog            https://github.com/serilog/serilog-aspnetcore

 (2).官網:https://serilog.net/

 (3).參考博客:https://www.cnblogs.com/RainFate/p/12073662.html

                        https://www.cnblogs.com/diwu0510/p/12828519.html

 

二. 各種實操測試

1. 前言

(1). 日志級別

 FATAL(致命錯誤) > ERROR(一般錯誤) > Warning(警告) > Information(一般信息) > DEBUG(調試信息)>Verbose(詳細模式,即全部)

 代碼中通過MinimumLevel.Debug()來設置日志級別,設置后只能捕獲該級別和高於該級別的日志信息了

(2). 日志模板

 框架定義的參數有:LogLevel日志級別、Message日志信息、Exception異常信息、NewLine換行,可以自定義格式如下:

 "{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message:{Message}{NewLine}{Exception}" + new string('-', 100);

2. 輸出控制台

(1). 通過Nuget安裝程序集:【Serilog 2.10】【Serilog.Sinks.Console 3.1.1】

(2). 設置日志捕獲級別、日志模板、輸出途徑(WriteTo.Console),並且createLogger即可

(3). 通過各種方法進行調用

注: Log.CloseAndFlush();就銷毀了該對象,再次使用需要重新創建了。

代碼分析:

            {
                string SerilogOutputTemplate = "{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message:{Message}{NewLine}{Exception}" + new string('-', 100);
                Log.Logger = new LoggerConfiguration()
                            .MinimumLevel.Debug() // 捕獲的最小日志級別
                            .WriteTo.Console(LogEventLevel.Verbose, SerilogOutputTemplate)
                            .CreateLogger();
                Log.Information("123456789");
                try
                {
                    int.Parse("sfsdfsf");
                }
                catch (Exception ex)
                {
                    Log.Error(ex, ex.Message);
                }
                Log.CloseAndFlush();
            }

3. 輸入文件-同步

(1). 通過Nuget安裝程序集:【Serilog 2.10】【Serilog.Sinks.File 4.1.0】

(2). 設置日志捕獲級別、日志模板、輸出途徑(WriteTo.File),並且createLogger即可

(3). 通過各種方法進行調用

PS:WriteTo.File詳解

 path:默認路徑是程序的bin目錄+path參數,當然也可以寫絕對路徑,只需要寫入參數就可以了

 rollingInterval:創建文件的類別,可以是分鍾,小時,天,月。 此參數可以讓創建的log文件名 + 時間。例如ApiLog20210109.log

 outputTemplate:日志模板,可以自定義

 retainedFileCountLimit:設置日志文件個數最大值,默認31,意思就是只保留最近的31個日志文件,等於null時永遠保留文件。

代碼分享:

            {
                string SerilogOutputTemplate = "{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message:{Message}{NewLine}{Exception}" + new string('-', 100);
                Log.Logger = new LoggerConfiguration()
                            .MinimumLevel.Debug() // 捕獲的最小日志級別
                            .WriteTo.File("MyLogs\\ApiLog.txt", rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate, retainedFileCountLimit: null)
                            .CreateLogger();
                Log.Information("123456789");
                try
                {
                    int.Parse("sfsdfsf");
                }
                catch (Exception ex)
                {
                    Log.Error(ex, ex.Message);

                }
                Log.CloseAndFlush();
            }
View Code

日志文件內容:

4. 輸入文件-異步(推薦)

(1). 通過Nuget安裝程序集:【Serilog 2.10】【Serilog.Sinks.File 4.1.0】【Serilog.Sinks.Async 1.4.0】

(2). 設置日志捕獲級別、日志模板、輸出途徑(WriteTo.Async(a => a.File())),並且createLogger即可

(3). 通過各種方法進行調用

代碼分享:

            {
                string SerilogOutputTemplate = "{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message:{Message}{NewLine}{Exception}" + new string('-', 100);
                Log.Logger = new LoggerConfiguration()
                            .MinimumLevel.Debug() // 捕獲的最小日志級別
                            .WriteTo.Async(a => a.File("My_Logs\\ApiLog.txt", rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate, retainedFileCountLimit: null))
                            .CreateLogger();
                Log.Information("123456789");
                try
                {
                    int.Parse("sfsdfsf");
                }
                catch (Exception ex)
                {
                    Log.Error(ex, ex.Message);
                }
                Log.CloseAndFlush();
            }
View Code

5. 按照日志級別存放到不同文件夾-(同步、異步)

(1). 通過Nuget安裝程序集:【Serilog 2.10】【Serilog.Sinks.File 4.1.0】【Serilog.Sinks.Async 1.4.0】

(2). 通過Filter設置日志級別,其它類似

(3). 通過各種方法進行調用

代碼分享:

            {
                string LogFilePath(string LogEvent) => $@"ALL_Logs\{LogEvent}\log.log";
                string SerilogOutputTemplate = "{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message:{Message}{NewLine}{Exception}" + new string('-', 100);
                //同步寫法
                //Log.Logger = new LoggerConfiguration()
                //            .Enrich.FromLogContext()
                //            .MinimumLevel.Debug() // 所有Sink的最小記錄級別
                //            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Debug).WriteTo.File(LogFilePath("Debug"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate))
                //            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Information).WriteTo.File(LogFilePath("Information"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate))
                //            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Warning).WriteTo.File(LogFilePath("Warning"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate))
                //            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Error).WriteTo.File(LogFilePath("Error"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate))
                //            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Fatal).WriteTo.File(LogFilePath("Fatal"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate))
                //            .CreateLogger();
                //異步寫法
                Log.Logger = new LoggerConfiguration()
                            .Enrich.FromLogContext()
                            .MinimumLevel.Debug() // 所有Sink的最小記錄級別
                            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Debug).WriteTo.Async(a => a.File(LogFilePath("Debug"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)))
                            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Information).WriteTo.Async(a => a.File(LogFilePath("Information"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)))
                            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Warning).WriteTo.Async(a => a.File(LogFilePath("Warning"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)))
                            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Error).WriteTo.Async(a => a.File(LogFilePath("Error"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)))
                            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Fatal).WriteTo.Async(a => a.File(LogFilePath("Fatal"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)))
                            .CreateLogger();

                Log.Debug("111111111");
                Log.Information("22222222222");
                Log.Warning("33333333333");
                Log.Error("44444444444");
                Log.Fatal("5555555555555");
                try
                {
                    int.Parse("sfsdfsf");
                }
                catch (Exception ex)
                {
                    Log.Error(ex, ex.Message);
                }
                Log.CloseAndFlush();
            }
View Code

6. 自定義輸出到指定文件夾(推薦)

 思路:這里采用過濾器的來實現,需要在日志內容中定義一個屬性,比如下面的{position},然后通過ByIncludingOnly(Matching.WithProperty<string>("position", p => p == "WebLog"))來篩選,然后再指定存放到那個文件夾下。

注:如果加上$符號,還要定義過濾器屬性,則需要用{{}}

代碼分享:

{
                static string LogFilePath(string FileName) => $@"ALL_Logs\{FileName}\log.log";
                string SerilogOutputTemplate = "{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message:{Message}{NewLine}{Exception}" + new string('-', 100);
                Log.Logger = new LoggerConfiguration()
                            .Enrich.FromLogContext()
                            .MinimumLevel.Debug() // 所有Sink的最小記錄級別
                            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(Matching.WithProperty<string>("position", p => p == "WebLog")).WriteTo.Async(a => a.File(LogFilePath("WebLog"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)))
                            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(Matching.WithProperty<string>("position", p => p == "ApiLog")).WriteTo.Async(a => a.File(LogFilePath("ApiLog"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)))
                            .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(Matching.WithProperty<string>("position", p => p == "ErrorLog")).WriteTo.Async(a => a.File(LogFilePath("ErrorLog"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)))
                            .CreateLogger();
                Log.Information("{position}:111111", "WebLog");
                Log.Information("{position}:222222", "ApiLog");
                Log.Information($"{position}:333333", "ErrorLog");
                try
                {
                    int.Parse("sfsdfsf");
                }
                catch (Exception ex)
                {
                    Log.Error(ex, "{position}:" + ex.Message, "ErrorLog");

                }
                Log.CloseAndFlush();
}

7. 輸入SQLServer(未完成)

 可參考:https://www.cnblogs.com/RainFate/p/12073662.html

 

三. 與Core MVC集成

前提:

 通過Nuget安裝程序集:【Serilog.AspNetCore 3.4.0】,該程序集涵蓋了多個子程序,可以自己封裝,你可以和控制台那樣自行選擇需要的程序集進行使用。

1. 寫法1

 類似控制台的形式,直接調用即可,可以自行封裝一下, 然后在ConfigureService中實例化, 使用的時候直接通過log對象調用即可。這里封裝LogUtils幫助類,可以分文件夾存儲,包括普通信息的記錄和Error錯誤,其它可自行封裝。

PS:這種寫法和上述控制台的類似,根據需要引入需要的程序集即可。

日志幫助類封裝代碼:

   /// <summary>
    /// 日志幫助類
    /// </summary>
    public class LogUtils
    {
        static string log1Name = "WebLog";
        static string log2Name = "ApiLog";
        static string log3Name = "ErrorLog";

        /// <summary>
        /// 初始化日志
        /// </summary>
        public static void InitLog()
        {
            static string LogFilePath(string FileName) => $@"{AppContext.BaseDirectory}ALL_Logs\{FileName}\log.log";
            string SerilogOutputTemplate = "{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message:{Message}{NewLine}{Exception}" + new string('-', 100);
            Log.Logger = new LoggerConfiguration()
                        .Enrich.FromLogContext()
                        .MinimumLevel.Debug() // 所有Sink的最小記錄級別
                        .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(Matching.WithProperty<string>("position", p => p == log1Name)).WriteTo.Async(a => a.File(LogFilePath(log1Name), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)))
                        .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(Matching.WithProperty<string>("position", p => p == log2Name)).WriteTo.Async(a => a.File(LogFilePath(log2Name), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)))
                        .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(Matching.WithProperty<string>("position", p => p == log3Name)).WriteTo.Async(a => a.File(LogFilePath(log3Name), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)))
                        .CreateLogger();
        }


        /*****************************下面是不同日志級別*********************************************/
        // FATAL(致命錯誤) > ERROR(一般錯誤) > Warning(警告) > Information(一般信息) > DEBUG(調試信息)>Verbose(詳細模式,即全部)



        /// <summary>
        /// 普通日志
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="fileName"></param>
        public static void Info(string msg, string fileName="")
        {
            if (fileName==""|| fileName == log1Name)
            {
                Log.Information($"{{position}}:{msg}", log1Name);
            }
            else if (fileName == log2Name)
            {
                Log.Information($"{{position}}:{msg}", log2Name);
            }
            else
            {
                //輸入其他的話,還是存放到第一個文件夾
                Log.Information($"{{position}}:{msg}", log1Name);
            }
        }

        /// <summary>
        /// Error方法統一存放到ErrorLog文件夾
        /// </summary>
        /// <param name="msg"></param>
        public static void Error(Exception ex)
        {
            Log.Error(ex, "{position}:" + ex.Message, log3Name);
        }


    }
View Code

ConfigureService注冊:

 public void ConfigureServices(IServiceCollection services)
 {
      //日志初始化
      LogUtils.InitLog();

      services.AddControllersWithViews();
 }

調用代碼:

 public IActionResult Index()
 {
      LogUtils.Info("111111111", "WebLog");
      LogUtils.Info("222222222", "ApiLog");

       try
       {
             int.Parse("sfsdfafd");
        }
        catch (Exception ex)
        {
                LogUtils.Error(ex);
         }
         return View();
}

2. 寫法2

(1). 在Program中通過UseSerilog進行初始化日志,和上述基本類似,特別注意,這里要重寫一下系統自帶的日志捕捉,可以寫為MinimumLevel.Override("Microsoft", LogEventLevel.Fatal) 否則,生成的日志文件中會生成很多我們不需要的日志信息。

(2). 在控制器中注入ILogger對象,使用即可。

注:這里實際上覆蓋系統自帶的日志。

program代碼分享: 

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();

                    //初始化日志
                    webBuilder.UseSerilog((hostingContext, loggerConfiguration) =>
                    {
                        string SerilogOutputTemplate = "{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:" +
                                                       "{Level}{NewLine}Message:{Message}{NewLine}{Exception}" + new string('-', 100);
                        loggerConfiguration
                        .MinimumLevel.Debug()
                        .MinimumLevel.Override("Microsoft", LogEventLevel.Fatal)
                        .Enrich.FromLogContext()
                       .WriteTo.File($"{AppContext.BaseDirectory}MyLogs\\log.log", rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate);
                    });

                });

調用代碼分享:

public class Home2Controller : Controller
    {
        private readonly ILogger<Home2Controller> _logger;
        public Home2Controller(ILogger<Home2Controller> logger)
        {
            _logger = logger;
        }

        public string Index()
        {

            for (int i = 0; i < 50; i++)
            {
                Task.Run(() =>
                {
                    _logger.LogInformation($"測試日志信息:{Guid.NewGuid().ToString("N")}");

                });
            }
            return "ok";
        }
    }

 

 

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM