前言
log4net 是一個(gè)廣泛使用的、功能強(qiáng)大的日志記錄庫,專為 .NET 平臺(tái)設(shè)計(jì)。
它源自 Java 社區(qū)中非常流行的日志框架 log4j,并繼承了其靈活、高效和可配置的特點(diǎn)。
log4net 允許開發(fā)者在 .net 應(yīng)用程序(包括 ASP.NET、.NET Core、.NET Framework、Windows Forms、WPF 等)中輕松地添加日志功能。
本文就來進(jìn)行簡(jiǎn)單的匯總介紹,供參考。
另外,但由于 log4net 是較老的日志框架,其生態(tài)在 .NET Core/.NET 5+ 環(huán)境中支持有限,因此使用時(shí)需注意兼容性。
其實(shí)現(xiàn)在更流行的框架有很多值得推薦,例如 Serilog、Microsoft.Extensions.Logging 等等,博主后續(xù)也將進(jìn)行簡(jiǎn)單的實(shí)踐。
一、log4net 基礎(chǔ)
log4net 的配置通常放在 log4net.config,app.config, web.config 或一個(gè)獨(dú)立的 .xml 文件中。
下面看下一個(gè)簡(jiǎn)單的配置示例:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<!-- 根日志配置 -->
<root>
<level value="DEBUG" />
<appender-ref ref="FileAppender" />
</root>
<!-- 屏蔽 Microsoft 開頭的所有日志(包括 Hosting.Lifetime) -->
<logger name="Microsoft" additivity="false">
<level value="OFF" />
</logger>
<!-- 屏蔽 System 開頭的日志(可選) -->
<logger name="System" additivity="false">
<level value="OFF" />
</logger>
<!-- 文件輸出器 -->
<appender name="FileAppender" type="log4net.Appender.RollingFileAppender">
<!-- 根據(jù)操作系統(tǒng)動(dòng)態(tài)設(shè)置日志路徑 -->
<file value="logs/logfile" />
<datePattern value="yyyy-MM-dd'.log'" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
</log4net>
1.1 配置文件關(guān)鍵節(jié)點(diǎn)有哪些?root、logger、appender、level
<root>是 Logger 層次結(jié)構(gòu)的根節(jié)點(diǎn),所有 Logger 都是它的后代。
必須配置,且只能有一個(gè)。
通常在這里設(shè)置應(yīng)用程序的默認(rèn)日志級(jí)別和主要的 Appender。例如:
<!-- 根記錄器 (Root Logger) -->
<!-- 這是所有 Logger 的父級(jí),必須存在且唯一 -->
<root>
<!-- 設(shè)置根記錄器的日志級(jí)別 -->
<level value="DEBUG" />
<!-- 引用已定義的 Appender,可以添加多個(gè) -->
<appender-ref ref="ConsoleTestAppender" />
<appender-ref ref="ConsoleAppender" />
</root>
用于為特定的命名空間或類創(chuàng)建自定義的 Logger。
name 屬性通常使用完整的類名或命名空間名(如 MyApp.Services.UserService)。
可以設(shè)置與根記錄器不同的 level,也可以引用不同的 appender-ref。
<!-- 根記錄器 (Root) -->
<root>
<level value="DEBUG" />
<!-- 根記錄器使用 ConsoleAppender -->
<appender-ref ref="ConsoleAppender" />
</root>
<!-- Logger 1: MyApp.Services 命名空間 -->
<logger name="MyApp.Services">
<level value="INFO" />
<!-- 關(guān)鍵:設(shè)置了 additivity="false" -->
<additivity value="false" />
<!-- 只使用 FileAppender -->
<appender-ref ref="FileAppender" />
</logger>
<!-- Logger 2: MyApp.Data 命名空間 -->
<logger name="MyApp.Data">
<level value="DEBUG" />
<!-- 沒有設(shè)置 additivity,默認(rèn)為 true -->
<!-- 使用自己的 Appender 和 繼承根記錄器的 Appender -->
<appender-ref ref="FileAppender" />
</logger>
additivity 屬性:
true(默認(rèn)):日志消息會(huì)輸出到當(dāng)前 Logger 的【所有 Appender 以及其所有祖先 Logger 的 Appender】。
false:日志消息只輸出到當(dāng)前 Logger 明確引用的 Appender,不會(huì)傳遞給父級(jí) Logger。這在需要隔離日志輸出時(shí)非常有用。
name:Appender 的唯一標(biāo)識(shí)符,供 Logger 引用。
type:Appender 的完全限定類型名。
內(nèi)部的 <layout> 定義了日志的輸出格式。PatternLayout 是最靈活的。
conversionPattern 格式化字符串,常用占位符:
| 占位符 | 含義 |
| %date{格式} | 時(shí)間戳,如 %date{yyyy-MM-dd HH:mm:ss,fff} |
| %thread | 線程名 |
| %level | 日志級(jí)別(DEBUG, INFO 等) |
| %logger{N} | Logger 名稱,{N} 表示只顯示最后 N 段(如 %logger{1} 只顯示類名) |
| %message | 日志消息 |
| %exception | 異常堆棧信息 |
| %newline | 換行 |
| %highlight{pattern} | 在支持的 Appender(如 ColoredConsoleAppender)中為文本添加顏色 |
如下示例,包含節(jié)點(diǎn)應(yīng)用和解釋(包含文件輸出、控制臺(tái)輸出、數(shù)據(jù)庫輸出):
<!-- ============ 定義 Appender (輸出目標(biāo)) ============ -->
<!-- Appender 1: 滾動(dòng)文件輸出器 -->
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<!-- 日志文件的路徑和名稱 -->
<file value="logs\\application.log" />
<!-- 是否追加到現(xiàn)有文件 -->
<appendToFile value="true" />
<!-- 滾動(dòng)方式: Size(按大小) 或 Date(按日期) -->
<rollingStyle value="Size" />
<!-- 最多保留的備份文件數(shù)量 -->
<maxSizeRollBackups value="5" />
<!-- 單個(gè)日志文件的最大大小 -->
<maximumFileSize value="10MB" />
<!-- 歸檔后文件名是否保持不變 -->
<staticLogFileName value="true" />
<!-- 歸檔模式 -->
<countDirection value="1" />
<!-- 布局 (Layout): 定義日志格式 -->
<layout type="log4net.Layout.PatternLayout">
<!-- 轉(zhuǎn)換模式 (Conversion Pattern) -->
<conversionPattern value="%date{yyyy-MM-dd HH:mm:ss,fff} [%thread] %-5level %logger{1} - %message%newline%exception" />
</layout>
</appender>
<!-- Appender 2: 控制臺(tái)輸出器 -->
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<!-- 使用彩色輸出 -->
<target value="Console.Out" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%highlight{%-5level} %logger{1} - %message%newline" />
</layout>
</appender>
<!-- Appender 3: 數(shù)據(jù)庫輸出器 (示例) -->
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data" />
<connectionString value="Data Source=.;Initial Catalog=MyAppLogs;Integrated Security=True;" />
<commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)" />
<parameter>
<parameterName value="@log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="@thread" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread" />
</layout>
</parameter>
<parameter>
<parameterName value="@log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="@logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="@exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
在 <root> 或 <logger> 內(nèi)部使用。
value 屬性設(shè)置具體的級(jí)別 (DEBUG, INFO, WARN, ERROR, FATAL, OFF, ALL)。
1.2 layout 中有哪些固有參數(shù)
| 參數(shù) | 含義 | 示例 | 其他要點(diǎn) |
|---|
| %m 或 %message | 日志消息(loggingEvent.MessageObject) | 用戶登錄成功 | |
| %n | 換行符(平臺(tái)相關(guān):Windows 是 \r\n,Unix 是 \n) | 換行 | |
| %t 或 %thread | 線程名 | MainThread | |
| %p 或 %level | 日志級(jí)別(Level) | INFO, ERROR | %-5level:左對(duì)齊,最小寬度 5(如 INFO ) %5level:右對(duì)齊,最小寬度 5(如 INFO) |
| %c 或 %logger | 記錄器名稱(Logger Name) | MyApp.Services.UserService | %.10logger:最多顯示 logger 的前 10 個(gè)字符 %-40[ %logger{1} ]:左對(duì)齊 40 字符,只顯示 logger 最后一級(jí) |
| %C | 調(diào)用者類名(需要 StackTrace 支持,性能較差) | UserService | |
| %M | 調(diào)用者方法名(同上,需 StackTrace) | Login | |
| %F | 調(diào)用者源文件名(需調(diào)試信息 .pdb) | UserService.cs | |
| %L | 調(diào)用者行號(hào)(需 .pdb) | 45 | |
| %l | 完整位置信息 = %F:%L | UserService.cs:45 | |
| %d 或 %date | 日期時(shí)間 | %d{yyyy-MM-dd HH:mm:ss} → 2025-10-14 23:30:00 | %d{yyyy-MM-dd HH:mm:ss.fff} %date{ISO8601} |
| %r | 從程序啟動(dòng)到記錄日志所經(jīng)過的毫秒數(shù) | 12345 | |
| %P | 當(dāng)前進(jìn)程 ID | 1234 | |
| %x 或 %ndc | NDC(Nested Diagnostic Context)棧內(nèi)容 | User123 | |
| %X{key} | MDC(Mapped Diagnostic Context)中的鍵值 | %X{userid} → 123 | |
| %exception | 異常信息(包括類型、消息、堆棧) | System.NullReferenceException: Object reference not set... | |
| %property{key} | Log4net 全局屬性或日志事件屬性 | %property{hostname}, %property{ThreadName} | |
| %newline | 換行符(同 %n) | 換行 | |
| %type | 日志事件的類型(通常是 LoggingEvent) | log4net.Core.LoggingEvent | |
| %location | 位置信息(等價(jià)于 %C.%M(%F:%L)) | UserService.Login(UserService.cs:45) | |
| 轉(zhuǎn)換符 | 注意事項(xiàng) |
|---|
| %C, %M, %F, %L, %l, %location | 需要生成 StackTrace,影響性能,建議僅在調(diào)試環(huán)境使用 |
| %X{key}, %property{key} | 可用于添加上下文信息(如用戶ID、請(qǐng)求ID) |
| %exception | 只有當(dāng) exception 不為 null 時(shí)才輸出 |
二、簡(jiǎn)單示例測(cè)試
2.1 打印出各個(gè)級(jí)別的日志信息
1)首先引用兩個(gè)依賴包:log4net 和 Microsoft.Extensions.Logging.Log4Net.AspNetCore。

2)在項(xiàng)目主目錄下添加配置文件 log4net.config:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<!-- 根日志配置 -->
<root>
<level value="DEBUG" />
<appender-ref ref="FileAppender" />
</root>
<!-- 屏蔽 Microsoft 開頭的所有日志(包括 Hosting.Lifetime) -->
<logger name="Microsoft" additivity="false">
<level value="OFF" />
</logger>
<!-- 屏蔽 System 開頭的日志(可選) -->
<logger name="System" additivity="false">
<level value="OFF" />
</logger>
<!-- 文件輸出器 -->
<appender name="FileAppender" type="log4net.Appender.RollingFileAppender">
<!-- 根據(jù)操作系統(tǒng)動(dòng)態(tài)設(shè)置日志路徑 -->
<file value="logs/logfile" />
<datePattern value="yyyy-MM-dd'.log'" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
</log4net>
3)在 Program.cs 文件中添加一行代碼builder.Logging.AddLog4Net("log4net.config");。
作用是,將 log4net 日志框架集成到 .NET 的內(nèi)置日志系統(tǒng)(Microsoft.Extensions.Logging)中,并使用指定的配置文件進(jìn)行初始化。
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddLog4Net("log4net.config"); // 此行
// Add services to the container.
builder.Services.AddControllers();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseAuthorization();
app.MapControllers();
app.Run();
4)最后,在控制器中如下配置,進(jìn)行日志記錄:
using log4net;
using Microsoft.AspNetCore.Mvc;
namespace Test.WebAPI._8._0.Log4net.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public void Get()
{
_logger.LogInformation("信息");
_logger.LogError("錯(cuò)誤");
_logger.LogWarning("警告");
_logger.LogDebug("調(diào)試");
}
}
}
5)驗(yàn)證
啟動(dòng)項(xiàng)目,并通過第三方接口測(cè)試應(yīng)用,調(diào)用 Get 接口,觸發(fā)日志記錄。
2025-10-09 21:51:04,811 [12] INFO Test.WebAPI._8._0.Log4net.Controllers.WeatherForecastController - 信息
2025-10-09 21:51:04,839 [12] ERROR Test.WebAPI._8._0.Log4net.Controllers.WeatherForecastController - 錯(cuò)誤
2025-10-09 21:51:04,841 [12] WARN Test.WebAPI._8._0.Log4net.Controllers.WeatherForecastController - 警告
2025-10-09 21:51:04,842 [12] DEBUG Test.WebAPI._8._0.Log4net.Controllers.WeatherForecastController - 調(diào)試
2.2 如何輸出 json 格式的字符串
其實(shí)實(shí)現(xiàn)起來很簡(jiǎn)單,就是創(chuàng)建自定義 PatternLayoutConverter 并注冊(cè)到 Layout。
作用就是,把需要輸出的內(nèi)容進(jìn)行格式化,轉(zhuǎn)義成字符串,避免把這個(gè)信息塞進(jìn) json 的一個(gè)字段后出現(xiàn)格式校驗(yàn)失敗。
如下一個(gè)轉(zhuǎn)換器的示例:
using log4net.Core;
using log4net.Layout;
using log4net.Layout.Pattern;
using System.Web;
namespace Test.WebAPI._8._0.Log4net.PublicClass
{
public class JsonPatternLayout : PatternLayout
{
public JsonPatternLayout()
{
// 注冊(cè)自定義轉(zhuǎn)換器名稱,在配置文件中使用這個(gè) %escapedmessage 來指代要記錄的日志內(nèi)容
this.AddConverter("escapedmessage", typeof(EscapedMessagePatternConverter));
}
}
public class EscapedMessagePatternConverter : PatternLayoutConverter
{
protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
{
string message = loggingEvent.RenderedMessage ?? string.Empty;
// 使用 JavaScriptStringEncode 進(jìn)行轉(zhuǎn)義,適合嵌入 JSON
string escapedMessage = HttpUtility.JavaScriptStringEncode(message);
writer.Write(escapedMessage);
}
}
}
然后在 log4net.config 配置文件中,把日志的輸出格式變更下:
<layout type="Test.WebAPI._8._0.Log4net.PublicClass.JsonPatternLayout">
<conversionPattern value="{"time":"%date{yyyy-MM-dd HH:mm:ss}", "level":"%level", "message":"%escapedmessage", "logger":"%logger"}%n"/>
</layout>
注意其中的自定義參數(shù)引用:%escapedmessage。
如下是輸出示例:
{"time":"2025-10-14 21:56:43", "level":"INFO", "message":"信息", "logger":"Test.WebAPI._8._0.Log4net.Controllers.WeatherForecastController"}
{"time":"2025-10-14 21:58:16", "level":"ERROR", "message":"錯(cuò)誤", "logger":"Test.WebAPI._8._0.Log4net.Controllers.WeatherForecastController"}
{"time":"2025-10-14 21:58:17", "level":"WARN", "message":"警告", "logger":"Test.WebAPI._8._0.Log4net.Controllers.WeatherForecastController"}
{"time":"2025-10-14 21:58:18", "level":"DEBUG", "message":"調(diào)試", "logger":"Test.WebAPI._8._0.Log4net.Controllers.WeatherForecastController"}
參考:https://blog.csdn.net/qq_61632126/article/details/136475013。
三、遇到的一些問題
3.1 Debug 日志沒有打印出來,其他級(jí)別正常
主要是因?yàn)轫?xiàng)目配置里的信息,默認(rèn)為 Information,此級(jí)別高于 Debug,因此需要如下修改。
// appsetting.json
{
"Logging": {
"LogLevel": {
"Default": "Information", // 注意這里,配置需改為 Debug
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
// appsettings.Development.json
{
"Logging": {
"LogLevel": {
"Default": "Information", // 注意這里,配置需改為 Debug
"Microsoft.AspNetCore": "Warning"
}
}
}