Serilog记录Web-api方法,在中间件内部添加上下文属性 [英] Serilog logging web-api methods, adding context properties inside middleware

查看:126
本文介绍了Serilog记录Web-api方法,在中间件内部添加上下文属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在努力用serilog记录响应主体有效负载数据,并从中间件记录日志.我正在使用 WEB API Core 应用程序,并将 swagger 添加到端点,并且我的目标是将每个端点调用记录到 .json serilog 的文件(请求和响应数据).

I've been struggling to log response body payload data with serilog, logging from middleware. I'm working on WEB API Core application, with swagger added to endpoints, and my goal is to log every endpoint call to a .json file with serilog (both request and response data).

对于 GET 请求,应记录响应的主体(作为属性添加到serilog上下文中),对于POST请求,应记录请求和响应的主体.我已经创建了中间件,并设法从请求和响应流中正确检索数据,并将其作为字符串获取,但是只有"RequestBody" 被正确记录.

For GET requests, body of the response should be logged (added to serilog context as a property), and for POST requests, both body of request and response should be logged. I have created middleware and managed to properly retrieve data from request and response stream, and getting it as a string, but only the "RequestBody" is being logged properly.

调试时,我可以看到读取请求/响应主体工作正常.

When debugging, I can see that reading request/response body works fine.

以下是程序-> Main方法的代码摘录:

Following is the code excerpt from Program->Main method:

Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(configuration)
    .Enrich.FromLogContext()
    .CreateLogger();

和中间件中的代码:

public async Task Invoke(HttpContext context)
{
    // Read and log request body data
    string requestBodyPayload = await ReadRequestBody(context.Request);

    LogContext.PushProperty("RequestBody", requestBodyPayload);

    // Read and log response body data
    var originalBodyStream = context.Response.Body;
    using (var responseBody = new MemoryStream())
    {
        context.Response.Body = responseBody;
        await _next(context);
        string responseBodyPayload = await ReadResponseBody(context.Response);

        if (!context.Request.Path.ToString().EndsWith("swagger.json") && !context.Request.Path.ToString().EndsWith("index.html"))
        {
            LogContext.PushProperty("ResponseBody", responseBodyPayload);
        }

        await responseBody.CopyToAsync(originalBodyStream);
    }
}

private async Task<string> ReadRequestBody(HttpRequest request)
{
    HttpRequestRewindExtensions.EnableBuffering(request);

    var body = request.Body;
    var buffer = new byte[Convert.ToInt32(request.ContentLength)];
    await request.Body.ReadAsync(buffer, 0, buffer.Length);
    string requestBody = Encoding.UTF8.GetString(buffer);
    body.Seek(0, SeekOrigin.Begin);
    request.Body = body;

    return $"{requestBody}";
}

private async Task<string> ReadResponseBody(HttpResponse response)
{
    response.Body.Seek(0, SeekOrigin.Begin);
    string responseBody = await new StreamReader(response.Body).ReadToEndAsync();
    response.Body.Seek(0, SeekOrigin.Begin);

    return $"{responseBody}";
}

正如我提到的,"RequestBody" 已正确记录到文件中,但"ResponseBody" 则没有任何记录(甚至没有添加为属性)感谢任何帮助.

As I mentioned, "RequestBody" is properly logged to file, but nothing for "ResponseBody" (not even added as a property) Appreciate any help.

推荐答案

从多个帖子中收集信息并根据我的需要对其进行了自定义之后,我找到了一种将请求和响应正文数据都记录为serilog日志结构的属性的方法.

After collecting informations from several posts, and customizing it to my needs, I have found a way to log both request and response body data as properties of serilog log structure.

我没有找到一种只在一个地方记录请求和响应正文的方法(在中间件的 Invoke 方法中),但是我找到了一种解决方法.由于请求处理管道的性质,这是我必须要做的:

I didn't find a way to log both request and response body in one place only (in the Invoke method of the middleware), but I found a workaround. Because of the nature of the request processing pipeline, here is what I had to do:

Startup.cs 中的

代码:

Code in the Startup.cs:

app.UseMiddleware<RequestResponseLoggingMiddleware>();
app.UseSerilogRequestLogging(opts => opts.EnrichDiagnosticContext = LogHelper.EnrichFromRequest);

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆