Apache log4net 3.5.0 配置参数详解
基于Ubuntu 22.04实测详解log4net 3.5.0的XML配置体系、Appender与Layout全参数、Filter链及生产配置模板。
Apache log4net 3.5.0 配置参数详解
目标:系统梳理 log4net 3.5.0 的配置加载体系,逐项解释 logger/root、Appender(Console/RollingFile)、Layout(PatternLayout 转换符)、Filter 各类参数含义与默认值并给出实测验证,最后提供两套生产配置模板。全部示例已在 Ubuntu 22.04 + .NET 8 实测通过。
一、环境信息
| 项目 | 说明 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS |
| 架构 | x86_64 |
| 运行时 | .NET SDK 8.0.426 |
| 组件版本 | log4net 3.5.0(NuGet) |
| 目录 | 项目 ~/dotnetdemo/Log4NetDemo,配置与日志见正文各节 |
逐项说明:log4net 只有 XML 一种配置格式(这点与 log4j 的 properties+XML 双格式不同),所有参数通过 XmlConfigurator 加载;本篇直接复用集成篇建好的项目与包引用。
二、配置体系概览
2.1 配置加载方式
| 方式 | 代码 | 适用 |
|---|---|---|
| 显式加载文件 | XmlConfigurator.Configure(new FileInfo("log4net.config")) | 本文实测方式,路径最可控 |
| 监视热更加载 | XmlConfigurator.ConfigureAndWatch(new FileInfo("log4net.config")) | 生产改级不停服 |
| 程序集特性 | [assembly: log4net.Config.XmlConfigurator(ConfigFile="log4net.config", Watch=true)] | 类库自描述配置 |
三种方式可并存,后配置者覆盖同仓库既有配置。实测对比:Configure 立即生效一次;ConfigureAndWatch 注册 FileSystemWatcher 持续监视。
2.2 配置文件骨架
<log4net>
<appender name="..." type="log4net.Appender.XxxAppender"> ... </appender>
<logger name="..."> ... </logger>
<root> ... </root>
</log4net>
逐项解说:appender 定义输出端(name 供引用、type 决定实现类);logger 命名配置的层次节点;root 是层次根,未显式配置的 Logger 都从它继承级别。根元素可选属性 debug="true" 打开内部诊断(见 FAQ Q8)。
三、logger 与 root 配置参数
3.1 root
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
| 子元素/属性 | 含义 | 默认值 |
|---|---|---|
| level/@value | root 的级别 | 默认 DEBUG(未配置时) |
| appender-ref/@ref | 挂接的 Appender 名 | 无 |
实测验证:root=DEBUG 时五个级别全部输出;代码侧读取仓库 Threshold 未显式设置时显示 ALL(默认不设总闸)。
3.2 命名 logger
<logger name="OrderService.Dao">
<level value="INFO" />
</logger>
<logger name="IsolatedLogger" additivity="false">
<appender-ref ref="SpecialFile" />
</logger>
| 子元素/属性 | 含义 | 默认值 |
|---|---|---|
| level/@value | 节点级别,未设则继承父链 | 继承 |
| additivity/@value | 事件是否继续传给父 Logger 的 Appender | true |
| appender-ref | 本节点挂接的 Appender | 无 |
实测验证(层次示例):OrderService.Dao 设 INFO 后其 DEBUG 无输出,同级未配置的 UserService.Dao 继承 root 的 DEBUG 正常输出——层次继承语义与 log4j 完全一致。
💡 技术拓展:log4net 不支持 log4j 风格的 properties 配置,只有 XML 一种。若团队想统一"改文本文件即可调日志"的运维习惯,XML 配合 ConfigureAndWatch 同样能做到;两种格式之争在 log4net 这里不存在,运维侧只需维护一份 .config。本文全部采用 XML 实测。
四、Appender 参数详解
4.1 ConsoleAppender
| 参数 | 含义 | 默认值 |
|---|---|---|
| layout | 布局子元素 | 无(必须配) |
| threshold | 本端最低级别 | 未启用 |
| filter | 过滤链子元素 | 无 |
实测模板:
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
实测输出样例:
2026-10-14 16:50:46,322 [1] INFO Log4NetDemo.Program - 普通信息:用户 admin 于 2026-10-15 登录系统
4.2 RollingFileAppender
log4net 最常用的 Appender,参数与默认值:
| 参数 | 含义 | 默认值 | 实测验证 |
|---|---|---|---|
| file | 目标文件路径;相对路径基于应用基目录 | 无 | logs/app.log 落在 bin/Debug/net8.0/logs |
| appendToFile | 追加或覆盖 | true | 多次运行内容保留 |
| rollingStyle | 滚动模式:Once/Size/Date/Composite | Size | 实测 Size |
| maximumFileSize | 单文件阈值,支持 KB/MB/GB | 10MB | 实测 10KB 触发 |
| maxSizeRollBackups | 历史文件保留数(-1 不限) | 0(不保留) | 实测 3 |
| staticLogFileName | true 时当前文件名固定,滚动后改名 | true | 实测启用 |
| countDirection | 编号方向:1 递增,-1 递减(log4j 风格) | -1 | 实测 1 |
| preserveLogFileNameExtension | 滚动文件保留原扩展名 | false | 实测启用后为 roll.1.log |
| datePattern | Date/Composite 模式下的日期模板 | .yyyy-MM-dd | Date 模式实测项 |
| lockingModel | 文件锁策略:ExclusiveLock/FileAppender.MinimalLock | ExclusiveLock | 多进程写需 MinimalLock |
| layout | 布局子元素 | 无 | 实测 PatternLayout |
| threshold | 本端最低级别 | 未启用 | 见 3.2 说明 |
| filter | 过滤链 | 无 | 见 Filter 章 |
滚动压测实测(10KB、3 份、countDirection=1、preserveLogFileNameExtension=true):
total 48
-rw-r--r-- 1 root root 10292 Oct 14 16:52 roll.1.log
-rw-r--r-- 1 root root 10296 Oct 14 16:52 roll.2.log
-rw-r--r-- 1 root root 10296 Oct 14 16:52 roll.3.log
-rw-r--r-- 1 root root 208 Oct 14 16:52 roll.log
逐项解说:递增编号(roll.1 是最先滚出的文件,roll.log.1 是 countDirection=-1 时的形态);当前文件 roll.log 永远是最新内容;第 300 条容量写满后,更早的 roll.4 及以后被删除,总占用约 31 KB。
4.3 FileAppender 与其它 Appender 速查
| Appender | 关键参数 | 说明 |
|---|---|---|
| FileAppender | file、appendToFile、lockingModel | RollingFileAppender 的父类,单文件不滚动 |
| TraceAppender | 无强制参数 | 输出到 System.Diagnostics.Trace |
| EventLogAppender | Application、Source | 仅 Windows |
| SmtpAppender | to/from/subject、smtpHost、bufferSize | 攒批邮件,适合 FATAL 告警 |
| AdoNetAppender | bufferSize、connectionType、connectionString、commandText | 参数化 SQL 落库 |
| UdpAppender | remoteAddress、remotePort、encoding | 轻量远程推送 |
五、Layout 参数详解
5.1 PatternLayout 转换符全表
| 转换符 | 含义 | 实测输出示例 |
|---|---|---|
| %date 或 %d | 时间戳,默认 ISO8601 含毫秒 | 2026-10-14 16:50:46,312 |
| %thread 或 %t | 线程号 | 1 |
| %level 或 %p | 级别,%-5level 补齐 5 列 | INFO (补 1 空格) |
| %logger 或 %c | Logger 名;%logger{1} 取最后一段 | Log4NetDemo.Program / Program |
| %message 或 %m | 消息文本 | 滚动压测第 299 条 |
| %newline 或 %n | 换行 | — |
| %exception 或 %exception{format} | 异常文本(无异常时空) | System.Exception: Connection refused |
| %property{key} | 上下文属性(Thread/LogicalThread/Global) | admin |
| %identity / %username | 身份(取决于环境) | — |
| %appdomain / %assembly / %type | 运行时信息 | — |
| %file / %line / %method | 调用位置(需 LocationInformationMode) | — |
| %% | 字面百分号 | % |
宽度与对齐语法与 log4j 相同:%-5level 左对齐最小 5 列,%20logger 右对齐 20 列,%logger{1} 中的花括号是精度段数(实测写 %logger{name} 报错,必须数字)。
5.2 其它 Layout
| Layout | 说明 | 实测备注 |
|---|---|---|
| SimpleLayout | "级别 - 消息" | 无参数 |
| XmlLayout | 输出 log4net:event XML 块 | XML 采集管道用 |
| RawTimeStampLayout 等 | 单字段裸值 | AdoNetAppender 参数化输出用 |
六、Filter 参数详解
Appender 内 Filter 按声明顺序形成链,返回 Deny/Neutral/Accept;出现 Deny 或 Accept 即终止,全 Neutral 则放行。
| Filter | type | 关键参数 | 默认值 |
|---|---|---|---|
| LevelMatchFilter | log4net.Filter.LevelMatchFilter | levelToMatch、acceptOnMatch | 无、true |
| LevelRangeFilter | log4net.Filter.LevelRangeFilter | levelMin、levelMax、acceptOnMatch | 无、无、true |
| StringMatchFilter | log4net.Filter.StringMatchFilter | stringToMatch、acceptOnMatch | 无、true |
| LoggerMatchFilter | log4net.Filter.LoggerMatchFilter | loggerToMatch、acceptOnMatch | 无、true |
| PropertyFilter | log4net.Filter.PropertyFilter | key、stringToMatch、acceptOnMatch | 无、无、true |
| MdcFilter / NdcFilter | log4net.Filter.* | 同 PropertyFilter 语义 | — |
| DenyAllFilter | log4net.Filter.DenyAllFilter | 无 | 无条件拒绝 |
6.1 LevelMatchFilter 白名单实测
<appender name="Console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%-5level] %logger - %message%newline" />
</layout>
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="WARN" />
<acceptOnMatch value="true" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
</appender>
程序发 INFO/WARN/ERROR 三条,实测输出仅一条:
[WARN ] FilterDemo - WARN 消息:命中 LevelMatchFilter,应被放行
逐项解说:WARN 命中即 ACCEPT(链终止);INFO/ERROR 未命中走 Neutral 交给 DenyAllFilter 被 DENY。若 acceptOnMatch=false,WARN 会被该 Filter DENY,其余走链尾默认放行——白名单秒变黑名单,务必理解再调。
6.2 LevelRangeFilter 区间实测
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="DEBUG" />
<levelMax value="ERROR" />
</filter>
实测验证:层次示例中父 Logger 的 FATAL 消息虽过 root 级别检查,仍被此 Filter 拦截(levelMax=ERROR),证明 Filter 独立于 Logger 级别生效。
七、生产配置模板
7.1 通用服务模板(控制台 + 大小滚动)
<?xml version="1.0" encoding="utf-8"?>
<log4net>
<appender name="Console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="/var/log/myapp/app.log" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<datePattern value="yyyyMMdd" />
<maximumFileSize value="100MB" />
<maxSizeRollBackups value="10" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline%exception" />
</layout>
</appender>
<logger name="Microsoft">
<level value="WARN" />
</logger>
<root>
<level value="INFO" />
<appender-ref ref="Console" />
<appender-ref ref="RollingFile" />
</root>
</log4net>
逐项解说:rollingStyle=Composite 同时按日期与大小滚动(每天一个文件、单文件超 100MB 再切);maxSizeRollBackups=10 控制每日期分片的历史数;框架日志(Microsoft 前缀)压到 WARN 防噪;%exception 追加在行尾保证异常不丢。
7.2 告警邮件模板(缓冲批量发送)
<appender name="SmtpAlert" type="log4net.Appender.SmtpAppender">
<to value="ops@example.com" />
<from value="myapp@example.com" />
<subject value="[myapp] 告警日志" />
<smtpHost value="smtp.example.com" />
<authentication value="Basic" />
<username value="alert" />
<password value="q1w2e3r4" />
<bufferSize value="20" />
<lossy value="true" />
<evaluator type="log4net.Core.LevelEvaluator">
<threshold value="ERROR" />
</evaluator>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %-5level %logger - %message%newline%exception" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="ERROR" />
</filter>
</appender>
逐项解说:lossy=true 时缓冲只在评估器命中(ERROR 以上)时整批发出,避免刷屏;bufferSize=20 一封邮件最多带 20 条;示例账号 alert 密码 q1w2e3r4,生产请替换并纳入密钥管理。SmtpAppender 与 LevelRangeFilter 组合即"只邮件告警"的经典形态。
八、常见问题(FAQ)
Q1:log4net 支持像 log4j 那样的 properties 配置吗? A:不支持,log4net 只有 XML 配置(log4net.config)。与 log4cxx/log4php 的双格式体系不同,这是 .NET 移植时的取舍。运维统一用 XML + ConfigureAndWatch 热更即可。
Q2:File 相对路径到底相对哪里? A:应用程序基目录(AppDomain BaseDirectory)。实测 bin/Debug/net8.0/logs 是 logs/app.log 的真实落点。要相对运行目录必须代码侧把 AppContext.BaseDirectory 拼进 file 值,或直接写绝对路径。
Q3:maximumFileSize 支持哪些单位? A:纯数字按字节,KB/MB/GB 后缀实测可用(10KB 触发滚动)。默认 10MB。
Q4:maxSizeRollBackups 默认值是多少?为什么我滚动后旧文件没了?
A:默认 0——滚动时直接覆盖,不留历史。生产必须显式设置(常用 1030)。实测设 3 后可见 roll.1.logroll.3.log。
Q5:countDirection 和 preserveLogFileNameExtension 怎么选? A:countDirection=1 生成 roll.1.log 递增风格,-1 是 log4j 的 roll.log.1 递减风格(越滚越大编号,文件检索工具按字母排序时更直观);preserveLogFileNameExtension=true 让滚动文件保留 .log 后缀,便于按扩展名关联日志工具。两者都实测验证,按团队习惯选。
Q6:多个进程能写同一个日志文件吗? A:默认 ExclusiveLock 独占锁,第二进程打开文件失败。多进程场景把 lockingModel 换成 log4net.Appender.FileAppender+MinimalLock(写入间隙释放锁),代价是频繁开关文件、吞吐下降;更优方案是每进程一个文件。
Q7:怎么按 Logger 名把不同模块日志分文件? A:为模块建独立 Appender,模块 logger 配 additivity="false" 只挂自己的 Appender;再在公共 Appender 上用 LoggerMatchFilter 排除该模块,避免双写。
Q8:配置明明正确却不生效,怎么排查? A:三步:确认加载了预期文件(Configure 传入的 FileInfo 路径);根元素加 debug="true" 看内部日志(实测会打印 Setting Property [File] ... 等属性注入全程);检查 appender-ref 的 ref 与 appender 的 name 是否逐字一致——拼写错是最高频事故。
Q9:%property{key} 取不到值怎么办? A:%property 读取的是 Thread/LogicalThread/Global 上下文属性,必须先在代码里设置(ThreadContext.Set("userId","admin"))。GlobalContext.Properties 在配置加载前设置即可被 %property 读取,适合注入节点名等部署参数。
Q10:日志文件中文乱码? A:log4net 默认按系统编码写文件。Linux 下通常无需处理(UTF-8 环境);确需显式控制时在 Appender 上设 encoding 参数(如 utf-8)。本篇实测中文消息在 Ubuntu 22.04 控制台与文件均正常。
九、参考链接
- log4net 配置参考(全 Appender/Layout/Filter 参数):https://logging.apache.org/log4net/release/config-reference.html
- RollingFileAppender 参数细节:https://logging.apache.org/log4net/release/sdk/html/T_log4net_Appender_RollingFileAppender.htm
- PatternLayout 转换符文档:https://logging.apache.org/log4net/release/sdk/html/T_log4net_Layout_PatternLayout.htm
- log4net FAQ 官方版:https://logging.apache.org/log4net/release/faq.html
- Apache log4net 主页:https://logging.apache.org/log4net/