如何在serilog的输出.net核心中添加“请求正文"? [英] How to add 'request body' in serilog's output .net core?
问题描述
我有一个基于.net core 3.1的Web API.
I have a web API based on .net core 3.1.
我正在使用SeriLog库作为记录器.
I'm using the SeriLog library as a logger.
这是我的SeriLog配置.Serilog已从"appsettings.json"配置.
Here is my SeriLog Configuration. Serilog has been configured from 'appsettings.json'.
我需要在日志输出中添加请求正文"参数(如果存在).有什么方法可以配置它.另外,我分享我的日志输出.
I need to add 'request body' parameters to log's output if it exists. Is there any way to configure this. Also, I share my log output.
推荐答案
我编写了一个自定义中间件来捕获HTTP请求和响应.它与ASP.NET Core 3.X兼容,并且也应与2.X和.NET 5.0兼容,尽管我尚未在那些框架版本中对其进行过测试.
I wrote a custom middleware to capture both HTTP requests and responses. It is compatible with ASP.NET Core 3.X and should also work with 2.X and .NET 5.0, although I haven't tested it with those framework versions.
这是我的git仓库的链接: https://github.com/matthew-daddario/AspNetCoreRequestResponseLogger
Here's the link to my git repo: https://github.com/matthew-daddario/AspNetCoreRequestResponseLogger
相关代码是这样:
public class RequestResponseLoggerMiddleware
{
private readonly RequestDelegate _next;
private readonly bool _isRequestResponseLoggingEnabled;
public RequestResponseLoggerMiddleware(RequestDelegate next, IConfiguration config)
{
_next = next;
_isRequestResponseLoggingEnabled = config.GetValue<bool>("EnableRequestResponseLogging", false);
}
public async Task InvokeAsync(HttpContext httpContext)
{
// Middleware is enabled only when the EnableRequestResponseLogging config value is set.
if (_isRequestResponseLoggingEnabled)
{
Console.WriteLine($"HTTP request information:\n" +
$"\tMethod: {httpContext.Request.Method}\n" +
$"\tPath: {httpContext.Request.Path}\n" +
$"\tQueryString: {httpContext.Request.QueryString}\n" +
$"\tHeaders: {FormatHeaders(httpContext.Request.Headers)}\n" +
$"\tSchema: {httpContext.Request.Scheme}\n" +
$"\tHost: {httpContext.Request.Host}\n" +
$"\tBody: {await ReadBodyFromRequest(httpContext.Request)}");
// Temporarily replace the HttpResponseStream, which is a write-only stream, with a MemoryStream to capture it's value in-flight.
var originalResponseBody = httpContext.Response.Body;
using var newResponseBody = new MemoryStream();
httpContext.Response.Body = newResponseBody;
// Call the next middleware in the pipeline
await _next(httpContext);
newResponseBody.Seek(0, SeekOrigin.Begin);
var responseBodyText = await new StreamReader(httpContext.Response.Body).ReadToEndAsync();
Console.WriteLine($"HTTP request information:\n" +
$"\tStatusCode: {httpContext.Response.StatusCode}\n" +
$"\tContentType: {httpContext.Response.ContentType}\n" +
$"\tHeaders: {FormatHeaders(httpContext.Response.Headers)}\n" +
$"\tBody: {responseBodyText}");
newResponseBody.Seek(0, SeekOrigin.Begin);
await newResponseBody.CopyToAsync(originalResponseBody);
}
else
{
await _next(httpContext);
}
}
private static string FormatHeaders(IHeaderDictionary headers) => string.Join(", ", headers.Select(kvp => $"{{{kvp.Key}: {string.Join(", ", kvp.Value)}}}"));
private static async Task<string> ReadBodyFromRequest(HttpRequest request)
{
// Ensure the request's body can be read multiple times (for the next middlewares in the pipeline).
request.EnableBuffering();
using var streamReader = new StreamReader(request.Body, leaveOpen: true);
var requestBody = await streamReader.ReadToEndAsync();
// Reset the request's body stream position for next middleware in the pipeline.
request.Body.Position = 0;
return requestBody;
}
}
这篇关于如何在serilog的输出.net核心中添加“请求正文"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!