.NET 7控制台应用NLog按日+按小时分日志文件异常问题
问题:NLog时段切换后无法自动创建新日志文件
场景与需求
- .NET 7控制台应用
- 按日期创建独立日志文件夹(如
\15Dec2023\) - 按固定小时间隔生成子日志文件(示例路径:
\15Dec2023\1200-1600.log)
当前配置与实现
NLog目标配置
<target xsi:type="File" name="logfile" fileName="C:\LOGS_ADIALER\${date:format=ddMMMyyyy}\${custom-log-name}.log" layout="${longdate}|${level}|${callsite}|${message} ${all-event-properties} ${exception:format=tostring}" />
自定义LayoutRenderer(硬编码测试版)
[LayoutRenderer("custom-log-name")] public class CustomLog : LayoutRenderer { protected override void Append(StringBuilder builder, LogEventInfo logEvent) { int hour = DateTime.Now.Hour; if(hour <= 4) builder.Append("0000-0400"); else if(hour <= 8) builder.Append("0400-0800"); else if(hour <= 12) builder.Append("0800-1200"); else if(hour <= 16) builder.Append("1200-1600"); else if(hour <= 20) builder.Append("1600-2000"); else builder.Append("2000-2400"); } }
组件注册代码
services.AddLogging(loggingBuilder => { loggingBuilder.ClearProviders(); loggingBuilder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace); loggingBuilder.AddNLog(config); LogManager.Setup().SetupExtensions(ext => { ext.RegisterLayoutRenderer<CustomLog>(); }); });
问题现象
应用启动时日志生成正常,但时段切换后无法自动创建新的日志文件。
解决方案
1. 修正时间基准,使用日志事件时间而非当前时间
日志可能异步处理,DateTime.Now会导致时间偏差,改用日志事件本身的时间戳:
[LayoutRenderer("custom-log-name")] public class CustomLog : LayoutRenderer { protected override void Append(StringBuilder builder, LogEventInfo logEvent) { // 基于日志产生的时间判断时段,避免异步场景的时间错误 int hour = logEvent.TimeStamp.Hour; if(hour <= 4) builder.Append("0000-0400"); else if(hour <= 8) builder.Append("0400-0800"); else if(hour <= 12) builder.Append("0800-1200"); else if(hour <= 16) builder.Append("1200-1600"); else if(hour <= 20) builder.Append("1600-2000"); else builder.Append("2000-2400"); } }
2. 配置NLog强制重新计算文件名
NLog默认会缓存文件名并保持文件打开,需修改target配置触发文件名重计算:
<target xsi:type="File" name="logfile" fileName="C:\LOGS_ADIALER\${date:format=ddMMMyyyy}\${custom-log-name}.log" layout="${longdate}|${level}|${callsite}|${message} ${all-event-properties} ${exception:format=tostring}" keepFileOpen="false" checkFileNamePeriodically="3600" />
keepFileOpen="false":每次写入后关闭文件,强制每次重新计算文件名checkFileNamePeriodically="3600":若需保持文件打开(性能更优),可设置定期检查文件名的间隔(单位:秒)
3. 调整注册顺序,确保自定义Renderer先初始化
将自定义LayoutRenderer的注册移到NLog初始化前,避免组件未加载:
services.AddLogging(loggingBuilder => { // 先注册自定义组件 LogManager.Setup().SetupExtensions(ext => { ext.RegisterLayoutRenderer<CustomLog>(); }); // 再初始化NLog loggingBuilder.ClearProviders(); loggingBuilder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace); loggingBuilder.AddNLog(config); });
4. 可选:用NLog内置语法实现时段划分(无需自定义Renderer)
如果时段间隔固定,可直接通过NLog的日期渲染器实现,比如4小时间隔:
<target xsi:type="File" name="logfile" fileName="C:\LOGS_ADIALER\${date:format=ddMMMyyyy}\${date:format=HH00:cached=false}-${date:format=HH00:cached=false:shift=+4h}.log" layout="${longdate}|${level}|${callsite}|${message} ${all-event-properties} ${exception:format=tostring}" keepFileOpen="false" />
cached=false:强制每次计算文件名shift=+4h:计算时段结束时间
内容的提问来源于stack exchange,提问作者TarunReddy03
相关产品推荐
相关产品推荐

