【问题标题】:View Request's Response body in Application Insights在 Application Insights 中查看请求的响应正文
【发布时间】:2019-01-11 06:14:53
【问题描述】:

是否可以在 Application Insights 中查看请求的响应正文? 我看过很多关于请求正文的问题/文章,但没有发现任何关于响应正文的问题。

我正在构建一个 MVC 核心 2.1 Web Api。

相关文章:

View POST request body in Application Insights

这是我的代码,在从流创建阅读器时出现异常,即 “流不可读。”

public class ResponseBodyInitializer : ITelemetryInitializer
{
    readonly IHttpContextAccessor httpContextAccessor;

    public ResponseBodyInitializer(IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;
    }

    public void Initialize(ITelemetry telemetry)
    {
        if (telemetry is RequestTelemetry requestTelemetry)
        {
            HttpContext httpContext = httpContextAccessor.HttpContext;
            HttpRequest request = httpContext.Request;
            HttpResponse response = httpContext.Response;

            if (request.Method == HttpMethods.Post || 
                 request.Method == HttpMethods.Put)
            {
                //Log the response body
                if (httpContext.Response.HasStarted)
                {
                    const string responseBody = "ResponseBody";

                    if (requestTelemetry.Properties.ContainsKey(responseBody))
                    {
                        return;
                    }

                    try
                    {
                        var stream = new StreamReader(response.Body);
                        var body = stream.ReadToEnd();                            
                        response.Body.Position = 0;
                        requestTelemetry.Properties.Add(responseBody, body);
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
            }
        }
    }
}  

----------------------更新--------- -----------------------

这是我记录请求和响应正文的完整代码。请求正文已正确记录(使用 request.EnableRewind();),但是,响应部分在流阅读器上抛出异常流不可读。

public class RequestBodyAndResponseBodyInitializer : ITelemetryInitializer
{
    readonly IHttpContextAccessor httpContextAccessor;

    public RequestBodyAndResponseBodyInitializer(IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;
    }

    public void Initialize(ITelemetry telemetry)
    {
        if (telemetry is RequestTelemetry requestTelemetry)
        {
            HttpContext httpContext = httpContextAccessor.HttpContext;
            HttpRequest request = httpContext.Request;
            HttpResponse response = httpContext.Response;

            if (request.Method == HttpMethods.Post ||
                 request.Method == HttpMethods.Put)
            {
                //1- Log the request body
                if (request.Body.CanRead)
                {
                    const string requestBody = "RequestBody";
                    if (requestTelemetry.Properties.ContainsKey(requestBody))
                    {
                        return;
                    }

                    //Allows re-usage of the stream
                    request.EnableRewind();

                    var stream = new StreamReader(request.Body);
                    var body = stream.ReadToEnd();

                    //Reset the stream so data is not lost
                    request.Body.Position = 0;
                    requestTelemetry.Properties.Add(requestBody, body);
                }
                //2- Log the response body
                else if (httpContext.Response.HasStarted)
                {
                    //Allows re-usage of the stream
                    //request.EnableRewind();

                    const string responseBody = "ResponseBody";

                    if (requestTelemetry.Properties.ContainsKey(responseBody))
                    {
                        return;
                    }

                    try
                    {
                        //var stream = new StreamReader(response.Body);
                        //var body = stream.ReadToEnd();                            
                        //response.Body.Position = 0;
                        //requestTelemetry.Properties.Add(responseBody, body);

                        using (var memoryStream = new MemoryStream())
                        {
                            var stream = response.Body;
                            response.Body = memoryStream;

                            await next(context);

                            var body = new StreamReader(memoryStream).ReadToEnd();
                            //logger?.LogDebug($"Response: {responseBody}");

                            response.Body = stream;
                        }


                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
                else { }
            }
        }
    }
}

【问题讨论】:

  • 嗨!你有解决办法吗?我遇到了完全相同的问题!

标签: c# azure azure-application-insights telemetry


【解决方案1】:

你必须实现ITelemetryInitializer。将IHttpContextAccessor 注入类并在Initialize 方法中读取响应流。确保传递的 ITelemetry 对象来自 RequestTelemetry 类型,并且 HttpRequest 是 Post 或 Put。然后,您可以使用 IHttpContext.HttpContext.Response.Body 属性读取响应并使用 Application Insight 记录它。

最后,在 Startup.cs 的 ConfigureService 方法中注册您的类

【讨论】:

  • 是的,我确实尝试过,但是在响应正文上创建流时出错:(。我点击了链接stackoverflow.com/questions/42686363/…
  • 我已经用异常信息和代码 sn-p 修改了问题。
  • 添加context.Request.EnableRewind()(是的,在请求对象上,而不是在响应上)。解释:stackoverflow.com/questions/43403941/…
  • 我已将完整代码粘贴到问题的 UPDATED 部分中,该部分也使用了 Request.EnableRewind() 但仍然没有取得任何成果。
【解决方案2】:

我通过添加一个将请求正文保存为HttpContext 中的功能的中间件解决了这个问题。由于 Mvc 框架会处理流,因此在 app.UseMvc() 之前注册中间件很重要。

Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.Use(async (httpContext, next) =>
        {
            var request = httpContext.Request;

            if (request.Method == HttpMethods.Post || request.Method == HttpMethods.Put && request.Body.CanRead)
            {
                //Allows re-usage of the stream
                request.EnableBuffering();
                request.Body.Seek(0, SeekOrigin.Begin);

                using (var stream = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true))
                {
                    var body = await stream.ReadToEndAsync();
                    //Reset the stream so data is not lost
                    request.Body.Position = 0;
                    var bodyFeature = new RequestBodyFeature(body); // RequestBodyFeature is a simple POCO
                    httpContext.Features.Set(bodyFeature);
                }

                request.Body.Seek(0, SeekOrigin.Begin);
            }

            await next.Invoke();
        });

        app.UseMvc();
}

当我从我的 ExceptionFilter 登录到 ApplicationInsights 时,我会得到这样的正文:

context.HttpContext?.Features.Get<RequestBodyFeature>()?.Body

我在阅读 ApplicationInsights github 页面上的 this issue 和 AspNetCore github 页面上的 this issue 后得出了这个结论。

【讨论】:

  • 这个问题是关于记录响应正文而不是请求正文。
  • 谢谢@boylec1986 我当时并没有意识到这一点。在这里留下答案,因为 OP 也更新了请求正文。
【解决方案3】:

我解决了上述问题,我在下面的博客中解释了解决方案。基本上它涉及使用消息处理程序将响应存储在请求消息中,并在实现 ITelemetryInitialize 的类中检索相同的响应。

这里是详细解释的博客。

https://thirum.wordpress.com/2019/08/19/logging-the-http-response-body-in-application-insights/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-09
    • 2022-01-12
    • 2017-10-01
    相关资源
    最近更新 更多