Logging Inteligente de Requisições em APIs .NET — Captura Segura e Estruturada de Request Body
1. Contexto e Motivação
Em APIs modernas, o log de requisições é uma das ferramentas mais valiosas para observabilidade e diagnóstico.
Mas capturar o request body com segurança e eficiência é desafiador: o HttpContext.Request.Body é um stream forward-only, e a leitura incorreta pode:
- Quebrar o model binding;
- Causar vazamento de dados sensíveis (LGPD, PCI DSS, HIPAA…);
- Prejudicar performance e custo de armazenamento.
Este artigo apresenta uma implementação robusta e segura para registrar requisições — inclusive o corpo — com:
- Redação automática de dados sensíveis;
- Buffering eficiente e limite de tamanho;
- Suporte a logs estruturados e Serilog;
- Integração com middlewares de exceção e correlação.
2. Arquitetura de Logging
A solução é composta por dois middlewares complementares:
| Middleware | Responsabilidade | Fase |
|---|---|---|
RequestLoggingMiddleware | Captura e registra corpo, cabeçalhos e status | Sempre executado |
ExceptionMiddleware | Intercepta exceções, inclui corpo da requisição no log de erro | Executado apenas em falhas |
Essa separação segue o princípio Single Responsibility, garantindo clareza e extensibilidade.
3. Middleware de Logging de Requisição
O RequestLoggingMiddleware lê o corpo da requisição com EnableBuffering() e repassa o stream intacto ao pipeline:
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestLoggingMiddleware> _logger;
public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
var body = await RequestBodyReader.SafeReadAsync(context, 64 * 1024, new[] { "application/json" });
context.Items["__reqBody__"] = body.BodyForLog;
await _next(context);
_logger.LogInformation(
"HTTP {Method} {Status} {Path} | User={User} | Body={Body}",
context.Request.Method,
context.Response.StatusCode,
context.Request.Path,
context.User?.Identity?.Name ?? "anonymous",
body.BodyForLog);
}
}
4. Leitura Segura do Body
O helper RequestBodyReader garante que o conteúdo seja lido de forma segura e redigida:
public static class RequestBodyReader
{
public static async Task<(string BodyForLog, string RawBody)> SafeReadAsync(
HttpContext ctx, int maxBytes, string[] allowedContentTypes)
{
var req = ctx.Request;
if (!allowedContentTypes.Any(ct => req.ContentType?.StartsWith(ct, StringComparison.OrdinalIgnoreCase) == true))
return ("(body skipped: type not allowed)", "");
req.EnableBuffering();
using var mem = new MemoryStream();
await req.Body.CopyToAsync(mem);
var body = Encoding.UTF8.GetString(mem.ToArray());
req.Body.Position = 0;
return (Redact(body), body);
}
private static string Redact(string body)
{
var sensitive = new[] { "password", "token", "secret", "cpf" };
foreach (var key in sensitive)
body = body.Replace(key, "***redacted***", StringComparison.OrdinalIgnoreCase);
return body;
}
}
5. Middleware de Exceção Integrado
O ExceptionMiddleware aproveita o body já lido pelo middleware anterior, sem custo extra:
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ExceptionMiddleware> _logger;
public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
var body = context.Items["__reqBody__"] as string ?? "(unavailable)";
_logger.LogError(ex, "Unhandled exception: {Method} {Url} | Body={Body}",
context.Request.Method,
context.Request.Path,
body);
context.Response.StatusCode = 500;
await context.Response.WriteAsJsonAsync(new { error = "Server Error" });
}
}
}
6. Registro no Pipeline
app.UseMiddleware<RequestLoggingMiddleware>();
app.UseMiddleware<ExceptionMiddleware>();
app.UseRouting();
app.MapControllers();
7. Conformidade e Segurança
A implementação atende recomendações de:
- ISO 27001 A.12.4.1 – Registro de eventos de auditoria;
- SOC 2 CC7.2 – Detecção de falhas e evidência de eventos;
- NIST CSF DE.AE-3 – Logging e análise de anomalias;
- LGPD Art. 46 – Proteção de dados sensíveis e anonimização.
Medidas adotadas:
- Redação de campos sensíveis (
password,token, etc.); - Tamanho máximo de corpo (
maxBytes); - Exclusão de uploads (
multipart/form-data); - Amostragem controlada (
SampleRate); - Logs estruturados (compatíveis com Serilog/Elastic).
8. Extensões Possíveis
- Response Logging: captura do corpo de resposta para debugging avançado;
- Correlation ID Middleware: para rastrear requisições ponta a ponta;
- Contexto de Usuário (Claims): inclusão de
UserIdouTenantId; - Exportação para Elastic + Kibana: análise visual e alertas automáticos.
9. Conclusão
Com essa arquitetura, é possível atingir observabilidade de nível enterprise sem comprometer segurança ou performance.
O segredo está no equilíbrio: capturar o que é essencial, mascarar o que é sensível, e registrar o suficiente para diagnosticar qualquer incidente.
