如何通过Serilog限制生成5个日志文件且保留旧文件
Serilog日志文件数量限制实现方案
你的需求是:单日志文件达到大小上限时生成新文件,最多保留5个滚动文件;第5个满后不再创建新文件,且所有旧文件都不删除。但Serilog原生的retainedFileCountLimit参数是用来删除超出数量的旧文件,和你的需求冲突,所以得用自定义逻辑实现。
核心思路
- 关闭Serilog的自动清理:把
retainedFileCountLimit设为null,这样所有生成的日志文件都会被保留,不会被自动删除。 - 自定义滚动控制:通过包装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
相关产品推荐
相关产品推荐

