Microsoft.Extensions.Logging.HttpLogging 1.1.6

Microsoft.Extensions.Logging.HttpLogging

将 .NET Web 应用的 HTTP 请求/响应日志异步采集并写入 SQL Server,支持中间件采集、后台通道缓冲、存储过程写入、查询与维护。适合本地与企业内部集中化日志场景。


核心特性

  • HTTP 日志中间件:自动采集请求/响应的基础信息、头、客户端信息等。
  • 异步缓冲:使用有界 Channel(容量 1000,满时丢弃最旧)降低主线程阻塞。
  • 后台写入:托管服务批量消费消息并通过存储过程入库。
  • 可插拔处理器:实现 IHttpLoggingMessageHandler 自定义写入策略(默认 SQL Server 存储过程)。
  • 客户端能力:IHttpLoggingClient 提供追加、查询、删除、清空等维护操作。
  • 多实例隔离:通过 HttpLoggingOptions.Key 支持多路并行(通道/处理器/客户端均按 Key 隔离)。
  • 配置监控:IOptionsMonitor<HttpLoggingOptions> 支持运行期更新连接串等配置。

安装

dotnet add package Microsoft.Extensions.Logging.HttpLogging

快速开始

1) 注册日志与中间件(默认处理器)

using Microsoft.Extensions.Logging;

builder.Services.AddLogging(logging =>
{
    logging.AddHttpLogging(options =>
    {
        options.ConnectionString = "Server=localhost;Database=LogsDb;Trusted_Connection=True;TrustServerCertificate=True;";
        options.Application = "MyWebApp";
        options.TableName = "[dbo].[_Log_Http]";
        options.PorcName = "[dbo].[_Log_Http_Append]";
        options.SearchPorcName = "[dbo].[_Log_Http_Search]";
        options.Key = "Logging.Http"; // 多实例时确保唯一
        options.EnableRequest = true;
        options.EnableResponse = false;
        options.EnableHeaders = true;
        options.EnableAgent = true;
        options.EnableRequestBody = false; // 默认禁用,避免性能问题
        options.EnableResponseBody = false;
        options.RequestBodyLogLimit = 1024 * 1024; // 1MB
        options.ResponseBodyLogLimit = 1024 * 1024; // 1MB
        // 仅记录指定的 HTTP 方法(默认包含常见方法)
        options.HttpMethods = new[] { "GET", "POST", "PUT", "DELETE" };
    });
});

// 启用 HTTP 日志中间件(需在路由前)
var app = builder.Build();
app.UseHttpAccessLogging(); // 必须在 app.UseRouting() 之前
app.UseRouting();
app.MapGet("/ping", () => "pong");
app.Run();

首次运行若数据库无表/过程,默认处理器不会自动建表;请按下文“表结构与存储过程”准备对象。

2) 使用自定义消息处理器

实现自定义处理器以替代默认 SQL 写入策略:

using Microsoft.Extensions.Logging;

public class MyHttpHandler : IHttpLoggingMessageHandler
{
    private readonly ILogger<MyHttpHandler> _logger;
    public MyHttpHandler(ILogger<MyHttpHandler> logger) => _logger = logger;

    public Task HandleAsync(HttpLoggingMessage message, CancellationToken token = default)
    {
        // 写入自定义存储(如文件/ES/消息队列/第三方平台)
        _logger.LogInformation("{Method} {Path} from {IP}", message.Method, message.Path, message.IPAddress);
        return Task.CompletedTask;
    }

    public void Dispose() { /* 释放资源 */ }
}

// 注册自定义处理器
builder.Services.AddLogging(logging =>
{
    logging.AddHttpLogging<MyHttpHandler>(options =>
    {
        options.Key = "Logging.Http.Custom";
        // 若不使用 SQL,可忽略连接串/过程名等
    });
});

多实例:不同业务线或环境可使用不同 Key 分别配置与隔离。中间件内部按 Key 解析当前配置与通道。


中间件采集说明

  • IP 地址优先从代理/网关头部提取:X-Forwarded-ForX-Real-IPCF-Connecting-IPTrue-Client-IP,取第一个非空;若无则回退 HttpContext.Connection.RemoteIpAddress
  • 平台信息优先读取 Sec-CH-UA-Platform,否则解析 User-Agent 推断常见平台(windows/macos/ios/android/chromeos/linux)。
  • 响应体采集使用包装 IHttpResponseBodyFeature,仅在开启 EnableResponseBody 时记录;请求体采集需开启 EnableRequestBody 并启用 EnableBuffering,读取后会重置流位置。
  • 仅采集 HttpMethods 中包含的方法(大小写不敏感)。

从配置文件绑定

{
  "Logging": {
    "Http": {
      "ConnectionString": "Server=localhost;Database=LogsDb;Trusted_Connection=True;TrustServerCertificate=True;",
      "Application": "MyWebApp",
      "TableName": "[dbo].[_Log_Http]",
      "PorcName": "[dbo].[_Log_Http_Append]",
      "SearchPorcName": "[dbo].[_Log_Http_Search]",
      "Key": "Logging.Http",
      "EnableRequest": true,
      "EnableResponse": false,
      "EnableHeaders": true,
      "EnableAgent": true,
      "EnableRequestBody": false,
      "EnableResponseBody": false,
      "RequestBodyLogLimit": 1048576,
      "ResponseBodyLogLimit": 1048576,
      "HttpMethods": ["GET", "POST", "PUT", "DELETE"]
    }
  }
}
builder.Services.AddLogging(logging =>
{
    logging.AddHttpLogging(o => builder.Configuration.GetSection("Logging:Http").Bind(o));
});
app.UseHttpAccessLogging();

HTTP 日志消息结构

HttpLoggingMessage 字段:

  • Application:应用名
  • Target:业务目标标识(如资源/路由标识),由 HttpLoggingOptions.GenerateTarget(HttpContext) 生成
  • Machine:机器名
  • SystemOs:操作系统信息
  • Method:HTTP 方法
  • Path:请求路径
  • IPAddress:客户端 IP(优先代理头)
  • Agent:User-Agent
  • Headers:请求/响应头(文本串,按“Key:Value,Key:Value”格式拼接)
  • Direction:RequestResponse
  • Content:请求或响应主体(受 EnableRequestBody/EnableResponseBody 与大小限制影响)
  • Propertys:键值对扩展存储;可通过 HttpLoggingOptions.GenerateProperties(HttpContext, IDictionary<string,string>) 添加自定义属性

数据库初始化(IHttpLoggingDatabaseBuilder)

  • 通过 IHttpLoggingDatabaseBuilder.Build() 生成建表与存储过程脚本(表:TableName;写入过程:PorcName;查询过程:SearchPorcName)。
  • HttpLoggingHostedService 中会根据当前选项调用数据库脚本构建器以初始化对象(若不存在)。
  • 生产建议:审阅并在变更流程中执行脚本,确保权限与索引优化。

客户端维护能力(IHttpLoggingClient)

在控制器或后台任务中注入使用:

app.MapGet("/logs/search", async (HttpLoggingClientFactory factory, string? path) =>
{
    var client = factory.CreateClient(); // 默认使用 Key=Logging.Http.SqlServer
    var result = await client.SearchAsync(new HttpLoggingSearchOptions
    {
        Path = path,
        PageIndex = 1,
        PageSize = 50
    });
    return Results.Ok(result);
});

app.MapPost("/logs/add", async (HttpLoggingClientFactory factory) =>
{
    var client = factory.CreateClient();
    await client.AddAsync(new HttpLoggingMessage
    {
        Application = "MyWebApp",
        Method = "POST",
        Path = "/logs/add",
        Direction = HttpDirection.Request,
        Content = "manual"
    });
    return Results.Ok();
});

app.MapDelete("/logs/{id:long}", async (HttpLoggingClientFactory factory, long id) =>
{
    var client = factory.CreateClient();
    var affected = await client.DeleteAsync(id);
    return Results.Ok(new { affected });
});

app.MapDelete("/logs", async (HttpLoggingClientFactory factory, DateTime? before) =>
{
    var client = factory.CreateClient();
    var affected = await client.DeleteAsync(new HttpLoggingSearchOptions { EndTime = before });
    return Results.Ok(new { affected });
});

app.MapPost("/logs/clear", async (HttpLoggingClientFactory factory) =>
{
    var client = factory.CreateClient();
    await client.ClearAsyc();
    return Results.Ok();
});
  • 解析客户端:var client = factory.CreateClient("Logging.Http"); 指定 Key 获取对应实例。
  • 查询过程:依赖 SearchPorcName 返回分页结果集。

参数配置详解(HttpLoggingOptions)

  • Key:实例隔离键。默认 Logging.Http
  • ConnectionString:SQL Server 连接串。
  • TableName:日志表名,默认 [dbo].[_Log_Http]
  • PorcName:写入存储过程名,默认 [dbo].[_Log_Http_Append]
  • SearchPorcName:查询存储过程名,默认 [dbo].[_Log_Http_Search]
  • Application:应用标识,默认 AppDomain.CurrentDomain.FriendlyName
  • EnableRequest:是否记录请求信息(默认 true)。
  • EnableResponse:是否记录响应信息(默认 false)。
  • EnableHeaders:是否记录头(默认 true)。
  • EnableAgent:是否记录 User-Agent(默认 true)。
  • EnableRequestBody:是否记录请求体(默认 false)。
  • EnableResponseBody:是否记录响应体(默认 false)。
  • RequestBodyLogLimit:请求体记录大小上限(默认 1MB)。
  • ResponseBodyLogLimit:响应体记录大小上限(默认 1MB)。
  • HttpMethods:需要采集的 HTTP 方法列表(大小写不敏感)。
  • GenerateTarget(HttpContext):生成 Target 业务标识的委托(可选)。
  • GenerateProperties(HttpContext, IDictionary<string,string>):添加自定义属性的委托(可选)。

表结构与存储过程约定

建议表结构(与默认处理器写入字段一致,含必要索引):

  • ID bigint identity primary key
  • Application nvarchar(128)
  • Machine nvarchar(128)
  • SystemOs nvarchar(256)
  • Method nvarchar(16)
  • Path nvarchar(1024)
  • IPAddress nvarchar(64)
  • Agent nvarchar(512) null
  • Headers nvarchar(max) null
  • Direction tinyint -- 0=Request,1=Response
  • Content nvarchar(max) null
  • Time datetime default(getdate())

写入过程 PorcName:入参与 HttpLoggingMessage 字段对应,插入一条记录。 查询过程 SearchPorcName:根据 HttpLoggingSearchOptions 支持模糊与时间范围,返回两个结果集(总数 + 当前页)。

注意:本库不强制自动建表/建过程,生产环境建议手工创建并做索引优化(Path/Time/Method/Application 等)。


进阶说明

  • 多实例:不同 Key 将创建独立 Channel、处理器与客户端;中间件解析指定 Key 的选项与资源。
  • 中间件顺序:务必在 UseRouting 之前调用 UseHttpAccessLogging,以捕获完整请求。
  • 连接重建:默认处理器在连接异常或连接串变化时自动重建 SqlConnection
  • Dapper 参数:向存储过程传参时建议使用匿名对象或 DynamicParameters,避免把 Propertys 等不需要的属性传入过程。
  • 性能建议:
    • 默认关闭消息体采集;在排障时短期打开并设置大小上限。
    • 高并发场景队列满会丢弃最旧日志,需结合业务容忍度评估并可根据源码调整策略。
    • 分库或分表可降低单表压力。

常见问题(FAQ)

  1. 中间件未生效?确保已调用 app.UseHttpAccessLogging() 且顺序在 UseRouting() 前。
  2. 无法写入 SQL?检查连接串、过程名、权限与过程参数是否一致。
  3. 如何按环境隔离?使用不同的 Key、不同的表/过程或数据库。
  4. 客户端真实 IP 异常?确认代理头是否正确传递(X-Forwarded-For 等)。
  5. 是否支持 .NET 8/10?项目目标为 .NET 8,可在更高版本运行。

许可证

版权所有 © netor.me 本项目遵循 MIT 协议。


联系方式

Showing the top 20 packages that depend on Microsoft.Extensions.Logging.HttpLogging.

Packages Downloads
Microsoft.Extensions.Logging.Operates
将操作日志记录到数据库,支持高并发缓冲与后台批量入库。自动建表与存储过程,轻松实现集中日志持久化与查询分析。
3

2025年11月30日 - 新增agent搜索 2025年12月1日 - 新增自定义扩展 2025年12月1日 - 新增记录httpmethod的筛选配置 2025年12月3日 - 重构可以通过 key 隔离 多个实列 - 可以单独使用 AddHttpLoggingClient 只集成客户端 - 自定义指定客户端 - 去掉过度包装的 key 隔离 多个实列 2025年12月4日 - 修复部分bug

Version Downloads Last updated
1.1.6 9 12/04/2025
1.1.5 3 12/04/2025
1.1.3 3 12/04/2025
1.1.2 3 12/04/2025
1.1.1 3 12/03/2025
1.1.0 3 12/03/2025
1.0.8 3 12/03/2025
1.0.6 2 12/03/2025
1.0.5 2 12/03/2025
1.0.3 2 12/03/2025
1.0.2 3 12/01/2025
1.0.1 3 11/30/2025
1.0.0 3 11/30/2025