nlog日志不写入文件主因是nlog.config未复制到输出目录或配置加载失败;需设“始终复制”,检查bin目录是否存在该文件,并确认asp.net core中无配置干扰。

日志不写入文件?八成是 NLog.config 没复制到输出目录,或者 LogManager.GetCurrentClassLogger() 调用前配置就已加载失败——它不会报错,只会静默丢弃所有日志。
为什么 NLog.config 必须设为“始终复制”
运行时 LogManager 默认只从 bin/Debug 或 bin/Release 目录加载配置。如果 NLog.config 仅存在于项目根目录但未复制过去,LogManager.Configuration 就是 null,后续所有 logger.Info() 都无效。
- 右键
NLog.config→ “属性” → “复制到输出目录” → 选“始终复制” - 检查输出目录下是否存在该文件;若没有,手动复制一次并观察是否开始出日志
- 不要依赖“如果较新则复制”,某些构建缓存会导致它跳过更新
- ASP.NET Core 项目中,还需确认
web.config或appsettings.json没有干扰 NLog 初始化顺序
LogManager.GetCurrentClassLogger() 的隐式行为和陷阱
这个方法看似简单,实则绑定两个关键逻辑:自动以 typeof(CurrentClass).FullName 命名 logger,并触发首次配置加载。一旦失败,无提示、无异常、无日志。
- 不能在静态构造函数或字段初始化器里调用它——此时配置尚未加载,
LogManager.Configuration仍为null - 每个类建议只声明一个
static readonly ILogger字段,避免重复创建 logger 实例 - 若需按模块分组(如所有订单相关类共用
"Order"),改用LogManager.GetLogger("Order"),而非依赖类名 - 调试时可加一句
Console.WriteLine(LogManager.Configuration?.AllTargets.Count)确认配置是否加载成功
文件目标(File target)常见配置项含义
fileName、archiveEvery、maxArchiveFiles 这三个参数协同决定日志怎么落盘、何时滚动、保留多久,配错会导致日志堆积或瞬间清空。
-
fileName="${basedir}/logs/${shortdate}.log":每天生成新文件,路径基于程序启动目录 -
archiveEvery="Day"和archiveFileName="${basedir}/logs/archives/app.{#}.log"配合使用才生效;单独设archiveEvery不会归档 -
maxArchiveFiles="30"是指归档目录下的最大文件数,不是总日志天数(例如每天归档 1 个,就是最多存 30 天) - 若用
archiveAboveSize,必须同时设archiveNumbering="Rolling",否则归档逻辑不触发
结构化日志在 NLog 中不是默认开启的
写 _logger.LogInformation("User {Id} logged in", userId),默认输出仍是纯文本 User {Id} logged in,字段 Id 不会被提取。要真正结构化,得靠 JsonLayout + 正确的 layout 配置。
- 必须在
<target></target>内显式指定<layout xsi:type="JsonLayout"></layout> - 需启用
includeAllProperties="true",否则只有message和level等基础字段 - 搭配
renderers可控制字段名,例如<attribute name="timestamp" layout="${longdate}"></attribute> - 注意:结构化日志会略微增加序列化开销,高吞吐场景下建议只对
Info及以上级别启用
最常被忽略的一点:NLog 不读取 appsettings.json,哪怕你把连接字符串或路径变量放进去,它也视而不见。所有动态值要么硬编码进 NLog.config,要么通过代码注入 LogManager.Configuration.Variables,别指望自动桥接。










