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.