Serilog日志清理:如何在SQL数据库中仅保留近3个月日志
Serilog SQL Server日志自动清理方案
嘿,作为Serilog新手碰到日志清理的问题太正常了——毕竟Serilog本身没有内置的自动清理SQL Server日志的功能,不过我们有几个非常靠谱的解决方案,帮你实现只保留近3个月数据的需求:
方案1:使用SQL Server Agent定时作业(最推荐)
这是生产环境中最常用的方式,直接利用SQL Server自身的调度能力来清理旧日志,不需要改动应用代码:
- 先写一个清理日志的SQL脚本,注意替换成你的日志表名和时间字段(Serilog默认时间字段是
Timestamp,如果自定义过要调整):
-- 先查询确认要删除的记录,没问题再执行DELETE SELECT * FROM [YourLogTableName] WHERE [Timestamp] < DATEADD(MONTH, -3, GETUTCDATE()) -- 确认后执行删除 DELETE FROM [YourLogTableName] WHERE [Timestamp] < DATEADD(MONTH, -3, GETUTCDATE())
- 打开SQL Server Management Studio,创建一个SQL Server Agent作业:
- 新建作业,添加一个执行上述SQL的步骤
- 设置调度规则(比如每周日凌晨2点执行,避开业务高峰)
- 配置作业通知(比如失败时发邮件告警)
方案2:在WebAPI中添加后台定时任务
如果你的环境没法用SQL Server Agent(比如用的是Azure SQL Database,需要用弹性作业或者应用内调度),可以在ASP.NET Core中添加一个后台服务来定时清理:
步骤1:创建日志清理后台服务
public class LogCleanupBackgroundService : BackgroundService { private readonly string _logDbConnectionString; private readonly ILogger<LogCleanupBackgroundService> _logger; public LogCleanupBackgroundService(IConfiguration configuration, ILogger<LogCleanupBackgroundService> logger) { _logDbConnectionString = configuration.GetConnectionString("YourLogDatabaseConnection"); _logger = logger; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // 每天凌晨1点执行一次清理 var cleanupInterval = TimeSpan.FromDays(1); using var timer = new PeriodicTimer(cleanupInterval); while (!stoppingToken.IsCancellationRequested && await timer.WaitForNextTickAsync(stoppingToken)) { try { await CleanupOldLogs(); _logger.LogInformation("Successfully cleaned up logs older than 3 months"); } catch (Exception ex) { _logger.LogError(ex, "Failed to clean up old logs"); } } } private async Task CleanupOldLogs() { const string cleanupSql = @" DELETE FROM [YourLogTableName] WHERE [Timestamp] < DATEADD(MONTH, -3, GETUTCDATE())"; using var connection = new SqlConnection(_logDbConnectionString); await connection.OpenAsync(); using var command = new SqlCommand(cleanupSql, connection); var rowsDeleted = await command.ExecuteNonQueryAsync(); _logger.LogDebug("Deleted {RowsDeleted} old log records", rowsDeleted); } }
步骤2:注册后台服务
在Program.cs中添加服务注册:
builder.Services.AddHostedService<LogCleanupBackgroundService>();
额外优化建议
- 给时间字段加索引:给
Timestamp字段创建非聚集索引,能大幅提升删除操作的效率,尤其是日志表数据量很大的时候。 - 考虑分区表:如果日志量特别大,可以把日志表按月份分区,直接删除旧分区比逐条删除快得多。
- Seq的日志保留:你同时用了Seq,记得在Seq的管理后台也配置日志保留策略(比如保留3个月),避免Seq存储冗余数据。
内容的提问来源于stack exchange,提问作者Akhil




