The Ultimate Guide to HTTP Logging in ASP.NET Core: From Basic Configuration to Sensitive Data Redaction Practices

Logging HTTP requests and responses can help developers quickly troubleshoot issues, monitor performance, and audit user behavior. ASP.NET Core provides out-of-the-box support through the built-in <span>HttpLogging</span> middleware, which you can flexibly configure and extend according to your needs.

This article covers in-depth: 🔹 Enabling and configuring HTTP logging in ASP.NET Core projects 🔹 Detailed explanation of logging options and settings 🔹 Custom logging and endpoint-level configuration 🔹 Sensitive data redaction techniques 🔹 Logging requests and responses made by <span>HttpClient</span>.

Visit my website for best practices in .NET and architecture Subscribe to my newsletter to enhance your .NET skills

Step 1: Enable HttpLogging

Just two simple steps:

1️⃣ Add middleware in Program.cs:

var builder = WebApplication.CreateBuilder(args);

// Enable HTTP logging service
builder.Services.AddHttpLogging(options =>
{
    options.LoggingFields = HttpLoggingFields.Request | HttpLoggingFields.Response;
});

var app = builder.Build();

// Add to HTTP request pipeline
app.UseHttpLogging();

app.Run();

2️⃣ Adjust logging level in appsettings.json:

{
  "Logging":{
    "LogLevel":{
      "Default":"Information",
      "Microsoft.AspNetCore":"Warning",
      "Microsoft.AspNetCore.Hosting.Diagnostics":"Warning",
      "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware":"Information"
    }
  }
}

Example Output:

info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1]
      Request:
      Protocol: HTTP/1.1
      Method: GET
      Scheme: https
      PathBase: 
      Path: /
      Headers:
        Host: localhost:5001
        User-Agent: Mozilla/5.0...
      Response:
      StatusCode: 200
      Headers:
        Content-Type: text/plain; charset=utf-8

⚙️ Advanced Configuration Tips

Custom Logging Fields

builder.Services.AddHttpLogging(options =>
{
    options.LoggingFields = 
        HttpLoggingFields.RequestMethod |
        HttpLoggingFields.RequestPath |
        HttpLoggingFields.RequestQuery |
        HttpLoggingFields.RequestHeaders |
        HttpLoggingFields.ResponseStatusCode |
        HttpLoggingFields.Duration;
});

Limit Recorded Headers

builder.Services.AddHttpLogging(options =>
{
    options.RequestHeaders.Add("X-API-Version");
    options.RequestHeaders.Add("User-Agent");
    options.ResponseHeaders.Add("Content-Type");
});

Environment-Specific Configuration

builder.Services.AddHttpLogging(options =>
{
    // Basic configuration
    options.LoggingFields = ...;
    
    // Log request/response bodies in development environment
    if (builder.Environment.IsDevelopment())
    {
        options.LoggingFields |= HttpLoggingFields.RequestBody | HttpLoggingFields.ResponseBody;
        options.RequestBodyLogLimit = 1024 * 32; // 32 KB
        options.ResponseBodyLogLimit = 1024 * 32;
    }
});

🛠️ Custom Logging with Interceptors

public class CustomLoggingInterceptor : IHttpLoggingInterceptor
{
    public ValueTask OnRequestAsync(HttpLoggingInterceptorContext context)
    {
        // Dynamically remove sensitive headers
        context.HttpContext.Request.Headers.Remove("X-API-Key");
        
        // Add tracking ID
        context.AddParameter("RequestId", Guid.NewGuid().ToString());
        return ValueTask.CompletedTask;
    }

    public ValueTask OnResponseAsync(HttpLoggingInterceptorContext context)
    {
        // Remove sensitive headers like Set-Cookie
        context.HttpContext.Response.Headers.Remove("Set-Cookie");
        return ValueTask.CompletedTask;
    }
}

// Register interceptor
builder.Services.AddSingleton<IHttpLoggingInterceptor, CustomLoggingInterceptor>();

🔐 Endpoint-Level Logging Configuration

// Disable logging for specific endpoint
app.MapGet("/health", () => Results.Ok()).DisableHttpLogging();

// Custom endpoint logging behavior
app.MapPost("/api/orders", (OrderRequest request) => Results.Created())
   .WithHttpLogging(logging =>
   {
       logging.LoggingFields = HttpLoggingFields.RequestBody | HttpLoggingFields.ResponseStatusCode;
   });

🚫 Sensitive Data Redaction Practices

Why Redact?:

  • • Security Risks: Tokens/passwords in logs can lead to unauthorized access
  • • Compliance Requirements: Regulations like GDPR/HIPAA mandate protection of sensitive data
  • • User Trust: Protecting privacy is fundamental to gaining user trust

Solution:

public class SensitiveDataRedactionInterceptor : IHttpLoggingInterceptor
{
    public ValueTask OnRequestAsync(HttpLoggingInterceptorContext context)
    {
        // Redact path
        if (context.TryDisable(HttpLoggingFields.RequestPath))
            context.AddParameter("Path", "[REDACTED]");

        // Redact headers
        foreach (var header in context.HttpContext.Request.Headers)
            context.AddParameter(header.Key, "[REDACTED]");
        
        return ValueTask.CompletedTask;
    }
}

Example of Redacted Logs:

info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1]
      Request:
      Path: [REDACTED]
      Authorization: [REDACTED]
      Method: GET

⚡ Logging HttpClient Requests

public class HttpLoggingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken ct)
    {
        // Log request
        var traceId = Guid.NewGuid().ToString();
        _logger.LogDebug($"[REQUEST] {traceId}\n{request.Method}: {request.RequestUri}");

        // Execute request
        var response = await base.SendAsync(request, ct);

        // Log response
        _logger.LogDebug($"[RESPONSE] {traceId}\nStatus: {response.StatusCode}");
        return response;
    }
}

// Register with HttpClient
builder.Services.AddHttpClient<ITodoClient, TodoClient>()
    .AddHttpMessageHandler(provider => 
        new HttpLoggingHandler(provider.GetRequiredService<ILogger>()));

Example Output:

dbug: [REQUEST] 4d251738-5aeb-4342-824e-5d23ddf738a2
      GET: https://jsonplaceholder.typicode.com/todos/50
dbug: [RESPONSE] 4d251738-5aeb-4342-824e-5d23ddf738a2
      Status: 200 OK

Security Logging Best Practices Checklist

✅ Best Practices ❌ Dangerous Practices
Default exclusion of sensitive data Logging all headers and body
Enable detailed logging in development Log sensitive information in production
Use regular expressions for precise redaction Manually filter sensitive fields
Automated tests to validate redaction rules Assume logs won’t leak sensitive data
Enable request/response body logging as needed Log large bodies throughout

When the production alert rings at 3 AM, comprehensive HTTP logs will be your lifeline for troubleshooting. Follow this guide to build a logging system that is both robust and secure!

Recommended Reading:
Bury these 9 outdated design patterns! A modernization guide for .NET 10 + C#12
6 recommended open-source serial debugging tools based on .NET, a boost for debugging efficiency!
An enterprise-level permission development framework based on .NET 8+VUE
7 recommended open-source, free, and beautiful .NET Blazor UI component libraries
An open-source, free, lightweight, fast, cross-platform PDF reader based on .NET
A painful lesson! Still using DateTime.Now? Your code is silently crashing
Click the card below to follow DotNet NB

Let's learn and communicate together

▲ Click the card above to follow DotNet NB, let's learn and communicate together

Please reply in the public account backend
Reply with [Roadmap] to get the .NET 2024 developer roadmap
Reply with [Original Content] to get original content from the public account
Reply with [Summit Video] to get .NET Conf summit videos
Reply with [Personal Profile] to get the author's personal profile
Reply with [Year-End Summary] to get the author's year-end review
Reply with [Join Group] to join the DotNet NB learning group

Long press to recognize the QR code below, or click to read the original text. Let's communicate, learn, and share insights together.

Leave a Comment