I have a requirement for creating Request/Response Logging. I am using default Logger implementation of Microsoft.
//Add Http Logging
builder.Services.AddHttpLogging(options =>
{
options.CombineLogs = true;
options.LoggingFields = HttpLoggingFields.RequestQuery | HttpLoggingFields.RequestPath |
HttpLoggingFields.RequestBody | HttpLoggingFields.ResponseStatusCode | HttpLoggingFields.Duration;
});
//Using Middleware
app.UseHttpLogging();
In my appSettings.json file:
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
}
}
My issue is the default Log format of HTTP logging Middleware. This is what printed on my console:
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[9]
Request and Response:
PathBase:
Path: /api/film/rating
QueryString:
StatusCode: 200
RequestBody: {
"title": "G K Mon",
"rating": "G"
}
RequestBodyStatus: [Completed]
Duration: 1595.698
Can I customize this default log format of HTTP Logging Middleware? Additional question is that how should I store logs in file without using Third party library.
/a/68363461/22971430
HttpLogging has pre-defined format/order and doesn’t have a built-in way to change. You could try implement a custom loggerProvider to modify the logmessage before log and then write to a file.
Reformat the logMessage before output.
public class CustomHttpLogger : ILogger
{
private readonly string _filePath;
public CustomHttpLogger(string filePath)
{
_filePath = filePath;
}
public IDisposable BeginScope<TState>(TState state) => null;
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
var logMessage = formatter(state, exception);
if (eventId.Name == "RequestResponseLog")
{
// Example: Reorder fields manually (string manipulation, regex, etc.)
string reorderedLogMessage = ReorderLogFields(logMessage);
// Output the reordered log message , if you use console without clearproviders you will find the default provider also logging.
//Console.WriteLine(reorderedLogMessage);
File.AppendAllText(_filePath, reorderedLogMessage);
}
//else
//{
// Console.WriteLine(logMessage);
//}
}
private string ReorderLogFields(string logMessage)
{
var messages=logMessage.Split("rn");
string newMessage = "";
newMessage += messages.FirstOrDefault(x => x.StartsWith("QueryString")) + "rn";
newMessage += messages.FirstOrDefault(x => x.StartsWith("PathBase"))+ "rn";
newMessage += messages.FirstOrDefault(x => x.StartsWith("RequestBody")) + "rn";
newMessage += messages.FirstOrDefault(x => x.StartsWith("StatusCode")) + "rn";
newMessage += messages.FirstOrDefault(x => x.StartsWith("Duration")) + "rn";
return newMessage;
}
}
Warp this logger to a logger provider
public class CustomHttpLoggerProvider : ILoggerProvider
{
private readonly string _filePath;
public CustomHttpLoggerProvider(string filePath)
{
_filePath = filePath;
}
public ILogger CreateLogger(string categoryName)
{
return new CustomHttpLogger(_filePath);
}
public void Dispose() { }
}
Then added to logging providers
//This will clear the default providers, then only your custom provider will work.
//builder.Logging.ClearProviders();
builder.Logging.AddProvider(new CustomHttpLoggerProvider("E:\log1.txt"));
builder.Services.AddHttpLogging(options =>
{
options.CombineLogs = true;
options.LoggingFields = HttpLoggingFields.RequestQuery | HttpLoggingFields.RequestPath |
HttpLoggingFields.RequestBody | HttpLoggingFields.ResponseStatusCode | HttpLoggingFields.Duration;
});
Test result