.NET Core 和 ASP.NET Core 中的 HTTP 日志记录

您所在的位置:网站首页 日志中的host .NET Core 和 ASP.NET Core 中的 HTTP 日志记录

.NET Core 和 ASP.NET Core 中的 HTTP 日志记录

#.NET Core 和 ASP.NET Core 中的 HTTP 日志记录 | 来源: 网络整理| 查看: 265

ASP.NET Core 中的 HTTP 日志记录 项目 10/30/2023

注意

此版本不是本文的最新版本。 对于当前版本,请参阅本文的 .NET 7 版本。

重要事项

此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。

对于当前版本,请参阅本文的 .NET 7 版本。

HTTP 日志记录是一种中间件,用于记录传入 HTTP 请求和 HTTP 响应的相关信息。 HTTP 日志记录可以记录:

HTTP 请求信息 公共属性 标头 正文 HTTP 响应信息

HTTP 日志记录可以:

记录所有请求和响应,或者仅记录满足特定条件的请求和响应。 选择要记录请求和响应的哪些部分。 支持修订日志中的敏感信息。

HTTP 日志记录可能会降低应用的性能,尤其是在记录请求和响应正文时。 在选择要记录的字段时请考虑性能影响。 测试所选日志记录属性的性能影响。

警告

HTTP 日志记录可能会记录个人身份信息 (PII)。 请考虑风险,并避免记录敏感信息。

启用 HTTP 日志记录

HTTP 日志记录通过调用 AddHttpLogging 和 UseHttpLogging 来调用,如以下示例所示:

var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpLogging(o => { }); var app = builder.Build(); app.UseHttpLogging(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.MapGet("/", () => "Hello World!"); app.Run();

上述调用 AddHttpLogging 的示例中的空 Lambda 添加具有默认配置的中间件。 默认情况下,HTTP 日志记录会记录路径、状态代码、请求头和响应头等常用属性。

将以下行添加到 "LogLevel": { 级别的 appsettings.Development.json 文件,以便显示 HTTP 日志:

"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"

如果使用默认配置,请求和响应将记录为一对消息,与以下示例类似:

info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1] Request: Protocol: HTTP/2 Method: GET Scheme: https PathBase: Path: / Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Host: localhost:52941 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.61 Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Upgrade-Insecure-Requests: [Redacted] sec-ch-ua: [Redacted] sec-ch-ua-mobile: [Redacted] sec-ch-ua-platform: [Redacted] sec-fetch-site: [Redacted] sec-fetch-mode: [Redacted] sec-fetch-user: [Redacted] sec-fetch-dest: [Redacted] info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2] Response: StatusCode: 200 Content-Type: text/plain; Date: Tue, 24 Oct 2023 02:03:53 GMT Server: Kestrel HTTP 日志记录选项

若要配置 HTTP 日志记录中间件的全局选项,请调用 Program.cs 中的 AddHttpLogging,使用 Lambda 来配置 HttpLoggingOptions。

using Microsoft.AspNetCore.HttpLogging; var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpLogging(logging => { logging.LoggingFields = HttpLoggingFields.All; logging.RequestHeaders.Add("sec-ch-ua"); logging.ResponseHeaders.Add("MyResponseHeader"); logging.MediaTypeOptions.AddText("application/javascript"); logging.RequestBodyLogLimit = 4096; logging.ResponseBodyLogLimit = 4096; logging.CombineLogs = true; }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseHttpLogging(); app.Use(async (context, next) => { context.Response.Headers["MyResponseHeader"] = new string[] { "My Response Header Value" }; await next(); }); app.MapGet("/", () => "Hello World!"); app.Run();

注意

在上述示例和下面的示例中,UseHttpLogging 在 UseStaticFiles 之后调用,因此没有为静态文件启用 HTTP 日志记录。 要启用静态文件 HTTP 日志记录,请在 UseStaticFiles 之前调用 UseHttpLogging。

LoggingFields

HttpLoggingOptions.LoggingFields 是一个枚举标志,用于配置要记录的请求和响应的特定部分。 HttpLoggingOptions.LoggingFields 默认为 RequestPropertiesAndHeaders | ResponsePropertiesAndHeaders。

RequestHeaders 和 ResponseHeaders

RequestHeaders 和 ResponseHeaders 是记录的 HTTP 标头集。 只记录这些集合中的标头名称的标头值。 以下代码将 sec-ch-ua 添加到 RequestHeaders 中,因此会记录 sec-ch-ua 标头的值。 并且它将 MyResponseHeader 添加到 ResponseHeaders 中,因此会记录 MyResponseHeader 标头的值。 如果删除了这些行,则这些标头的值是 [Redacted]。

using Microsoft.AspNetCore.HttpLogging; var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpLogging(logging => { logging.LoggingFields = HttpLoggingFields.All; logging.RequestHeaders.Add("sec-ch-ua"); logging.ResponseHeaders.Add("MyResponseHeader"); logging.MediaTypeOptions.AddText("application/javascript"); logging.RequestBodyLogLimit = 4096; logging.ResponseBodyLogLimit = 4096; logging.CombineLogs = true; }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseHttpLogging(); app.Use(async (context, next) => { context.Response.Headers["MyResponseHeader"] = new string[] { "My Response Header Value" }; await next(); }); app.MapGet("/", () => "Hello World!"); app.Run(); MediaTypeOptions

MediaTypeOptions 提供了选择要用于特定媒体类型的编码的配置。

using Microsoft.AspNetCore.HttpLogging; var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpLogging(logging => { logging.LoggingFields = HttpLoggingFields.All; logging.RequestHeaders.Add("sec-ch-ua"); logging.ResponseHeaders.Add("MyResponseHeader"); logging.MediaTypeOptions.AddText("application/javascript"); logging.RequestBodyLogLimit = 4096; logging.ResponseBodyLogLimit = 4096; logging.CombineLogs = true; }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseHttpLogging(); app.Use(async (context, next) => { context.Response.Headers["MyResponseHeader"] = new string[] { "My Response Header Value" }; await next(); }); app.MapGet("/", () => "Hello World!"); app.Run();

此方法也可用于为在默认情况下未记录的数据启用日志记录(例如表单数据,其可能具有 application/x-www-form-urlencoded 或 multipart/form-data 等媒体类型)。

MediaTypeOptions 方法 AddText AddBinary Clear RequestBodyLogLimit 和 ResponseBodyLogLimit RequestBodyLogLimit ResponseBodyLogLimit using Microsoft.AspNetCore.HttpLogging; var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpLogging(logging => { logging.LoggingFields = HttpLoggingFields.All; logging.RequestHeaders.Add("sec-ch-ua"); logging.ResponseHeaders.Add("MyResponseHeader"); logging.MediaTypeOptions.AddText("application/javascript"); logging.RequestBodyLogLimit = 4096; logging.ResponseBodyLogLimit = 4096; logging.CombineLogs = true; }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseHttpLogging(); app.Use(async (context, next) => { context.Response.Headers["MyResponseHeader"] = new string[] { "My Response Header Value" }; await next(); }); app.MapGet("/", () => "Hello World!"); app.Run(); CombineLogs

将 CombineLogs 设置为 true 会配置中间件,使其在最后将请求和响应所有已启用的日志合并到一个日志中。 这包括请求、请求正文、响应、响应正文和持续时间。

using Microsoft.AspNetCore.HttpLogging; var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpLogging(logging => { logging.LoggingFields = HttpLoggingFields.All; logging.RequestHeaders.Add("sec-ch-ua"); logging.ResponseHeaders.Add("MyResponseHeader"); logging.MediaTypeOptions.AddText("application/javascript"); logging.RequestBodyLogLimit = 4096; logging.ResponseBodyLogLimit = 4096; logging.CombineLogs = true; }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseHttpLogging(); app.Use(async (context, next) => { context.Response.Headers["MyResponseHeader"] = new string[] { "My Response Header Value" }; await next(); }); app.MapGet("/", () => "Hello World!"); app.Run(); 特定于终结点的配置

对于最小 API 应用中特定于终结点的配置,可使用 WithHttpLogging 扩展方法。 以下示例演示如何为一个终结点配置 HTTP 日志记录:

app.MapGet("/response", () => "Hello World! (logging response)") .WithHttpLogging(HttpLoggingFields.ResponsePropertiesAndHeaders);

对于使用控制器的应用中特定于终结点的配置,可使用 [HttpLogging] 属性。 还可在最小 API 应用中使用该属性,如以下示例所示:

app.MapGet("/duration", [HttpLogging(loggingFields: HttpLoggingFields.Duration)] () => "Hello World! (logging duration)"); IHttpLoggingInterceptor

IHttpLoggingInterceptor 是服务的接口,可实现它来处理每请求和每响应回调,从而自定义记录的详细信息。 首先应用任何特定于终结点的日志设置,然后可在这些回调中替代它们。 实现可以:

检查请求或响应。 启用或禁用任何 HttpLoggingFields。 调整记录的请求或响应正文量。 将自定义字段添加到日志。

通过调用 Program.cs 中的 AddHttpLoggingInterceptor 来注册 IHttpLoggingInterceptor 实现。 如果注册了多个 IHttpLoggingInterceptor 实例,会按注册的顺序运行这些实例。

以下示例显示如何注册 IHttpLoggingInterceptor 实现:

var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpLogging(logging => { logging.LoggingFields = HttpLoggingFields.Duration; }); builder.Services.AddHttpLoggingInterceptor();

以下示例是一个 IHttpLoggingInterceptor 实现,它执行以下操作:

检查请求方法并禁用 POST 请求的日志记录。 对于非 POST 请求: 修订请求路径、请求头和响应头。 将自定义字段和字段值添加到请求和响应日志。 using Microsoft.AspNetCore.HttpLogging; namespace HttpLoggingSample; internal sealed class SampleHttpLoggingInterceptor : IHttpLoggingInterceptor { public ValueTask OnRequestAsync(HttpLoggingInterceptorContext logContext) { if (logContext.HttpContext.Request.Method == "POST") { // Don't log anything if the request is a POST. logContext.LoggingFields = HttpLoggingFields.None; } // Don't enrich if we're not going to log any part of the request. if (!logContext.IsAnyEnabled(HttpLoggingFields.Request)) { return default; } if (logContext.TryDisable(HttpLoggingFields.RequestPath)) { RedactPath(logContext); } if (logContext.TryDisable(HttpLoggingFields.RequestHeaders)) { RedactRequestHeaders(logContext); } EnrichRequest(logContext); return default; } public ValueTask OnResponseAsync(HttpLoggingInterceptorContext logContext) { // Don't enrich if we're not going to log any part of the response if (!logContext.IsAnyEnabled(HttpLoggingFields.Response)) { return default; } if (logContext.TryDisable(HttpLoggingFields.ResponseHeaders)) { RedactResponseHeaders(logContext); } EnrichResponse(logContext); return default; } private void RedactPath(HttpLoggingInterceptorContext logContext) { logContext.AddParameter(nameof(logContext.HttpContext.Request.Path), "RedactedPath"); } private void RedactRequestHeaders(HttpLoggingInterceptorContext logContext) { foreach (var header in logContext.HttpContext.Request.Headers) { logContext.AddParameter(header.Key, "RedactedHeader"); } } private void EnrichRequest(HttpLoggingInterceptorContext logContext) { logContext.AddParameter("RequestEnrichment", "Stuff"); } private void RedactResponseHeaders(HttpLoggingInterceptorContext logContext) { foreach (var header in logContext.HttpContext.Response.Headers) { logContext.AddParameter(header.Key, "RedactedHeader"); } } private void EnrichResponse(HttpLoggingInterceptorContext logContext) { logContext.AddParameter("ResponseEnrichment", "Stuff"); } }

使用此侦听器时,即使 HTTP 日志记录配置为记录 HttpLoggingFields.All,POST 请求也不会生成任何日志。 GET 请求生成类似于以下示例的日志:

info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1] Request: Path: RedactedPath Accept: RedactedHeader Host: RedactedHeader User-Agent: RedactedHeader Accept-Encoding: RedactedHeader Accept-Language: RedactedHeader Upgrade-Insecure-Requests: RedactedHeader sec-ch-ua: RedactedHeader sec-ch-ua-mobile: RedactedHeader sec-ch-ua-platform: RedactedHeader sec-fetch-site: RedactedHeader sec-fetch-mode: RedactedHeader sec-fetch-user: RedactedHeader sec-fetch-dest: RedactedHeader RequestEnrichment: Stuff Protocol: HTTP/2 Method: GET Scheme: https info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2] Response: Content-Type: RedactedHeader MyResponseHeader: RedactedHeader ResponseEnrichment: Stuff StatusCode: 200 info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[4] ResponseBody: Hello World! info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[8] Duration: 2.2778ms 日志记录配置优先级顺序

以下列表显示了日志记录配置的优先级顺序:

HttpLoggingOptions 中的全局配置,通过调用 AddHttpLogging 来设置。 [HttpLogging] 属性或 WithHttpLogging 扩展方法中特定于终结点的配置会替代全局配置。 IHttpLoggingInterceptor 使用结果进行调用,并且可进一步修改每个请求的配置。

HTTP 日志记录是一种中间件,用于记录传入 HTTP 请求和 HTTP 响应的相关信息。 HTTP 日志记录可以记录:

HTTP 请求信息 公共属性 标头 正文 HTTP 响应信息

在以下几种方案中,HTTP 日志记录很有价值:

记录传入请求和响应的相关信息。 筛选请求和响应的哪些部分被记录。 筛选要记录的头。

HTTP 日志记录可能会降低应用的性能,尤其是在记录请求和响应正文时。 在选择要记录的字段时请考虑性能影响。 测试所选日志记录属性的性能影响。

警告

HTTP 日志记录可能会记录个人身份信息 (PII)。 请考虑风险,并避免记录敏感信息。

启用 HTTP 日志记录

HTTP 日志记录是通过 UseHttpLogging 启用,它添加了 HTTP 日志记录中间件。

var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.UseHttpLogging(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.MapGet("/", () => "Hello World!"); app.Run();

HTTP 日志记录默认记录路径、状态代码以及请求头和响应头等常用属性。 将以下行添加到 "LogLevel": { 级别的 appsettings.Development.json 文件,以便显示 HTTP 日志:

"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"

输出作为单条消息记录在 LogLevel.Information 上。

HTTP 日志记录选项

若要配置 HTTP 日志记录中间件,请在 Program.cs 中调用 AddHttpLogging。

using Microsoft.AspNetCore.HttpLogging; var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpLogging(logging => { logging.LoggingFields = HttpLoggingFields.All; logging.RequestHeaders.Add("sec-ch-ua"); logging.ResponseHeaders.Add("MyResponseHeader"); logging.MediaTypeOptions.AddText("application/javascript"); logging.RequestBodyLogLimit = 4096; logging.ResponseBodyLogLimit = 4096; }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseHttpLogging(); app.Use(async (context, next) => { context.Response.Headers["MyResponseHeader"] = new string[] { "My Response Header Value" }; await next(); }); app.MapGet("/", () => "Hello World!"); app.Run();

注意

在前面的示例和以下示例中,UseHttpLogging 在 UseStaticFiles 之后调用,因此没有为静态文件启用 HTTP 日志记录。 要启用静态文件 HTTP 日志记录,请在 UseStaticFiles 之前调用 UseHttpLogging。

LoggingFields

HttpLoggingOptions.LoggingFields 是一个枚举标志,用于配置要记录的请求和响应的特定部分。 HttpLoggingOptions.LoggingFields 默认为 RequestPropertiesAndHeaders | ResponsePropertiesAndHeaders。

RequestHeaders

Headers 是一组可以记录的 HTTP 请求头。 只记录此集合中的头名称的头值。 以下代码记录请求头 "sec-ch-ua"。 如果删除 logging.RequestHeaders.Add("sec-ch-ua");,则修订请求头 "sec-ch-ua" 的值。 以下突出显示的代码调用 HttpLoggingOptions.RequestHeaders 和 HttpLoggingOptions.ResponseHeaders:

using Microsoft.AspNetCore.HttpLogging; var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpLogging(logging => { logging.LoggingFields = HttpLoggingFields.All; logging.RequestHeaders.Add("sec-ch-ua"); logging.ResponseHeaders.Add("MyResponseHeader"); logging.MediaTypeOptions.AddText("application/javascript"); logging.RequestBodyLogLimit = 4096; logging.ResponseBodyLogLimit = 4096; }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseHttpLogging(); app.Use(async (context, next) => { context.Response.Headers["MyResponseHeader"] = new string[] { "My Response Header Value" }; await next(); }); app.MapGet("/", () => "Hello World!"); app.Run(); MediaTypeOptions

MediaTypeOptions 提供了选择要用于特定媒体类型的编码的配置。

using Microsoft.AspNetCore.HttpLogging; var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpLogging(logging => { logging.LoggingFields = HttpLoggingFields.All; logging.RequestHeaders.Add("sec-ch-ua"); logging.ResponseHeaders.Add("MyResponseHeader"); logging.MediaTypeOptions.AddText("application/javascript"); logging.RequestBodyLogLimit = 4096; logging.ResponseBodyLogLimit = 4096; }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseHttpLogging(); app.Use(async (context, next) => { context.Response.Headers["MyResponseHeader"] = new string[] { "My Response Header Value" }; await next(); }); app.MapGet("/", () => "Hello World!"); app.Run();

此方法也可用于为默认未记录的数据启用日志记录(例如表单数据,其媒体类型可能为 application/x-www-form-urlencoded 或 multipart/form-data)。

MediaTypeOptions 方法 AddText AddBinary Clear RequestBodyLogLimit 和 ResponseBodyLogLimit RequestBodyLogLimit ResponseBodyLogLimit using Microsoft.AspNetCore.HttpLogging; var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpLogging(logging => { logging.LoggingFields = HttpLoggingFields.All; logging.RequestHeaders.Add("sec-ch-ua"); logging.ResponseHeaders.Add("MyResponseHeader"); logging.MediaTypeOptions.AddText("application/javascript"); logging.RequestBodyLogLimit = 4096; logging.ResponseBodyLogLimit = 4096; }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseHttpLogging(); app.Use(async (context, next) => { context.Response.Headers["MyResponseHeader"] = new string[] { "My Response Header Value" }; await next(); }); app.MapGet("/", () => "Hello World!"); app.Run();


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3