[2core]Log和Log4net的配置使用
一、準備
儘管在asp.net core中幾乎把所有能DI化的技術、知識和概念都依賴注入,不過本人還是想不讓自己的專案那麼DI化,完全沒有必要“為了DI而DI”。這篇文章記錄日誌在asp.net core中的使用,以應用實戰為主,不講那麼多大道理。
在asp.net core中框架提供了四種日誌輸出方式,即Console日誌、Debug日誌、EventSource日誌和EventLog日誌。前兩種比較容易理解,EventSource提供程式寫入名稱為 Microsoft-Extensions-Logging 的跨平臺事件源,EventLog提供程式將日誌輸出傳送到 Windows 事件日誌。本文主要分析記錄Console日誌、Debug日誌和Log4net日誌的使用(前兩種無法輸出到檔案)。
日誌型別
Trace=0,Debug=1,Information=2,Warning=3,Error=4,Critical=5,None=6
日誌等級
None > Critical > Error > Warning > Information > Debug > Trace
二、實戰
1.Console日誌和Debug日誌
1.1.準備
a)開啟VS2022,建立Asp.net core WebApi專案
b)刪除簡化Program類程式碼,如下:
var builder = WebApplication.CreateBuilder(args);// Add services to the container. builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); app.Run();
1.2.依賴注入模式
1.2.1.Console日誌
a)通過nuget工具安裝依賴包。
1.Microsoft.Extensions.Logging:基礎包
2.Microsoft.Extensions.Logging.Console:輸出日誌到控制檯程式包
b)在Program檔案中,配置日誌。
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); builder.Services.AddLogging(logBuilder => { logBuilder.AddConsole(); }); var app = builder.Build(); app.MapControllers(); app.Run();
c)修改測試檔案WeatherForecastController的方法Get。
public IEnumerable<WeatherForecast> Get() { _logger.LogTrace("LogTrace"); _logger.LogDebug("LogDebug"); _logger.LogInformation("LogInformation"); _logger.LogWarning("LogWarning"); _logger.LogError("LogError"); _logger.LogCritical("LogCritical"); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); }
d)通過VS執行除錯程式,檢視輸出結果。
LogInformation
LogWarning
LogError
LogCritical
不出意外會輸出上述四行結果,Why?請用1.4小節中配置檔案,替換掉預設的配置資訊就好。
1.2.2.Debug日誌
a)通過nuget工具安裝依賴包。
Microsoft.Extensions.Logging.Debug:輸出日誌到Debug程式包
b)在Program檔案中,配置日誌。
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); builder.Services.AddLogging(logBuilder => { logBuilder.AddConsole(); logBuilder.AddDebug(); }); var app = builder.Build(); app.MapControllers(); app.Run();
d)通過VS執行除錯程式,此時就可以在VS的“輸出”視窗中,看到日誌的輸出資訊了。
1.2.3.小節
通過上述操作,你已經能夠以依賴注入的方式使用框架內建的日誌。如果你從.net framework升級到.net core的程式設計師,以及你理解DI/IOC的原理,不難看出所謂的依賴注入就是魔法糖。
1.3.工廠模式
在asp.net core中,不僅可以通過AddLogging()方法實現日誌的配置和啟用,還可以通過日誌工廠進行操作。
使用日誌工廠方式,appsettings.json配置檔案中的日誌配置資料就無效了,而以編寫程式碼的方式設定日誌輸出等級就生效了。
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); var loggerFactory = LoggerFactory.Create(logBuilder => { logBuilder.ClearProviders(); logBuilder.AddConsole(); logBuilder.AddDebug(); logBuilder.SetMinimumLevel(LogLevel.Trace); }); ILogger _logger = loggerFactory.CreateLogger<Program>(); _logger.LogTrace("LogTrace"); _logger.LogDebug("LogDebug"); _logger.LogInformation("LogInformation"); _logger.LogWarning("LogWarning"); _logger.LogError("LogError"); _logger.LogCritical("LogCritical"); var app = builder.Build(); app.MapControllers(); app.Run();
1.4.配置檔案
特別提示,asp.net core專案中,配置檔案的日誌配置資料的優先順序要高於程式中編寫程式碼,僅限於依賴注入模式。
{ "Logging": { "Console": { "LogLevel": { "Default": "Trace", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "Debug": { "LogLevel": { "Default": "Trace", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "EventSource": { "LogLevel": { "Microsoft": "Warning" } }, "EventLog": { "LogLevel": { "Microsoft": "Warning" } }, "LogLevel": { "Default": "Trace", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" }
1.5.總結
通過上述兩種方式,實現了日誌輸出到Console和Debug,但是框架並沒有提供輸出到硬碟檔案的程式包,所以需要藉助第三方的程式包實現將日誌輸出到檔案的需求。
2.Log4net日誌
不能把日誌輸出到檔案中或寫入到日誌系統裡,是無法保證系統安全穩定執行以及快速定位查詢問題的,所以一定要實現在程式部署執行中,將日誌輸出到硬碟檔案或專門的日誌系統裡的需求,所以此處用到了Log4net程式包。
2.1.依賴注入和工廠模式
在asp.net core中,使用log4net還是比較容易的,主要分為兩步:第一安裝程式包,第二設定配置檔案,第三通過程式碼啟用,如下:
2.1.1.安裝程式包
1.log4net:基礎包
2.Microsoft.Extensions.Logging.Log4Net.AspNetCore:適配AspNetCore程式的軟體包
2.1.1.配置檔案
1.特別說明:a)配置檔案中<configuration>節點需要去掉;b)配置檔案中包含了兩種配置,一種適用於AspNetCore,一種是傳統.net framework模式。
2.配置檔案內容:注意配置檔案要輸出到根目錄,因為程式包預設就是從根目錄查詢載入。
<?xml version="1.0" encoding="utf-8" ?> <log4net> <!--DIOC日誌附加介質--> <!--根配置--> <root> <!--日誌級別: NONE > FATAL > ERROR > WARN > INFO > DEBUG > ALL --> <priority value="ALL"/> <level value="ALL"/> <appender-ref ref="DiocAppender" /> </root> <!-- name屬性指定其名稱,type則是log4net.Appender名稱空間的一個類的名稱,意思是,指定使用哪種介質--> <appender name="DiocAppender" type="log4net.Appender.RollingFileAppender"> <!--日誌輸出到exe程式這個相對目錄下--> <param name="File" value="logs\\diocs\\" /> <!--輸出的日誌不會覆蓋以前的資訊--> <param name="AppendToFile" value="true" /> <!--備份檔案的個數--> <param name="MaxSizeRollBackups" value="50" /> <!--最小鎖定模型以允許多個程序可以寫入同一個檔案--> <param name="MaxFileSize" value="10240" /> <!--當前日誌檔案的最大大小--> <param name="lockingModel" type="log4net.Appender.FileAppender+MinimalLock" /> <!--是否使用靜態檔名--> <param name="StaticLogFileName" value="false" /> <!--日誌檔名--> <param name="DatePattern" value="yyyyMMdd".txt"" /> <!--檔案建立的方式,這裡是以Date方式建立--> <param name="RollingStyle" value="Date" /> <!--輸出級別在INFO和ERROR之間的日誌--> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="ALL" /> <param name="LevelMax" value="FATAL" /> </filter> <!--資訊日誌佈局--> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/> </layout> </appender> <!--錯誤日誌類--> <logger name="logerror"> <!--日誌類的名字--> <level value="ALL" /> <!--定義記錄的日誌級別--> <appender-ref ref="ErrorAppender" /> </logger> <!--資訊日誌類--> <logger name="loginfo"> <!--日誌類的名字--> <level value="ALL" /> <!--定義記錄的日誌級別--> <appender-ref ref="InfoAppender" /> </logger> <!--錯誤日誌附加介質--> <!-- name屬性指定其名稱,type則是log4net.Appender名稱空間的一個類的名稱,意思是,指定使用哪種介質--> <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender"> <!--日誌輸出到exe程式這個相對目錄下--> <param name="File" value="logs\\errors\\" /> <!--輸出的日誌不會覆蓋以前的資訊--> <param name="AppendToFile" value="true" /> <!--備份檔案的個數--> <param name="MaxSizeRollBackups" value="50"/> <!--最小鎖定模型以允許多個程序可以寫入同一個檔案--> <param name="MaxFileSize" value="10240" /> <!--當前日誌檔案的最大大小--> <param name="lockingModel" type="log4net.Appender.FileAppender+MinimalLock" /> <!--是否使用靜態檔名--> <param name="StaticLogFileName" value="false" /> <!--日誌檔名--> <param name="DatePattern" value="yyyyMMdd".txt"" /> <!--檔案建立的方式,這裡是以Date方式建立--> <param name="RollingStyle" value="Date" /> <!--錯誤日誌佈局--> <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="[%t]異常類:%c [%x] 異常資訊:%m%n" /> </layout> </appender> <!--資訊日誌附加介質--> <!-- name屬性指定其名稱,type則是log4net.Appender名稱空間的一個類的名稱,意思是,指定使用哪種介質--> <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender"> <!--日誌輸出到exe程式這個相對目錄下--> <param name="File" value="logs\\infos\\" /> <!--輸出的日誌不會覆蓋以前的資訊--> <param name="AppendToFile" value="true" /> <!--備份檔案的個數--> <param name="MaxSizeRollBackups" value="50" /> <!--最小鎖定模型以允許多個程序可以寫入同一個檔案--> <param name="MaxFileSize" value="10240" /> <!--當前日誌檔案的最大大小--> <param name="lockingModel" type="log4net.Appender.FileAppender+MinimalLock" /> <!--是否使用靜態檔名--> <param name="StaticLogFileName" value="false" /> <!--日誌檔名--> <param name="DatePattern" value="yyyyMMdd".txt"" /> <!--檔案建立的方式,這裡是以Date方式建立--> <param name="RollingStyle" value="Date" /> <!--資訊日誌佈局--> <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="%m%n" /> </layout> </appender> </log4net>
2.1.2.程式程式碼
a)依賴注入模式
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); builder.Services.AddLogging(logBuilder => { logBuilder.AddConsole(); logBuilder.AddDebug(); logBuilder.AddLog4Net(); }); var app = builder.Build(); app.MapControllers(); app.Run();
b)工廠模式
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); var loggerFactory = LoggerFactory.Create(logBuilder => { logBuilder.ClearProviders(); logBuilder.AddConsole(); logBuilder.AddDebug(); logBuilder.AddLog4Net(); logBuilder.SetMinimumLevel(LogLevel.Trace); }); ILogger _logger = loggerFactory.CreateLogger<Program>(); _logger.LogTrace("LogTrace"); _logger.LogDebug("LogDebug"); _logger.LogInformation("LogInformation"); _logger.LogWarning("LogWarning"); _logger.LogError("LogError"); _logger.LogCritical("LogCritical"); var app = builder.Build(); app.MapControllers(); app.Run();
2.2.傳統模式
說實話,俺是一個比較純粹的人,不太喜歡黑魔法,所以使用傳統方式記錄日誌,我更加喜歡。傳統方式記錄日誌的過程沒有改變,簡單記錄一下使用過程:
a)設定配置檔案,操作如上,此處不再贅述。
b)建立Log4Writer類
public class Log4Writer { private static readonly log4net.ILog loginfo = log4net.LogManager.GetLogger("loginfo"); private static readonly log4net.ILog logerror = log4net.LogManager.GetLogger("logerror"); public static void WriteLog(string info) { if (loginfo.IsInfoEnabled) { loginfo.Info(info); } } public static void WriteLog(string info, Exception ex) { if (logerror.IsErrorEnabled) { logerror.Error(info, ex); } } }
c)建立Log4Helper類
public class LogHelper { private static object _objLocker = new object(); private static bool _isConfigure = false; public static void Configure() { if (!_isConfigure) { lock (_objLocker) { if (!_isConfigure) { _isConfigure = true; log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo("log4net.config")); } } } } }
d)在Program中啟用log4net
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); jks.core.test.log.LogHelper.Configure(); app.Run();
e)使用測試
public IEnumerable<WeatherForecast> Get() { Log4Writer.WriteLog("aaaaaaaaaaaaaaaaaaaaaaa"); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); }
2.3.特別說明
很多同學可能會問,為什麼使用log4net,而不是其他第三方日誌程式包?
第一,因為.net framework時就在用;第二,就是因為它比較獨立;第三,我不僅僅需要將日誌寫入到硬碟檔案裡,還需要寫入到專門的日誌系統,且日誌內容設計了固定的結構。
簡單的說,使用日誌工具記錄日誌到硬碟檔案是次要的,記錄到專門的日誌系統才是主要的、核心的。
三、總結
通過上述內容的分析、實驗和記錄,應該能夠在使用asp.net core中使用日誌了吧?以及如何從.net framework升級到.net core。
好了,就此結束。
程式原始碼:https://gitee.com/kinbor/jks.core.test.log