Asp.Net Core中簡單使用日誌組件log4net

本文將簡單介紹在.NET 6中使用log4net的方法,具體見下文範例。

1.首先新建一個ASP.NET Core空項目

 2.通過Nuget包管理器安裝下面兩個包

log4net
Microsoft.Extensions.Logging.Log4Net.AspNetCore

 

 3.在項目根目錄下新建log4net的配置文件log4net.config,並將其設置為始終複製

 

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
	<!--根配置-->
	<root>
		<!--日誌級別:可選值: ERROR > WARN > INFO > DEBUG -->
		<level value="ERROR"/>
		<level value="WARN"/>
		<level value="INFO"/>
		<level value="DEBUG"/>
		<appender-ref ref="ErrorLog" />
		<appender-ref ref="WarnLog" />
		<appender-ref ref="InfoLog" />
		<appender-ref ref="DebugLog" />
	</root>
	<!-- 錯誤 Error.log-->
	<appender name="ErrorLog" type="log4net.Appender.RollingFileAppender">
		<!--目錄路徑,可以是相對路徑或絕對路徑-->
		<param name="File" value="C:\logs\"/>
		<!--文件名,按日期生成文件夾-->
		<param name="DatePattern" value="/yyyy-MM-dd/"Error.log""/>
		<!--追加到文件-->
		<appendToFile value="true"/>
		<!--創建日誌文件的方式,可選值:Date[日期],文件大小[Size],混合[Composite]-->
		<rollingStyle value="Composite"/>
		<!--寫到一個文件-->
		<staticLogFileName value="false"/>
		<!--單個文件大小。單位:KB|MB|GB-->
		<maximumFileSize value="200MB"/>
		<!--最多保留的文件數,設為"-1"則不限-->
		<maxSizeRollBackups value="-1"/>
		<!--日誌格式-->
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="[%d{HH:mm:ss}]%m%n"/>
		</layout>
		<filter type="log4net.Filter.LevelRangeFilter">
			<param name="LevelMin" value="ERROR" />
			<param name="LevelMax" value="ERROR" />
		</filter>
	</appender>

	<!-- 警告 Warn.log-->
	<appender name="WarnLog" type="log4net.Appender.RollingFileAppender">
		<!--目錄路徑,可以是相對路徑或絕對路徑-->
		<param name="File" value="C:\logs\"/>
		<!--文件名,按日期生成文件夾-->
		<param name="DatePattern" value="/yyyy-MM-dd/"Warn.log""/>
		<!--追加到文件-->
		<appendToFile value="true"/>
		<!--創建日誌文件的方式,可選值:Date[日期],文件大小[Size],混合[Composite]-->
		<rollingStyle value="Composite"/>
		<!--寫到一個文件-->
		<staticLogFileName value="false"/>
		<!--單個文件大小。單位:KB|MB|GB-->
		<maximumFileSize value="200MB"/>
		<!--最多保留的文件數,設為"-1"則不限-->
		<maxSizeRollBackups value="-1"/>
		<!--日誌格式-->
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="[%d{HH:mm:ss}]%m%n"/>
		</layout>
		<filter type="log4net.Filter.LevelRangeFilter">
			<param name="LevelMin" value="WARN" />
			<param name="LevelMax" value="WARN" />
		</filter>
	</appender>

	<!-- 信息 Info.log-->
	<appender name="InfoLog" type="log4net.Appender.RollingFileAppender">
		<!--目錄路徑,可以是相對路徑或絕對路徑-->
		<param name="File" value="C:\logs\"/>
		<!--文件名,按日期生成文件夾-->
		<param name="DatePattern" value="/yyyy-MM-dd/"Info.log""/>
		<!--追加到文件-->
		<appendToFile value="true"/>
		<!--創建日誌文件的方式,可選值:Date[日期],文件大小[Size],混合[Composite]-->
		<rollingStyle value="Composite"/>
		<!--寫到一個文件-->
		<staticLogFileName value="false"/>
		<!--單個文件大小。單位:KB|MB|GB-->
		<maximumFileSize value="200MB"/>
		<!--最多保留的文件數,設為"-1"則不限-->
		<maxSizeRollBackups value="-1"/>
		<!--日誌格式-->
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="[%d{HH:mm:ss}]%m%n"/>
		</layout>
		<filter type="log4net.Filter.LevelRangeFilter">
			<param name="LevelMin" value="INFO" />
			<param name="LevelMax" value="INFO" />
		</filter>
	</appender>

	<!-- 調試 Debug.log-->
	<appender name="DebugLog" type="log4net.Appender.RollingFileAppender">
		<!--目錄路徑,可以是相對路徑或絕對路徑-->
		<param name="File" value="C:\logs\"/>
		<!--文件名,按日期生成文件夾-->
		<param name="DatePattern" value="/yyyy-MM-dd/"Debug.log""/>
		<!--追加到文件-->
		<appendToFile value="true"/>
		<!--創建日誌文件的方式,可選值:Date[日期],文件大小[Size],混合[Composite]-->
		<rollingStyle value="Composite"/>
		<!--寫到一個文件-->
		<staticLogFileName value="false"/>
		<!--單個文件大小。單位:KB|MB|GB-->
		<maximumFileSize value="200MB"/>
		<!--最多保留的文件數,設為"-1"則不限-->
		<maxSizeRollBackups value="-1"/>
		<!--日誌格式-->
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="[%d{HH:mm:ss}]%m%n"/>
		</layout>
		<filter type="log4net.Filter.LevelRangeFilter">
			<param name="LevelMin" value="DEBUG" />
			<param name="LevelMax" value="DEBUG" />
		</filter>
	</appender>

</log4net>

  log4net配置參數此處不多贅述,只針對日誌的輸出格式參數conversionPattern配置做簡要說明。

%p(priority)::日誌的當前優先級別(DEBUG、INFO、WARN 等)
%t(thread id):當前記錄器所在的線程 ID
%d(datetime):當前記錄器運行時的時刻
%F(file):當前記錄器所在的文件名
%L(line):當前記錄器所在的行號
%m(message):需要輸出的日誌消息
%n(new line):換行
%M 方法名
%m 輸出代碼中指定的消息 
%p 輸出優先級,即DEBUG,INFO,WARN,ERROR,FATAL 
%r 輸出自應用啟動到輸出該log信息耗費的毫秒數 
%c 輸出所屬的類目,通常就是所在類的全名 
%t 輸出產生該日誌事件的線程名 
%n 輸出一個回車換行符,Windows平台為「rn」,Unix平台為「n」 
%d 輸出日誌時間點的日期或時間,默認格式為ISO8601,也可以在其後指定格式,比如:%d{yyyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 :10:28,921
%l 或 %L 輸出日誌事件的發生位置,包括類目名、發生的線程,以及在代碼中的行數。
%c 輸出日誌信息所屬的類的全名
%d 輸出日誌時間點的日期或時間,默認格式為ISO8601,也可以在其後指定格式,比如:%d{yyy-MM-dd HH:mm:ss },輸出類似:2002-10-18- 22:10:28
%f 輸出日誌信息所屬的類的類名
%l 輸出日誌事件的發生位置,即輸出日誌信息的語句處於它所在的類的第幾行
%m 輸出代碼中指定的信息,如log(message)中的message
%n 輸出一個回車換行符,Windows平台為「rn」,Unix平台為「n」
%p 輸出優先級,即DEBUG,INFO,WARN,ERROR,FATAL。如果是調用debug()輸出的,則為DEBUG,依此類推
%r 輸出自應用啟動到輸出該日誌信息所耗費的毫秒數
%t 輸出產生該日誌事件的線程名

  4.在Program中使用log4net輸出自定義日誌內容

using log4net;

var builder = WebApplication.CreateBuilder(args);
//注入Log4Net
builder.Services.AddLogging(cfg =>
{
    cfg.AddLog4Net();
    //默認的配置文件路徑是在根目錄,且文件名為log4net.config
    //如果文件路徑或名稱有變化,需要重新設置其路徑或名稱
    //比如在項目根目錄下創建一個名為cfg的文件夾,將log4net.config文件移入其中,並改名為log.config
    //則需要使用下面的代碼來進行配置
    //cfg.AddLog4Net(new Log4NetProviderOptions()
    //{
    //    Log4NetConfigFileName = "cfg/log.config",
    //    Watch = true
    //});
});
var app = builder.Build();
//訪問根頁面時
app.MapGet("/", (ILogger<Program> logger) =>
{
    logger.LogInformation("logger:測試一下Log4Net=》Info");
    return "Hello World!";
});
//訪問test頁面時
app.MapGet("/test", () =>
{
    var log = LogManager.GetLogger(typeof(Program));
    log.Info("log:這是一條普通日誌信息");
});
app.Run();

  5.將項目運行起來,即可發現日誌文件已生成

 

 

 

 

 

 6.擴展使用:使用簡單工廠模式IOC注入到自定義類中使用

  新建一個ITestLog4Net接口文件,並為其定義一個Log方法。

public interface ITestLog4Net
{
        public void Log();
}

    並且新建一個TestLog4Net的自定義類,繼承於ITestLog4Net,並實現該Log方法。

public class TestLog4Net : ITestLog4Net
{
        private readonly ILogger<TestLog4Net> _logger;
        public TestLog4Net(ILogger<TestLog4Net> logger)
        {
            _logger = logger;
            _logger.LogInformation("ctor測試一下Log4Net=》Info");
        }


        public void Log()
        {
            _logger.LogInformation("測試一下Log4Net=》Info");
        }
}

  在Program中注入我們的自定義類TestLog4Net  

builder.Services.AddTransient<ITestLog4Net, TestLog4Net>();
testLog4Net.Log();

 

  使用方法

var testLog4Net = app.Services.GetService<ITestLog4Net>()!;

  或者

var services = new ServiceCollection()!;
var provider = services.BuildServiceProvider()!;
var testLog4Net = provider.GetService<ITestLog4Net>()!;
testLog4Net.Log();

  其中,使用下面這種寫法,將會收到一個編譯警告信息。

  warning ASP0000: Calling ‘BuildServiceProvider’ from application code results in an additional copy of singleton services being created. Consider alternatives such as dependency injecting services as parameters to ‘Configure’.

 

 

   推薦使用上面的寫法,百度之後,得到的答案是:不要通過調用BuildServiceProvider(). 這個方法應該只被 Host 調用一次。重複的服務提供者可能會導致一些意想不到的錯誤。如果有哪位大佬知道具體原因,請告知一下,謝謝!

Tips:代碼中的感嘆號!表示該對象不會為空,一定要確保該對象不會為空才能這樣寫,這是C#10中的新特性。