You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Serilog日志清理:如何在SQL数据库中仅保留近3个月日志

Serilog SQL Server日志自动清理方案

嘿,作为Serilog新手碰到日志清理的问题太正常了——毕竟Serilog本身没有内置的自动清理SQL Server日志的功能,不过我们有几个非常靠谱的解决方案,帮你实现只保留近3个月数据的需求:

方案1:使用SQL Server Agent定时作业(最推荐)

这是生产环境中最常用的方式,直接利用SQL Server自身的调度能力来清理旧日志,不需要改动应用代码:

  1. 先写一个清理日志的SQL脚本,注意替换成你的日志表名和时间字段(Serilog默认时间字段是Timestamp,如果自定义过要调整):
-- 先查询确认要删除的记录,没问题再执行DELETE
SELECT * FROM [YourLogTableName]
WHERE [Timestamp] < DATEADD(MONTH, -3, GETUTCDATE())

-- 确认后执行删除
DELETE FROM [YourLogTableName]
WHERE [Timestamp] < DATEADD(MONTH, -3, GETUTCDATE())
  1. 打开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

火山引擎 最新活动