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

如何用.NET Core自定义ILogger中间件捕获耗时超n毫秒的请求

解决.NET Core慢请求按Warning级别日志记录的方案

嘿,这个需求其实挺常见的,刚好可以通过自定义中间件来完美解决——毕竟默认的ASP.NET Core请求日志没法直接修改它的级别判断逻辑,咱们自己写个中间件来掌控整个流程就好啦!结合你已经实现了自定义ILogger的情况,下面是具体的实现步骤:

1. 创建慢请求日志中间件

这个中间件会在请求开始时记录时间,请求结束后计算耗时,再根据阈值决定日志级别:

public class SlowRequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<SlowRequestLoggingMiddleware> _logger;
    private readonly int _slowRequestThresholdMs;

    // 注入必要的依赖:下一个中间件、日志实例、配置
    public SlowRequestLoggingMiddleware(RequestDelegate next, ILogger<SlowRequestLoggingMiddleware> logger, IConfiguration configuration)
    {
        _next = next;
        _logger = logger;
        // 从配置读取慢请求阈值,默认设为500ms(可按需调整)
        _slowRequestThresholdMs = configuration.GetValue<int>("Logging:SlowRequestThresholdMs", 500);
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 记录请求开始时间(用UTC时间避免时区干扰)
        var startTime = DateTime.UtcNow;

        // 传递请求到后续中间件处理
        await _next(context);

        // 计算总耗时
        var elapsedMs = (DateTime.UtcNow - startTime).TotalMilliseconds;
        var statusCode = context.Response.StatusCode;
        var contentType = context.Response.ContentType;
        var requestMethod = context.Request.Method;
        var requestPath = context.Request.Path;

        // 根据阈值判断日志级别
        if (elapsedMs > _slowRequestThresholdMs)
        {
            _logger.LogWarning(
                "Slow {RequestMethod} request to {RequestPath} finished in {ElapsedMs:F4}ms | StatusCode: {StatusCode} | ContentType: {ContentType}",
                requestMethod, requestPath, elapsedMs, statusCode, contentType);
        }
        else
        {
            // 如果需要保留常规请求的Info级别日志,就保留这段;如果默认日志已经记录,可注释避免重复
            _logger.LogInformation(
                "{RequestMethod} request to {RequestPath} finished in {ElapsedMs:F4}ms | StatusCode: {StatusCode} | ContentType: {ContentType}",
                requestMethod, requestPath, elapsedMs, statusCode, contentType);
        }
    }
}

2. 注册中间件并配置

在Program.cs中注册这个中间件,注意中间件顺序很重要,要让它包裹住整个请求处理流程:

var builder = WebApplication.CreateBuilder(args);

// 注册你的自定义ILoggerProvider(替换成你已实现的Provider)
builder.Logging.ClearProviders();
builder.Logging.AddProvider(new YourCustomLoggerProvider());

// 添加其他服务(比如控制器、授权等)
builder.Services.AddControllers();

var app = builder.Build();

// 基础中间件(HTTPS重定向、静态文件等)
app.UseHttpsRedirection();
app.UseStaticFiles();

// 注册慢请求日志中间件(放在路由之前,确保能捕获完整请求耗时)
app.UseMiddleware<SlowRequestLoggingMiddleware>();

app.UseRouting();
app.UseAuthorization();

app.MapControllers();

app.Run();

然后在appsettings.json中配置阈值和生产环境的日志级别:

{
  "Logging": {
    "SlowRequestThresholdMs": 500, // 自定义慢请求阈值,单位毫秒
    "LogLevel": {
      "Default": "Warning", // 生产环境默认日志级别设为Warning
      "Microsoft.AspNetCore.Hosting.Diagnostics": "None", // 关闭默认的请求完成日志,避免重复输出
      "Microsoft.AspNetCore": "Warning"
    }
  }
}

3. 关键注意事项

  • 中间件顺序:必须把慢请求中间件放在UseRouting之前,这样才能捕获从请求进入到响应返回的完整耗时。
  • 避免重复日志:默认的ASP.NET Core会通过Microsoft.AspNetCore.Hosting.Diagnostics输出请求完成日志,所以我们把它的日志级别设为None,只保留自定义的日志输出。
  • 自定义ILogger适配:因为我们已经通过builder.Logging.AddProvider注册了你的自定义ILoggerProvider,中间件中的ILogger会自动使用你的实现,日志会输出到文本文件。
  • 多环境配置:可以通过appsettings.Production.json单独设置生产环境的阈值,比如把生产环境的阈值设为1000ms,开发环境设为500ms。

这样配置后,生产环境下只有耗时超过阈值的慢请求会以Warning级别记录,刚好符合你的需求~

内容的提问来源于stack exchange,提问作者pr.lwd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:34:53