Registro em log HTTP no ASP.NET Core
Observação
Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Aviso
Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, confira .NET e a Política de Suporte do .NET Core. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Importante
Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.
Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
O registro em log HTTP é um middleware que registra informações sobre a entrada de solicitações e respostas HTTP. O registro em log HTTP fornece logs de:
- Informações de solicitação HTTP
- Propriedades comuns
- Cabeçalhos
- Corpo
- Informações de resposta HTTP
O registro em log HTTP pode:
- Registre todas as solicitações e respostas ou apenas as solicitações e respostas que atendam a determinados critérios.
- Selecione quais partes da solicitação e da resposta são registradas em log.
- Permite que você exclua informações confidenciais dos logs.
O registro em log HTTP pode reduzir o desempenho de um aplicativo, especialmente ao registrar em log os corpos de solicitação e resposta. Considere o impacto sobre o desempenho ao selecionar campos para registrar. Teste o impacto sobre o desempenho das propriedades de log selecionadas.
Aviso
O registro em log HTTP pode registrar PII (informações de identificação pessoal). Considere o risco e evite registrar informações confidenciais.
Habilitar o registro em log HTTP
O registro em log HTTP é habilitado chamando AddHttpLogging e UseHttpLogging, conforme mostrado no exemplo a seguir:
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();
O lambda vazio no exemplo anterior de chamada AddHttpLogging
adiciona o middleware com a configuração padrão. Por padrão, o registro em log HTTP registra propriedades comuns, como caminho, código de status e cabeçalhos para solicitações e respostas.
Adicione a seguinte linha ao arquivo appsettings.Development.json
no nível "LogLevel": {
para que os logs HTTP sejam exibidos:
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
Com a configuração padrão, uma solicitação e resposta é registrada como um par de mensagens semelhante ao exemplo a seguir:
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; charset=utf-8
Date: Tue, 24 Oct 2023 02:03:53 GMT
Server: Kestrel
Opções de registro em log HTTP
Para configurar opções globais para o middleware de registro em log HTTP, chame AddHttpLogging em Program.cs
, usando o lambda para configurar 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();
Observação
No exemplo anterior e nos exemplos a seguir, UseHttpLogging
é chamado após UseStaticFiles
, portanto, o registro em log HTTP não está habilitado para arquivos estáticos. Para habilitar o log HTTP do arquivo estático, chame UseHttpLogging
antes de UseStaticFiles
.
LoggingFields
HttpLoggingOptions.LoggingFields
é um sinalizador de enumeração que configura partes específicas da solicitação e da resposta para registrar. HttpLoggingOptions.LoggingFields
usa como padrão RequestPropertiesAndHeaders | ResponsePropertiesAndHeaders.
RequestHeaders
e ResponseHeaders
RequestHeaders e ResponseHeaders são conjuntos de cabeçalhos HTTP registrados. Os valores de cabeçalho são registrados apenas para nomes de cabeçalho que estão nestas coleções. O código a seguir adiciona sec-ch-ua
ao RequestHeaders, para que o valor do cabeçalho sec-ch-ua
seja registrado. O código a seguir adiciona MyResponseHeader
ao ResponseHeaders, para que o valor do cabeçalho MyResponseHeader
seja registrado. Se essas linhas forem removidas, os valores desses cabeçalhos serão [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 fornece configuração para selecionar qual codificação usar para um tipo de mídia específico.
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();
Essa abordagem também pode ser usada para habilitar o registro em log de dados que não são registrados por padrão (por exemplo, dados de formulário, que podem ter um tipo de mídia como application/x-www-form-urlencoded
ou multipart/form-data
).
Métodos MediaTypeOptions
RequestBodyLogLimit
e 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
Definir CombineLogs como true
configura o middleware para consolidar todos os seus logs habilitados para uma solicitação e resposta em um único log no final. Isso inclui a solicitação, o corpo da solicitação, a resposta, o corpo da resposta e a duração.
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();
Configuração específica do ponto de extremidade
Para configuração específica de ponto de extremidade em aplicativos de API mínimos, um método de extensão WithHttpLogging está disponível. O exemplo a seguir mostra como configurar o registro em log HTTP para um ponto de extremidade:
app.MapGet("/response", () => "Hello World! (logging response)")
.WithHttpLogging(HttpLoggingFields.ResponsePropertiesAndHeaders);
Para a configuração específica de ponto de extremidade em aplicativos que usam controladores, o atributo [HttpLogging]
está disponível. O atributo também pode ser usado em aplicativos de API mínimos, conforme mostrado no exemplo a seguir:
app.MapGet("/duration", [HttpLogging(loggingFields: HttpLoggingFields.Duration)]
() => "Hello World! (logging duration)");
IHttpLoggingInterceptor
IHttpLoggingInterceptor é a interface de um serviço que pode ser implementado para lidar com retornos de chamada por solicitação e por resposta para personalizar quais detalhes são registrados. As configurações de log específicas do ponto de extremidade são aplicadas primeiro e podem ser substituídas nesses retornos de chamada. Uma implementação pode:
- Inspecione uma solicitação ou resposta.
- Habilite ou desabilite qualquer HttpLoggingFields.
- Ajuste a quantidade de logs do corpo de solicitação ou resposta.
- Adicione campos personalizados aos logs.
Registre uma implementação IHttpLoggingInterceptor
chamando AddHttpLoggingInterceptor<T>
em Program.cs
. Se várias instâncias IHttpLoggingInterceptor
forem registradas, elas serão executadas na ordem registrada.
O exemplo a seguir mostra como registrar uma implementação IHttpLoggingInterceptor
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.Duration;
});
builder.Services.AddHttpLoggingInterceptor<SampleHttpLoggingInterceptor>();
O exemplo a seguir é uma implementação IHttpLoggingInterceptor
que:
- Inspeciona o método de solicitação e desabilita o registro em log para solicitações POST.
- Para solicitações não POST:
- Reduz o caminho da solicitação, os cabeçalhos da solicitação e os cabeçalhos da resposta.
- Adiciona campos personalizados e valores de campo aos logs de solicitação e resposta.
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");
}
}
Com esse interceptador, uma solicitação POST não gera nenhum log, mesmo que o registro em log HTTP esteja configurado para registrar HttpLoggingFields.All
. Uma solicitação GET gera registros semelhantes ao exemplo a seguir:
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
Ordem de precedência da configuração de registro em log
A lista a seguir mostra a ordem de precedência da configuração de registro em log:
- Configuração global de HttpLoggingOptions, definida pela chamada de AddHttpLogging.
- A configuração específica do ponto de extremidade do atributo
[HttpLogging]
ou do método de extensão WithHttpLogging substitui a configuração global. IHttpLoggingInterceptor
é chamado com os resultados e pode modificar ainda mais a configuração por solicitação.
O Registro em Log HTTP é um middleware que registra informações sobre a entrada de solicitações HTTP e respostas HTTP. O registro em log HTTP fornece logs de:
- Informações de solicitação HTTP
- Propriedades comuns
- Cabeçalhos
- Corpo
- Informações de resposta HTTP
O registro em log HTTP é útil em vários cenários para:
- Registrar informações sobre solicitações e respostas de entrada.
- Filtrar quais partes da solicitação e da resposta são registradas.
- Filtrar quais cabeçalhos registrar.
O registro em log HTTP pode reduzir o desempenho de um aplicativo, especialmente ao registrar em log os corpos de solicitação e resposta. Considere o impacto sobre o desempenho ao selecionar campos para registrar. Teste o impacto sobre o desempenho das propriedades de log selecionadas.
Aviso
O registro em log HTTP pode registrar PII (informações de identificação pessoal). Considere o risco e evite registrar informações confidenciais.
Habilitando o registro em log HTTP
O registro em log HTTP é habilitado com UseHttpLogging, que adiciona o middleware de registro em log 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();
Por padrão, o registro em log HTTP registra propriedades comuns, como caminho, código de status e cabeçalhos, para solicitações e respostas. Adicione a seguinte linha ao arquivo appsettings.Development.json
no nível "LogLevel": {
para que os logs HTTP sejam exibidos:
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
A saída é registrada como uma mensagem em LogLevel.Information
.
Opções de registro em log HTTP
Para configurar o middleware de registro em log HTTP, chame AddHttpLogging em Program.cs
.
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();
Observação
No exemplo anterior e nos exemplos a seguir, UseHttpLogging
é chamado após UseStaticFiles
, portanto, o registro em log HTTP não está habilitado para arquivo estático. Para habilitar o log HTTP do arquivo estático, chame UseHttpLogging
antes de UseStaticFiles
.
LoggingFields
HttpLoggingOptions.LoggingFields
é um sinalizador de enumeração que configura partes específicas da solicitação e da resposta para registrar. HttpLoggingOptions.LoggingFields
usa como padrão RequestPropertiesAndHeaders | ResponsePropertiesAndHeaders.
RequestHeaders
Headers são um conjunto de cabeçalhos de solicitação HTTP que têm permissão para ser registrados. Os valores de cabeçalho são registrados apenas para nomes de cabeçalho que estão nesta coleção. O código a seguir registra o cabeçalho de solicitação "sec-ch-ua"
. Se logging.RequestHeaders.Add("sec-ch-ua");
for removido, o valor do cabeçalho da solicitação "sec-ch-ua"
será redigido. O seguinte código realçado chama HttpLoggingOptions.RequestHeaders
e 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 fornece configuração para selecionar qual codificação usar para um tipo de mídia específico.
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();
Essa abordagem também pode ser usada para habilitar o registro em log de dados que não são registrados por padrão. Por exemplo, dados de formulário, que podem ter um tipo de mídia como application/x-www-form-urlencoded
ou multipart/form-data
.
Métodos MediaTypeOptions
RequestBodyLogLimit
e 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();