日誌服務
日誌服務可以分為2種,一種是NetCore內建的日誌ILogger
,一種是第三方日誌服務元件,如Log4Net
需要掌握:
內建日誌元件
注意:
- NetCore不提供將日誌寫入檔案的程式,如果要記錄日誌檔案,請用第三方
- 日誌記錄應該會很快,不值得犧牲效能來使用非同步程式碼。 如果日誌記錄資料儲存很慢,請不要直接寫入它。 考慮先將日誌訊息寫入快速儲存,然後再將其移至慢速儲存。
分析:
使用最小託管模型建立應用,在Program.cs檔案
中WebApplication.CreateBuilder()
方法會新增以下日誌服務。
即WebApplication物件中的Logging屬性
新增的一組預設的日誌記錄提供程式
var builder = WebApplication.CreateBuilder(args);
// 提供程式將輸出記錄到控制檯
builder.Logging.AddConsole();
// 提供程式使用 System.Diagnostics.Debug 類寫入日誌輸出
builder.Logging.AddDebug();
// EventLog 提供程式將日誌輸出傳送到 Windows 事件日誌。
builder.Logging.AddEventLog();
// 提供程式寫入名稱為Microsoft-Extensions-Logging 的跨平臺事件源 在Windows上,提供程式使用的是 ETW
builder.Logging.AddEventSourceLogger();
同樣會在appsettings.{ENVIRONMENT}.json
檔案的 Logging
部分提供檔案生成一個日誌相關的配置節點(不是6.0也會建立的)
{
"Logging": {
"LogLevel": {
// 低於Information級別的日誌不會被輸出
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
-
預設等級:如果需要更改輸出的級別日誌下限等級,可以修改
appsettings.json
配置檔案的 "Default"節點,比如修改為"Default"節點的內容為“Debug”,這意味著低於Debug等級的日誌不會被記錄 -
單個類設定等級:如果需要指定具體的類輸出預設輸出的下限的等級,可以增加以下節點
"LogLevel": { "完整名稱空間.類名": "Warning" }
日誌等級
net內部元件日誌一共分為7個等級,從低到高,可以從列舉LogLevel中看出來:
public enum LogLevel
{
// 跟蹤日誌:包含最詳細訊息的日誌,不應該在生產環境啟用
Trace = 0,
// 除錯日誌:在開發過程中用於互動式調查的日誌
Debug = 1,
// 資訊日誌:跟蹤應用程式常規流的日誌
Information = 2,
// 警告日誌:指的應用程式流中異常或意外事件的日誌,但是不會導致應用程式停止
Warning = 3,
// 報錯日誌:指的在應用程式執行失敗而停止的日誌
Error = 4,
// 緊急日誌:描述不可恢復的應用程式或系統崩潰或災難性事件的日誌
Critical = 5,
// 不寫入日誌:不用於寫入日誌訊息
None = 6
}
如何建立日誌-netcore內部元件
微軟:在6.0開始,日誌服務不再使用ILogger型別。而是使用ILogger
或將 ILogger 註冊為依賴注入
ILoggingBuilder介面
首先,我們來了解一下ILoggingBuilder
這個東西,微軟官方說是用於配置日誌記錄提供程式的介面,但是實際上,這個介面只提供了一個獲取從DI容器中配置的日誌服務的方法,我們更多的是使用他的擴充方法AddConfiguration()
來配置我們自己的日誌服務。
demo
// 用於配置日誌記錄提供程式的介面。
public interface ILoggingBuilder
{
// 獲取從DI容器中配置的日誌服務
IServiceCollection Services { get; }
}
// ILoggingBuilder的擴充類
public static class LoggingBuilderExtensions
{
// 擴充我們自己的日誌服務
public static ILoggingBuilder AddConfiguration(this ILoggingBuilder builder, IConfiguration configuration)
{
// 注入關於日誌等級過濾的服務,預設是拿appsetting.json裡面“Logging”節點的 "LogLevel"設定
builder.Services.AddSingleton<IConfigureOptions<LoggerFilterOptions>>(new LoggerFilterConfigureOptions(configuration));
builder.Services.AddSingleton<IOptionsChangeTokenSource<LoggerFilterOptions>>(
new ConfigurationChangeTokenSource<LoggerFilterOptions>(configuration)
);
return builder;
}
}
使用ILoggerFactory工廠建立日誌
一般在應用程式中,我們建立日誌需要一個ILogger物件,而ILogger物件是由LoggerFactory工廠提供的,所以我們首先得需要一個ILoggerFactory工廠
日誌過濾
整合Log4net元件
由於netcore的日誌元件,不能提供寫入檔案的服務,所以我們整合Log4net元件來為我們提供服務
安裝和配置服務
-
安裝Nuget包:log4net和對應的apsnet.core包
-
在
Program.cs檔案
中,注入服務,啟用自定義配置檔案builder.Logging.AddLog4Net("xxxx.config");
-
編寫配置檔案
log4net.config
,如果不使用自定義配置檔案,則可以寫在web.config
中
日誌等級
7個等級由低到高:
- ALL:所有
- DEBUG:除錯
- INFO:資訊
- WARN:警告
- ERROR:報錯
- FATAL:重大事故
- OFF :不輸出
編寫log4net.config
編寫配置檔案的原因是需要設定日誌的一些基本引數,檔案格式為xml。
注意:
- appenders、logger、root這幾個節點需要小寫!!!否則讀取不到
以下有些配置資訊不太全面,具體百度官網檢視,我這裡只寫了我們比較常用的幾個
log4net有3個節點
Appenders節點:
作用:
定義日誌的輸出方式,可以存在多個,可以理解為日誌的輸出模板。
必須屬性:
type:Appender物件的輸出型別,設定為log4net.Appender.RollingFileAppender則是 日誌以回滾檔案的形式寫到檔案中,AdoNetAppender則是寫入資料庫,有許多種選擇,請自行百度。
name:Appender物件的名稱,這個地方設定的值會在root標籤用到
子節點:必須屬性value,如果還有子節點param或者其他的時候則為type
<!--過濾器 輸出級別在INFO和ERROR之間的日誌 -->
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="ALL" />
<param name="LevelMax" value="FATAL" />
</filter>
這裡的%class的資料來源是,當我們呼叫LogManager.GetLogger(typeof(型別)),會傳入一個類的type,這就是他的資料來源,當前日誌物件的名稱。
格式引數,可以簡寫可以完整寫:
%m(message):資料來源是,當我們得到的ILog物件,呼叫如Error或者Debug之類的方法,傳入的message就是這個資料來源。
%d(datetime){yyy-MM-dd HH:mm:ss }:當前時間,{}裡面是格式化內容
%r(runtime):執行時間
%p(priority):日誌的等級
%c(class):類名
%t(thread):執行緒id
%l(line):行號
%f(file):檔名稱
有一些會自動填充,有一些則來自於我們呼叫的方法的引數。
<!--佈局器 就是輸出的錯誤文案是由什麼組成的 這裡用的是自定義型別-->
<layout type="log4net.Layout.PatternLayout">
<!--佈局器 輸出在什麼時間 那個類 哪個行 呼叫的哪個方法 輸出詳細報錯資訊-->
<conversionPattern value="%d{yyy-MM-dd HH:mm:ss } :%c %n %m %n"/>
</layout>
logger節點:
作用:
預設繼承root節點,設定的目的是來單獨處理一種日誌,可以多個,比如定義一個錯誤日誌的appender和一個錯誤日誌的logger,然後請求日誌一樣配套appender和logger,這樣做可以方便我們定義輸出不同的日誌型別,如果不定義,預設採用root節點。
怎麼使用?:
在使用LogManager.GetLogger("logger節點設定的name屬性的值")
,可以獲取logger物件
必須屬性:
name:用於設定logger的名稱,這個名稱在使用LogManager.GetLogger("name屬性值")
,可以獲取logger物件。
additivity:用於設定是否繼承root節點。如果同時設定了root和logger,則logger裡面的appender會寫一份,root裡面的appender也會寫一份,設定為false可以避免出現這種情況
<logger name = "testLog">
<!--預設輸出的等級,低於此等級的不會被輸出-->
<level value="ALL"/>
<!--引用我們自定義的appender-->
<appender-ref ref="rollingAppender" />
</logger>
root節點:
作用:
只能有一個,是所有logger物件的父節點,必須設定,當我們在方法中,呼叫LogManager.GetLogger()
不使用logger節點的name屬性獲取logger的時候,預設就是拿的這個裡面的輸出配置。
<root>
<priority value="ALL"/>
<!--控制級別,由低到高:ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF
比如定義級別為INFO,則INFO級別向下的級別,比如DEBUG日誌將不會被記錄-->
<level value="ALL"/>
<appender-ref ref="rollingAppender" />
</root>
使用log4net記錄日誌
在我們在Program.cs
注入服務後,編寫完配置檔案就可以開始使用了,
所有的日誌物件都是由 LogManager類
來獲取管理的,該類有一個GetLogger()
靜態的方法,透過這個方法來獲取logger物件,這個方法有好幾個過載
如果框架裡不存在該Logger物件,它也會為我們建立一個Logger物件,預設的輸出方式採用root節點裡面的appender。
使用方法
LogManager.GetLogger("log4net.config配置檔案中logger節點的name屬性值")
LogManager.GetLogger(typeof(型別))
得到logger物件後我們就可以用來輸出了,比如debug、Info、Warn、Error、FatalFormat在不同的情況下使用不同的方法
log.Error(Exception ex);
log.Error(object message);
完整demo
/// <summary>
/// log4net 日誌工具類
/// </summary>
public class LogHelper
{
private static readonly ILog log = LogManager.GetLogger("ErrorLog");
public static void Error(Exception ex)
{
log.Error(ex);
}
}
注意:我這裡的ErrorLog的logger物件屬性additivity沒有設定為false,所以會寫2次日誌記錄,一份到報錯日誌,一份預設請求日誌。
<?xml version="1.0" encoding="utf-8"?>
<log4net>
<!--debug日誌輸出模板-->
<appender name="ErrorLogByRollingAppender" type="log4net.Appender.RollingFileAppender">
<file value="OtherFiles/ErrorLog/" />
<datePattern value="yyyy-MM-dd-'.txt'"/>
<rollingStyle value="Composite" />
<encoding value="utf-8" />
<maxSizeRollBackups value="20" />
<maximumFileSize value="5MB" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<staticLogFileName value="false" />
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="ALL" />
<param name="LevelMax" value="FATAL" />
</filter>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="報錯日誌:%n 時間:%d{yyy-MM-dd HH:mm:ss } %n 類名:%c %n 報錯資訊:%m %n "/>
</layout>
</appender>
<!--debug日誌物件-->
<logger name ="ErrorLog">
<level value="Error"/>
<appender-ref ref="ErrorLogByRollingAppender" />
</logger>
<!--預設請求日誌輸出模板-->
<appender name ="DefaultLogByRollingAppender" type="log4net.Appender.RollingFileAppender">
<!--配置生成的日誌檔案放在哪裡-->
<file value="OtherFiles/DefaultLog/" />
<datePattern value="yyyy-MM-dd-'.txt'"/>
<rollingStyle value="Composite" />
<encoding value="utf-8" />
<maxSizeRollBackups value="20" />
<maximumFileSize value="5MB" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<staticLogFileName value="false" />
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="ALL" />
<param name="LevelMax" value="DEBUG" />
</filter>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value=" 預設請求日誌:%n 時間:%d{yyy-MM-dd HH:mm:ss } %n 執行時間:%r %n "/>
</layout>
</appender>
<!--父節點-->
<root>
<level value="ALL"/>
<appender-ref ref="DefaultLogByRollingAppender" />
</root>
</log4net>