Serilog需配置RollingInterval.Day并配合路径中的{Date}占位符才能按日期生成日志文件;否则日志将覆盖或不生效。同时须调用Log.CloseAndFlush()确保刷盘,并提前创建目录、注意时区一致性。
怎么让Serilog按日期生成日志文件
serilog 默认不自动按日期分卷,必须显式配置 rollinginterval.day 并指定文件路径含日期占位符。否则所有日志会堆在同一个文件里,查历史日志得手动翻、归档也麻烦。
关键点是:路径模板里的 {Date} 占位符必须和 RollingInterval.Day 配合使用,缺一不可——只写 {Date} 不设滚动策略,它就当普通字符串处理;只设 RollingInterval.Day 不带 {Date},文件名不会变,只是每天清空重写(不是你想要的“保留多天日志”)。
- 正确写法:
.WriteTo.File("logs/log-{Date}.txt", rollingInterval: RollingInterval.Day) - 错误写法:
.WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day)→ 每天覆盖,旧日志丢失 - 错误写法:
.WriteTo.File("logs/log-{Date}.txt")→{Date}不生效,生成文件叫log-{Date}.txt - 注意
{Date}格式固定为yyyyMMdd,不能自定义成yyyy-MM-dd;如需更细粒度(比如每小时一个文件),改用RollingInterval.Hour,占位符仍是{Date},但文件名里时分秒不体现,靠滚动逻辑切分
为什么 Serilog 的 File Sink 有时不写日志到磁盘
最常见原因是没调用 Log.CloseAndFlush(),尤其在控制台或短生命周期程序中。Serilog 是异步缓冲写入的,默认等缓冲区满或超时才落盘。程序直接退出,缓冲区里那几条日志就丢了。
另一个隐蔽坑是目录权限或路径不存在:logs/ 文件夹如果没提前创建,且进程没权限自动建目录,File Sink 会静默失败(不抛异常,也不写日志),连 SelfLog 都可能被绕过。
- 启动时确保目录存在:
Directory.CreateDirectory("logs"); - 退出前必须加:
Log.CloseAndFlush();(.NET 6+ 的IHostApplicationLifetime.ApplicationStopping里注册最稳妥) - 调试时打开 SelfLog:
Serilog.Debugging.SelfLog.Enable(Console.Error);,能捕获路径无权限、JSON 序列化失败等底层错误 - 别依赖
using var log = new LoggerConfiguration().CreateLogger();自动释放——IDisposable只清资源,不保证刷盘
RollingInterval.Day 在 Windows 和 Linux 下行为一致吗
行为一致,但底层文件系统差异会影响实际表现。核心逻辑由 Serilog 自己控制:每天零点检查当前文件名是否匹配当天 {Date},不匹配就新建文件。和 OS 无关。
真正要注意的是时区和系统时间同步问题。如果服务器时区设错(比如 UTC 但业务按北京时间),日志文件会按错误时间切分——比如北京时间 00:05 本该进 0704 文件,结果进了 0703,因为系统认为还没过零点。
- 确认宿主环境时区:
TimeZoneInfo.Local.DisplayName,建议统一设为业务所在时区(如Asia/Shanghai) - 不要依赖
DateTime.Now.ToString("yyyy-MM-dd")手动拼路径——这是反模式,FileSink 内部已处理好时序逻辑 - 跨时区部署时,避免用
RollingInterval.Day+ 本地时区,改用RollingInterval.Hour更可控 - Linux 下注意 SELinux 或容器 rootless 模式可能导致
mkdir权限拒绝,错误仍静默,务必开SelfLog
如何限制单个日志文件大小并保留最近 N 天
File Sink 不支持“按天保留 + 按大小滚动”双策略。它只能选一种:要么按时间(RollingInterval),要么按大小(retainedFileCountLimit 配合 fileSizeLimitBytes),不能同时生效。
如果你要“每天一个文件,最多留 7 天”,就用 rollingInterval: RollingInterval.Day + retainedFileCountLimit: 7;如果要“每个文件不超过 10MB,总共最多 20 个文件”,就去掉 rollingInterval,只配 fileSizeLimitBytes 和 retainedFileCountLimit。
- 按天保留 7 天:
.WriteTo.File("logs/log-{Date}.txt", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7) - 按大小限制(10MB/个,共 20 个):
.WriteTo.File("logs/log.txt", fileSizeLimitBytes: 10_485_760, retainedFileCountLimit: 20) - 混合需求(比如“每天一个,每个不超过 50MB,最多留 30 天”)→ Serilog 原生不支持,得换
Seq或自己封装ILogEventSink -
retainedFileCountLimit是硬上限,到数后最早文件被删,不判断文件日期,所以按天滚动时它等于“最多留几天”
日期分卷看着简单,但 {Date} 占位符、滚动策略、刷盘时机、目录权限、时区这五点串起来,漏一个就丢日志。尤其是短任务或 Lambda 类场景,CloseAndFlush 容易被忽略,等出问题再查,日志早就没了。










