Log4Net配置不生效的主因是XmlConfigurator.Configure()未在启动时调用、配置文件未复制到输出目录、根节点命名空间错误、logger名称不匹配、日志级别过高、文件权限不足、多进程并发写入及.NET Core中混用日志框架。

Log4Net 配置文件不生效的典型原因
最常见的情况是 XmlConfigurator.Configure() 没在程序启动时调用,或者调用时机太晚(比如放在某个业务方法里)。Log4Net 不会自动扫描配置文件,必须显式触发初始化。
- ASP.NET Core 项目中,
Global.asax的Application_Start是安全位置;.NET 6+ 的Program.cs中需在builder.Build()之前调用 - 配置文件(如
log4net.config)必须设为“复制到输出目录:始终复制”,否则运行时找不到 - 如果用
XmlConfigurator.Configure(new FileInfo("log4net.config")),路径错误会导致静默失败——不会抛异常,但日志完全不输出 -
log4net.config根节点必须是<log4net></log4net>,且命名空间不能错;常见错误是粘贴了带xmlns的示例,导致解析失败
Logger.GetLogger() 返回 null 或不写日志
不是配置错了,而是类名/字符串参数传错了。Log4Net 的 logger 名称是分级匹配的,不是随便起个名字就能用。
- 推荐统一用
LogManager.GetLogger(typeof(Program))—— 这样 logger 名和类名严格一致,和配置里的<logger name="YourNamespace.Program"></logger>或根 logger 能对上 - 避免用
LogManager.GetLogger("MyApp")这种硬编码字符串,除非你明确在配置里定义了同名<logger></logger> - 如果用了继承结构,父类 logger 写日志,子类没配置,日志仍会向上委托到根 logger——但前提是根 logger 的
additivity="true"(默认就是 true) - 检查配置中
<root></root>的<level value="INFO"></level>是否高于你要写的日志级别(比如代码调logger.Debug(),但 root 级别设的是 INFO)
文件 Appender 写入失败或权限不足
Windows 上最常见的报错是 System.UnauthorizedAccessException,尤其在 IIS 或 Windows Service 下运行时,进程账户没有目标目录写权限。
- 不要把日志路径写死成
C:Logspp.log;改用相对路径或环境变量,例如logs\${date:yyyy-MM-dd}.log,配合FileAppender.File设置为logs\目录(Log4Net 会自动创建) - 确认 IIS 应用池标识(如
IIS APPPOOLDefaultAppPool)或服务登录账户对日志目录有“修改”权限 - 使用
RollingFileAppender时,注意maxSizeRollBackups和maximumFileSize单位是字节,不是 KB——"10MB"是非法值,得写"10485760"或用"10MB"(仅较新版本支持,老版只认数字) - 多进程写同一个文件?别这么做。Log4Net 的
FileAppender默认不支持并发写入,会丢日志。改用AsyncAppender包裹,或换TraceAppender+ 自定义 trace listener
在 .NET Core/.NET 5+ 中混合使用 Log4Net 和 Microsoft.Extensions.Logging
Log4Net 本身不兼容 ILogger<t></t> 接口,强行桥接容易掩盖上下文(比如 scope、scopeId)或丢失结构化日志能力。
- 如果只是迁移旧项目,用
Log4NetProvider(来自Microsoft.Extensions.Logging.Log4Net.AspNetCore包)是最快路径,但它只是把ILogger调用转给 Log4Net,不增强功能 - 不要在同一个项目里既用
LogManager.GetLogger()又用ILogger<t></t>——日志来源混杂,过滤、格式化、采样策略难以统一 - Log4Net 的
%property{NDC}或%property{ThreadName}在 ASP.NET Core 请求上下文中基本失效,因为线程切换频繁;改用%property{RequestId}需手动注入,不如直接用Microsoft.Extensions.Logging原生的BeginScope() - 如果你需要结构化日志(比如 Serilog 风格),Log4Net 的
JsonLayout插件成熟度低、文档少、序列化控制弱——这时候真不如切过去用 Serilog


















