〇、前言
log4net 是一个广泛使用的、功能强大的日志记录库,专为 .NET 平台设计。
它源自 Java 社区中非常流行的日志框架 log4j,并继承了其灵活、高效和可配置的特点。
log4net 允许开发者在 .net 应用程序(包括 ASP.NET、.NET Core、.NET Framework、Windows Forms、WPF 等)中轻松地添加日志功能。
本文就来进行简单的汇总介绍,供参考。
另外,但由于 log4net 是较老的日志框架,其生态在 .NET Core/.NET 5+ 环境中支持有限,因此使用时需注意兼容性。
其实现在更流行的框架有很多值得推荐,例如 Serilog、Microsoft.Extensions.Logging 等等,博主后续也将进行简单的实践。
一、log4net 基础
log4net 的配置通常放在 log4net.config,app.config, web.config 或一个独立的 .xml 文件中。
下面看下一个简单的配置示例:
<?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">
<!-- 根据操作系统动态设置日志路径 -->
<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 配置文件关键节点有哪些?root、logger、appender、level
- <root>记录器:必要、唯一
<root>是 Logger 层次结构的根节点,所有 Logger 都是它的后代。
必须配置,且只能有一个。
通常在这里设置应用程序的默认日志级别和主要的 Appender。例如:
<!-- 根记录器 (Root Logger) -->
<!-- 这是所有 Logger 的父级,必须存在且唯一 -->
<root>
<!-- 设置根记录器的日志级别 -->
<level value="DEBUG" />
<!-- 引用已定义的 Appender,可以添加多个 -->
<appender-ref ref="ConsoleTestAppender" />
<appender-ref ref="ConsoleAppender" />
</root>
- <logger>记录器:非必要、可多个
用于为特定的命名空间或类创建自定义的 Logger。
name 属性通常使用完整的类名或命名空间名(如 MyApp.Services.UserService)。
可以设置与根记录器不同的 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" />
<!-- 关键:设置了 additivity="false" -->
<additivity value="false" />
<!-- 只使用 FileAppender -->
<appender-ref ref="FileAppender" />
</logger>
<!-- Logger 2: MyApp.Data 命名空间 -->
<logger name="MyApp.Data">
<level value="DEBUG" />
<!-- 没有设置 additivity,默认为 true -->
<!-- 使用自己的 Appender 和 继承根记录器的 Appender -->
<appender-ref ref="FileAppender" />
</logger>
additivity 属性:
true(默认):日志消息会输出到当前 Logger 的【所有 Appender 以及其所有祖先 Logger 的 Appender 】。
false:日志消息只输出到当前 Logger 明确引用的 Appender,不会传递给父级 Logger。这在需要隔离日志输出时非常有用。
- <appender>配置:必要、可多个
name:Appender 的唯一标识符,供 Logger 引用。
type:Appender 的完全限定类型名。
内部的 <layout> 定义了日志的输出格式。PatternLayout 是最灵活的。
conversionPattern 格式化字符串,常用占位符:
|---------------------|-------------------------------------------------|
| 占位符 | 含义 |
| %date{格式} | 时间戳,如 %date{yyyy-MM-dd HH:mm:ss,fff} |
| %thread | 线程名 |
| %level | 日志级别(DEBUG, INFO 等) |
| %logger{N} | Logger 名称,{N} 表示只显示最后 N 段(如 %logger{1} 只显示类名) |
| %message | 日志消息 |
| %exception | 异常堆栈信息 |
| %newline | 换行 |
| %highlight{pattern} | 在支持的 Appender(如 ColoredConsoleAppender)中为文本添加颜色 |
如下示例,包含节点应用和解释(包含文件输出、控制台输出、数据库输出):
<!-- ============ 定义 Appender (输出目标) ============ -->
<!-- Appender 1: 滚动文件输出器 -->
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<!-- 日志文件的路径和名称 -->
<file value="logs\\application.log" />
<!-- 是否追加到现有文件 -->
<appendToFile value="true" />
<!-- 滚动方式: Size(按大小) 或 Date(按日期) -->
<rollingStyle value="Size" />
<!-- 最多保留的备份文件数量 -->
<maxSizeRollBackups value="5" />
<!-- 单个日志文件的最大大小 -->
<maximumFileSize value="10MB" />
<!-- 归档后文件名是否保持不变 -->
<staticLogFileName value="true" />
<!-- 归档模式 -->
<countDirection value="1" />
<!-- 布局 (Layout): 定义日志格式 -->
<layout type="log4net.Layout.PatternLayout">
<!-- 转换模式 (Conversion Pattern) -->
<conversionPattern value="%date{yyyy-MM-dd HH:mm:ss,fff} [%thread] %-5level %logger{1} - %message%newline%exception" />
</layout>
</appender>
<!-- Appender 2: 控制台输出器 -->
<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: 数据库输出器 (示例) -->
<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>
- <level>配置:
在 <root> 或 <logger> 内部使用。
value 属性设置具体的级别 (DEBUG, INFO, WARN, ERROR, FATAL, OFF, ALL)。
1.2 layout 中有哪些固有参数
参数 | 含义 | 示例 | 其他要点 |
---|---|---|---|
%m 或 %message | 日志消息(loggingEvent.MessageObject) | 用户登录成功 | |
%n | 换行符(平台相关:Windows 是 \r\n,Unix 是 \n) | 换行 | |
%t 或 %thread | 线程名 | MainThread | |
%p 或 %level | 日志级别(Level) | INFO, ERROR | %-5level:左对齐,最小宽度 5(如 INFO ) %5level:右对齐,最小宽度 5(如 INFO) |
%c 或 %logger | 记录器名称(Logger Name) | MyApp.Services.UserService | %.10logger:最多显示 logger 的前 10 个字符 %-40[ %logger{1} ]:左对齐 40 字符,只显示 logger 最后一级 |
%C | 调用者类名(需要 StackTrace 支持,性能较差) | UserService | |
%M | 调用者方法名(同上,需 StackTrace) | Login | |
%F | 调用者源文件名(需调试信息 .pdb) | UserService.cs | |
%L | 调用者行号(需 .pdb) | 45 | |
%l | 完整位置信息 = %F:%L | UserService.cs:45 | |
%d 或 %date | 日期时间 | %d{yyyy-MM-dd HH:mm:ss} → 2025-10-14 23:30:00 | %d{yyyy-MM-dd HH:mm:ss.fff} %date{ISO8601} |
%r | 从程序启动到记录日志所经过的毫秒数 | 12345 | |
%P | 当前进程 ID | 1234 | |
%x 或 %ndc | NDC(Nested Diagnostic Context)栈内容 | 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 | 位置信息(等价于 %C.%M(%F:%L)) | UserService.Login(UserService.cs:45) |
转换符 | 注意事项 |
---|---|
%C, %M, %F, %L, %l, %location | 需要生成 StackTrace,影响性能,建议仅在调试环境使用 |
%X{key}, %property{key} | 可用于添加上下文信息(如用户ID、请求ID) |
%exception | 只有当 exception 不为 null 时才输出 |
二、简单示例测试
2.1 打印出各个级别的日志信息
1)首先引用两个依赖包:log4net 和 Microsoft.Extensions.Logging.Log4Net.AspNetCore。

2)在项目主目录下添加配置文件 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">
<!-- 根据操作系统动态设置日志路径 -->
<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 的内置日志系统(Microsoft.Extensions.Logging)中,并使用指定的配置文件进行初始化。
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)最后,在控制器中如下配置,进行日志记录:
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("错误");
_logger.LogWarning("警告");
_logger.LogDebug("调试");
}
}
}
5)验证
启动项目,并通过第三方接口测试应用,调用 Get 接口,触发日志记录。
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 - 错误
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 - 调试
2.2 如何输出 json 格式的字符串
其实实现起来很简单,就是创建自定义 PatternLayoutConverter 并注册到 Layout。
作用就是,把需要输出的内容进行格式化,转义成字符串,避免把这个信息塞进 json 的一个字段后出现格式校验失败。
如下一个转换器的示例:
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()
{
// 注册自定义转换器名称,在配置文件中使用这个 %escapedmessage 来指代要记录的日志内容
this.AddConverter("escapedmessage", typeof(EscapedMessagePatternConverter));
}
}
public class EscapedMessagePatternConverter : PatternLayoutConverter
{
protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
{
string message = loggingEvent.RenderedMessage ?? string.Empty;
// 使用 JavaScriptStringEncode 进行转义,适合嵌入 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>
注意其中的自定义参数引用:%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":"错误", "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":"调试", "logger":"Test.WebAPI._8._0.Log4net.Controllers.WeatherForecastController"}
参考:https://blog.csdn.net/qq_61632126/article/details/136475013。
三、遇到的一些问题
3.1 Debug 日志没有打印出来,其他级别正常
主要是因为项目配置里的信息,默认为 Information,此级别高于 Debug,因此需要如下修改。
// appsetting.json
{
"Logging": {
"LogLevel": {
"Default": "Information", // 注意这里,配置需改为 Debug
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
// appsettings.Development.json
{
"Logging": {
"LogLevel": {
"Default": "Information", // 注意这里,配置需改为 Debug
"Microsoft.AspNetCore": "Warning"
}
}
}
