You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 01:53:18