日誌服務

Ghetto_richh發表於2024-03-13

日誌服務

日誌服務可以分為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元件來為我們提供服務

安裝和配置服務

  1. 安裝Nuget包:log4net和對應的apsnet.core包

  2. Program.cs檔案中,注入服務,啟用自定義配置檔案

    builder.Logging.AddLog4Net("xxxx.config");
    
  3. 編寫配置檔案log4net.config,如果不使用自定義配置檔案,則可以寫在web.config

日誌等級

7個等級由低到高:

  1. ALL:所有
  2. DEBUG:除錯
  3. INFO:資訊
  4. WARN:警告
  5. ERROR:報錯
  6. FATAL:重大事故
  7. OFF :不輸出

編寫log4net.config

編寫配置檔案的原因是需要設定日誌的一些基本引數,檔案格式為xml。

注意:

  1. appenders、logger、root這幾個節點需要小寫!!!否則讀取不到

以下有些配置資訊不太全面,具體百度官網檢視,我這裡只寫了我們比較常用的幾個

log4net有3個節點

Appenders節點:

作用:

定義日誌的輸出方式,可以存在多個,可以理解為日誌的輸出模板。

必須屬性:

type:Appender物件的輸出型別,設定為log4net.Appender.RollingFileAppender則是 日誌以回滾檔案的形式寫到檔案中,AdoNetAppender則是寫入資料庫,有許多種選擇,請自行百度。

name:Appender物件的名稱,這個地方設定的值會在root標籤用到

子節點:必須屬性value,如果還有子節點param或者其他的時候則為type

:生成的日誌檔案存放在哪裡。value用於設定檔案路徑;資料夾不存在則會新建

:檔案命名規則。value用於設定規則,如yyyy-MM-dd-.'txt',將會以時間為命名格式輸出,檔案型別需要加上英文單引號包裹起來;

:檔名稱是否為靜態,當設定了命名規則的時候,value要設定為false,如果設定為true,那麼log的檔名稱永遠為file節點裡面的名稱

:按照什麼方式生成日誌檔案。value有3個選擇Size、Date、Composite(Size+Date組合)

:日誌能分割最大個數,超過設定的值,會刪掉最舊的,value必須好好設定,設定為-1的時候,代表無線增加,如果rollingStyle節點的value設定為Size,則設定的數字代表只能由有N個日誌;當設定為Composite則代表只能每天最多有N個日誌

:單個日誌檔案大小,value用於設定檔案大小;只有rollingStyle節點設定為Size或者Composite的時候才使用。比如設定value = ”500KB“,檔案大小單位要大寫(KB、MB、GB),必須是正整數。

:編碼格式。value設定utf-8等格式

:是否追加到檔案末尾,value設定為true的時候,代表追加,false代表不追加

:value設定為log4net.Appender.FileAppender+MinimalLock,目的是防止多執行緒無法寫入log

:過濾器,比如輸出級別在INFO和ERROR之間的日誌,有一個屬性,type,設定為log4net.Filter.LevelRangeFilter的時候,會以日誌等級來過濾是否寫入檔案。必須下方就是最低輸出all,最高到FATAL

<!--過濾器  輸出級別在INFO和ERROR之間的日誌 -->
		<filter type="log4net.Filter.LevelRangeFilter">
			<param name="LevelMin" value="ALL" />
			<param name="LevelMax" value="FATAL" />
		</filter>

:佈局器,意思是每條記錄的文案,type一般設定為log4net.Layout.PatternLayout,代表自定義型別

節點的作用在於規範輸出行為,value設定輸出格式

這裡的%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>

相關文章