log4net 日志框架 — 从配置到实战速查手册

一、核心概念

术语 说明
ILog 日志记录器接口,提供 Debug/Info/Warn/Error/Fatal 等方法
LogManager 日志管理器,通过 GetLogger() 获取 ILog 实例
Appender 日志输出目标(控制台、文件、数据库等),可叠加多个
Layout 日志输出格式,常用 PatternLayout 自定义格式
Logger 日志记录器名称,通常与类名对应,支持层级过滤
Root 根 Logger,所有 Logger 的默认配置
Level 日志级别:DEBUG < INFO < WARN < ERROR < FATAL

二、安装与基础配置

1. 安装 NuGet 包

cs 复制代码
# Package Manager
Install-Package log4net
​
# .NET CLI
dotnet add package log4net

2. App.config / Web.config 配置(.NET Framework)

cs 复制代码
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
​
  <!-- 1. 声明 log4net 自定义配置节 -->
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
​
  <!-- 2. log4net 配置 -->
  <log4net>
    <!-- 文件输出 Appender -->
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="logs/myapp.log" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="5" />
      <maximumFileSize value="10MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
      </layout>
    </appender>
​
    <!-- 根 Logger 配置 -->
    <root>
      <level value="ALL" />
      <appender-ref ref="RollingFileAppender" />
    </root>
  </log4net>
​
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
  </startup>
</configuration>

3. .NET Core / .NET 5+ 配置(独立配置文件)

第一步: 创建 log4net.config 文件,设置属性为 复制到输出目录

cs 复制代码
<?xml version="1.0" encoding="utf-8"?>
<log4net>
  <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
    <file value="logs/app.log" />
    <appendToFile value="true" />
    <rollingStyle value="Date" />
    <datePattern value="yyyy-MM-dd" />
    <staticLogFileName value="false" />
    <encoding value="utf-8" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
    </layout>
  </appender>
​
  <root>
    <level value="ALL" />
    <appender-ref ref="RollingFileAppender" />
  </root>
</log4net>

第二步: 在项目文件 .csproj 中配置自动复制:

cs 复制代码
<ItemGroup>
  <None Update="log4net.config">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

第三步: 初始化配置(二选一):

cs 复制代码
// 方式1:AssemblyInfo.cs 中声明(推荐)
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
​
// 方式2:Program.cs 中手动初始化(.NET 6+ 推荐)
var logRepository = log4net.LogManager.GetRepository(System.Reflection.Assembly.GetExecutingAssembly());
log4net.Config.XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config"));

三、常用 Appender 分类

Appender 类型 说明 常用场景
ConsoleAppender 输出到控制台 开发调试
FileAppender 输出到单个文件 简单日志
RollingFileAppender 按大小/日期滚动文件 生产环境首选
AdoNetAppender 输出到数据库 需要查询分析日志
EventLogAppender 输出到 Windows 事件日志 系统级监控
SmtpAppender 邮件发送日志 错误告警
UdpAppender UDP 远程发送 日志集中收集

RollingFileAppender 常用属性

属性 说明 示例值
file 日志文件路径 logs/app.log
appendToFile 是否追加写入 true
rollingStyle 滚动方式 Size / Date / Composite
maxSizeRollBackups 最大备份文件数 5
maximumFileSize 单文件最大大小 10MB
datePattern 日期滚动格式 yyyy-MM-dd
staticLogFileName 是否固定文件名 true

四、PatternLayout 格式化说明

conversionPattern 常用占位符:

占位符 简写 说明 示例输出
%date %d 日志时间 2026-06-12 10:08:58,148
%thread %t 线程ID 1
%-5level %-5p 日志级别(左对齐5字符) INFO
%logger %c Logger 名称 loginfo
%message %m 日志内容 用户自定义消息
%newline %n 换行符 \r\n
%exception - 异常堆栈 完整异常信息
%type %C 调用者类名 MainFrm
%method %M 调用方法名 Button_Click
%file %F 调用文件名 MainFrm.cs
%line %L 调用行号 42
%property - 线程属性 自定义值
%username - 当前用户名 DOMAIN\User

性能警告%type%method%file%line 等位置信息需要获取堆栈帧,会显著降低性能(约10倍),生产环境慎用!

推荐格式:

cs 复制代码
<!-- 基础格式(推荐生产环境使用) -->
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
​
<!-- 详细格式(开发调试用,含异常堆栈) -->
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline%exception" />
​
<!-- 完整格式(仅开发环境,含调用位置) -->
<conversionPattern value="%date [%thread] %-5level %logger.%method:%line - %message%newline%exception" />

五、日志级别详解

级别 数值 用途
OFF 2147483647 关闭所有日志
FATAL 110000 致命错误,程序无法继续运行
ERROR 70000 错误,但程序可继续运行
WARN 40000 警告,潜在问题
INFO 30000 一般信息,运行状态
DEBUG 20000 调试信息,开发阶段使用
ALL -2147483648 开启所有日志

注意 :日志是否输出取决于 Root/Logger 配置的 level 值,只有 >= 该级别的日志才会输出。

配置示例: 只记录 INFO 及以上级别

cs 复制代码
<root>
  <level value="INFO" />
  <appender-ref ref="RollingFileAppender" />
</root>

六、LogHelper 封装(实战代码)

完整 LogHelper 工具类

cs 复制代码
using System;
using System.IO;
using log4net;
​
namespace YourProject.Helper
{
    /// <summary>
    /// log4net 日志帮助类
    /// </summary>
    public static class LogHelper
    {
        /// <summary>
        /// 信息日志记录器
        /// </summary>
        public static readonly ILog LogInfo = LogManager.GetLogger("loginfo");
​
        /// <summary>
        /// 错误日志记录器
        /// </summary>
        public static readonly ILog LogError = LogManager.GetLogger("logerror");
​
        /// <summary>
        /// 使用默认配置初始化(从 App.config/Web.config 读取)
        /// </summary>
        public static void SetConfig()
        {
            log4net.Config.XmlConfigurator.Configure();
        }
​
        /// <summary>
        /// 使用指定配置文件初始化
        /// </summary>
        /// <param name="configFile">配置文件路径</param>
        public static void SetConfig(FileInfo configFile)
        {
            log4net.Config.XmlConfigurator.Configure(configFile);
        }
​
        /// <summary>
        /// 使用指定配置流初始化(适用于嵌入资源)
        /// </summary>
        /// <param name="configStream">配置文件流</param>
        public static void SetConfig(Stream configStream)
        {
            log4net.Config.XmlConfigurator.Configure(configStream);
        }
​
        /// <summary>
        /// 记录信息日志
        /// </summary>
        /// <param name="message">日志消息</param>
        public static void WriteLog(string message)
        {
            if (LogInfo.IsInfoEnabled)
            {
                LogInfo.Info(message);
            }
        }
​
        /// <summary>
        /// 记录错误日志(含异常)
        /// </summary>
        /// <param name="message">日志消息</param>
        /// <param name="ex">异常对象</param>
        public static void WriteLog(string message, Exception ex)
        {
            if (LogError.IsErrorEnabled)
            {
                LogError.Error(message, ex);
            }
        }
​
        /// <summary>
        /// 记录调试日志
        /// </summary>
        /// <param name="message">日志消息</param>
        public static void WriteDebug(string message)
        {
            if (LogInfo.IsDebugEnabled)
            {
                LogInfo.Debug(message);
            }
        }
​
        /// <summary>
        /// 记录警告日志
        /// </summary>
        /// <param name="message">日志消息</param>
        public static void WriteWarn(string message)
        {
            if (LogInfo.IsWarnEnabled)
            {
                LogInfo.Warn(message);
            }
        }
​
        /// <summary>
        /// 记录致命错误日志
        /// </summary>
        /// <param name="message">日志消息</param>
        /// <param name="ex">异常对象</param>
        public static void WriteFatal(string message, Exception ex)
        {
            if (LogError.IsFatalEnabled)
            {
                LogError.Fatal(message, ex);
            }
        }
​
        /// <summary>
        /// 格式化记录信息日志
        /// </summary>
        /// <param name="format">格式化字符串</param>
        /// <param name="args">参数</param>
        public static void WriteLogFormat(string format, params object[] args)
        {
            if (LogInfo.IsInfoEnabled)
            {
                LogInfo.InfoFormat(format, args);
            }
        }
​
        /// <summary>
        /// 格式化记录错误日志
        /// </summary>
        /// <param name="format">格式化字符串</param>
        /// <param name="args">参数</param>
        public static void WriteErrorFormat(string format, params object[] args)
        {
            if (LogError.IsErrorEnabled)
            {
                LogError.ErrorFormat(format, args);
            }
        }
    }
}

调用示例

cs 复制代码
using YourProject.Helper;

// 1. 初始化配置(程序启动时调用一次)
// .NET Framework: 从 App.config 读取
LogHelper.SetConfig();

// .NET Core/5+: 指定配置文件
// var logRepository = LogManager.GetRepository(Assembly.GetExecutingAssembly());
// XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config"));

// 2. 记录各类日志
LogHelper.WriteLog("程序启动成功");
LogHelper.WriteDebug("调试信息:变量 x = 100");
LogHelper.WriteWarn("警告:磁盘空间不足");
LogHelper.WriteLog("数据库连接失败", new Exception("连接超时"));

// 3. 格式化日志
LogHelper.WriteLogFormat("用户 {0} 登录成功,IP: {1}", "admin", "192.168.1.100");
LogHelper.WriteErrorFormat("请求 {0} 失败,状态码: {1}", "/api/user", 500);

WinForms 项目调用示例

cs 复制代码
using log4net;
using YourProject.Helper;

public partial class MainFrm : Form
{
    public MainFrm()
    {
        InitializeComponent();
        // 窗体加载时初始化日志配置
        LogHelper.SetConfig();
    }

    private void btnSearch_Click(object sender, EventArgs e)
    {
        try
        {
            LogHelper.WriteLog("开始查询数据");
            // 业务逻辑...
            LogHelper.WriteLog("查询完成");
        }
        catch (Exception ex)
        {
            LogHelper.WriteLog("查询失败", ex);
            MessageBox.Show("查询出错,请查看日志");
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        // 测试各种日志级别
        LogHelper.WriteDebug("调试信息");
        LogHelper.WriteLog("一般信息");
        LogHelper.WriteWarn("警告信息");
        LogHelper.WriteLog("错误信息", new InvalidOperationException("测试异常"));
    }
}

七、多 Logger 分类配置

按模块分离日志文件

cs 复制代码
<log4net>
  <!-- 系统日志 -->
  <appender name="SystemAppender" type="log4net.Appender.RollingFileAppender">
    <file value="logs/system.log" />
    <appendToFile value="true" />
    <rollingStyle value="Date" />
    <datePattern value="yyyy-MM-dd" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level - %message%newline" />
    </layout>
  </appender>

  <!-- 错误日志 -->
  <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
    <file value="logs/error.log" />
    <appendToFile value="true" />
    <rollingStyle value="Date" />
    <datePattern value="yyyy-MM-dd" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger - %message%newline%exception" />
    </layout>
  </appender>

  <!-- 系统 Logger -->
  <logger name="loginfo">
    <level value="INFO" />
    <appender-ref ref="SystemAppender" />
  </logger>

  <!-- 错误 Logger -->
  <logger name="logerror">
    <level value="ERROR" />
    <appender-ref ref="ErrorAppender" />
  </logger>

  <!-- 根 Logger -->
  <root>
    <level value="ALL" />
    <appender-ref ref="SystemAppender" />
  </root>
</log4net>

八、常见问题排查

错误1:日志文件未生成

  • 现象 :程序运行后 logs/ 目录下无日志文件

  • 原因:未调用初始化配置 或 配置文件路径错误

  • 解决

cs 复制代码
// 方式1:AssemblyInfo.cs 中声明(推荐,.NET Framework)
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]

// 方式2:代码中手动初始化
log4net.Config.XmlConfigurator.Configure(new FileInfo("log4net.config"));

// 方式3:.NET Core/5+ 推荐方式
var logRepository = LogManager.GetRepository(Assembly.GetExecutingAssembly());
XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config"));

错误2:中文乱码

  • 现象 :日志文件中中文显示为 ???? 或乱码

  • 原因:配置文件未指定编码

  • 解决

cs 复制代码
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
  <encoding value="utf-8" />
  <!-- 其他配置 -->
</appender>

错误3:日志未按日期滚动

  • 现象:所有日志写入同一个文件

  • 原因rollingStylestaticLogFileName 配置错误

  • 解决

cs 复制代码
<rollingStyle value="Date" />
<datePattern value="yyyy-MM-dd" />
<staticLogFileName value="false" />

错误4:configSections 报错

  • 现象ConfigurationErrorsException: 无法识别的配置节 log4net

  • 原因 :未在 configSections 中声明(仅 .NET Framework 需要)

  • 解决

cs 复制代码
<configSections>
  <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>

错误5:配置文件未复制到输出目录

  • 现象:.NET Core 项目找不到配置文件

  • 原因log4net.config 未复制到 bin 目录

  • 解决

cs 复制代码
<!-- 在 .csproj 中添加 -->
<ItemGroup>
  <None Update="log4net.config">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

错误6:日志写入性能问题

  • 现象 :使用 %method%file%line 后性能下降

  • 原因:位置信息需要获取堆栈帧,开销大

  • 解决:生产环境移除位置信息占位符

cs 复制代码
<!-- 生产环境推荐 -->
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />

<!-- 仅开发调试使用 -->
<conversionPattern value="%date [%thread] %-5level %logger.%method:%line - %message%newline" />

错误7:日志文件被锁定

  • 现象:程序重启后无法写入日志

  • 原因:FileAppender 默认锁定文件

  • 解决 :使用 MinimalLock 或切换到 RollingFileAppender

cs 复制代码
<appender name="FileAppender" type="log4net.Appender.FileAppender">
  <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
  <!-- 其他配置 -->
</appender>

九、与现代日志框架对比

特性 log4net Serilog NLog Microsoft.Extensions.Logging
维护状态 维护模式 活跃开发 活跃开发 官方支持
最新版本 3.x 4.x 5.x 9.x
结构化日志 ❌ 不支持 ✅ 原生支持 ✅ 支持 ✅ 支持
.NET Core 支持 ✅ 支持 ✅ 原生 ✅ 原生 ✅ 原生
性能 良好 优秀 优秀 优秀
配置方式 XML 代码/JSON/XML 代码/JSON/XML 代码/JSON
学习曲线
社区生态 成熟 活跃 活跃 官方生态
依赖注入集成 ❌ 需适配 ✅ 原生 ✅ 原生 ✅ 原生

选择建议:

  • 旧项目维护:继续使用 log4net,迁移成本高

  • 新项目推荐:Serilog(结构化日志)或 NLog(功能丰富)

  • ASP.NET Core 项目 :优先使用 Microsoft.Extensions.Logging + Serilog/NLog 提供程序

  • 快速上手:log4net 配置简单,适合小型桌面项目


总结

  • log4net 是 .NET 平台经典的日志框架,配置简单、输出灵活

  • 核心三要素:ILog(记录器)、Appender(输出目标)、Layout(格式)

  • 生产环境推荐 RollingFileAppender 按大小/日期滚动

  • 使用 LogHelper 静态类封装,统一调用入口

  • 中文环境务必配置 <encoding value="utf-8" />

  • 避免在生产环境使用 %method%file%line 等位置信息占位符

  • 新项目建议评估 Serilog/NLog 作为替代方案


最佳实践速查表

场景 推荐配置
生产环境日志格式 %date [%thread] %-5level %logger - %message%newline
开发调试日志格式 添加 %exception 显示完整堆栈
日志文件滚动方式 rollingStyle="Composite" + maxSizeRollBackups="10"
日志文件大小限制 maximumFileSize="50MB"
日志文件编码 <encoding value="utf-8" />
日志级别设置 生产环境 INFO,开发环境 DEBUG
日志文件路径 logs/app.loglogs/{appname}.log
相关推荐
JaydenAI6 小时前
[对比学习LangChain和MAF-07]如何引入人机交互的审批流程
python·ai·langchain·c#·agent·hitl·maf
北域码匠7 小时前
SHA-1算法:安全哈希原理与应用解析
算法·c#·哈希算法
袁小皮皮不皮8 小时前
1.HCIP BFD 学习笔记(优化版)
服务器·网络·笔记·网络协议·学习·智能路由器·ip
123的故事8 小时前
工具分享(7)-多Excel文件内容查询工具
c#·excel·实用工具
iCxhust11 小时前
C#进程管理程序
开发语言·汇编·stm32·单片机·c#·微机原理
ceclar12312 小时前
C# 的任务并行库(TPL)
开发语言·c#·.net
hhcgchpspk12 小时前
汇编语言传递数据和地址的误区
汇编·笔记·nasm·masm
智者知已应修善业12 小时前
【51单片机2个外部中断显示中断历时,初始化8左移3位共阳数码管】2024-6-6
c++·经验分享·笔记·算法·51单片机
xiaoshuaishuai813 小时前
C# 委托与事件
开发语言·c#