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

如何通过Serilog限制生成5个日志文件且保留旧文件

Serilog日志文件数量限制实现方案

你的需求是:单日志文件达到大小上限时生成新文件,最多保留5个滚动文件;第5个满后不再创建新文件,且所有旧文件都不删除。但Serilog原生的retainedFileCountLimit参数是用来删除超出数量的旧文件,和你的需求冲突,所以得用自定义逻辑实现。

核心思路

  1. 关闭Serilog的自动清理:把retainedFileCountLimit设为null,这样所有生成的日志文件都会被保留,不会被自动删除。
  2. 自定义滚动控制:通过包装Serilog的File Sink,在每次写入日志前检查当前已有的同前缀日志文件数量,达到5个时就停止创建新文件,直接写入最后一个文件。

修改后的基础配置

先调整appsettings.json里的Serilog配置,关闭自动清理:

"Serilog": {
  "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.Seq" ],
  "MinimumLevel": {
    "Default": "Information",
    "Override": {
      "Serilog.AspNetCore.RequestLoggingMiddleware": "Information",
      "Microsoft": "Warning",
      "Microsoft.EntityFrameworkCore": "Warning",
      "System": "Warning",
      "Microsoft.AspNetCore.Authentication": "Information"
    }
  },
  "WriteTo": [
    {
      "Name": "File",
      "Args": {
        "path": "..\\logs\\log-rfzo-test-.log",
        "rollingInterval": "Day",
        "fileSizeLimitBytes": 10240,
        "rollOnFileSizeLimit": true,
        "retainedFileCountLimit": null,
        "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] [{SourceContext}] {Message}{NewLine}{Exception}"
      }
    }
  ]
}

自定义Sink实现

创建一个自定义的日志Sink,用来控制滚动文件的数量:

using Serilog.Core;
using Serilog.Events;
using Serilog.Sinks.File;
using System.IO;
using System.Linq;

public class LimitedRollingFileSink : ILogEventSink
{
    private readonly ILogEventSink _innerFileSink;
    private readonly string _logFilePattern;
    private readonly int _maxAllowedFiles;
    private readonly object _writeLock = new object();

    public LimitedRollingFileSink(string logPath, int maxFileCount, FileSinkOptions sinkOptions)
    {
        _innerFileSink = new FileSink(
            logPath,
            sinkOptions.TextFormatter,
            sinkOptions.FileSizeLimitBytes,
            sinkOptions.RollingInterval,
            sinkOptions.RollOnFileSizeLimit,
            sinkOptions.RetainedFileCountLimit,
            sinkOptions.Buffered,
            sinkOptions.Shared,
            sinkOptions.Encoding);
        
        var dir = Path.GetDirectoryName(logPath);
        var fileName = Path.GetFileNameWithoutExtension(logPath) + "*" + Path.GetExtension(logPath);
        _logFilePattern = Path.Combine(dir, fileName);
        _maxAllowedFiles = maxFileCount;
    }

    public void Emit(LogEvent logEvent)
    {
        lock (_writeLock)
        {
            // 获取当前所有符合命名规则的日志文件,按创建时间倒序排列
            var existingLogs = Directory.GetFiles(Path.GetDirectoryName(_logFilePattern), Path.GetFileName(_logFilePattern))
                .OrderByDescending(f => new FileInfo(f).CreationTime)
                .ToList();

            if (existingLogs.Count >= _maxAllowedFiles)
            {
                // 达到文件数量上限,直接写入最后一个日志文件
                var lastLogFile = existingLogs.First();
                using var writer = File.AppendText(lastLogFile);
                _innerFileSink.TextFormatter.Format(logEvent, writer);
            }
            else
            {
                // 未达到上限,使用原生滚动逻辑写入
                _innerFileSink.Emit(logEvent);
            }
        }
    }
}

配置使用自定义Sink

在Program.cs里替换默认的File Sink为自定义Sink:

var builder = WebApplication.CreateBuilder(args);

// 读取配置
var config = builder.Configuration;

// 配置Serilog
Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(config)
    .WriteTo.Sink(new LimitedRollingFileSink(
        logPath: "..\\logs\\log-rfzo-test-.log",
        maxFileCount: 5,
        sinkOptions: new FileSinkOptions
        {
            FileSizeLimitBytes = 10240,
            RollingInterval = RollingInterval.Day,
            RollOnFileSizeLimit = true,
            RetainedFileCountLimit = null,
            OutputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] [{SourceContext}] {Message}{NewLine}{Exception}"
        }))
    .CreateLogger();

builder.Host.UseSerilog();

// 其他中间件配置...

var app = builder.Build();

// 应用逻辑...

app.Run();

说明

Serilog官方的File Sink没有原生支持“达到文件数量上限后停止滚动”的功能,所以必须通过自定义Sink来实现上述逻辑。该方案既保留了所有旧日志文件,又限制了滚动文件的最大数量,符合你的需求。

内容的提问来源于stack exchange,提问作者DraganMilovac1993

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 17:37:45