Просмотреть тело ответа на запрос в приложении Insights

Можно ли просмотреть тело ответа на запрос в Application Insights? Я видел много вопросов / статей относительно тела запроса, но не нашел ни одного, касающегося тела ответа.

Я строю MVC Core 2.1 Web Api.

Связанная статья:

Просмотреть тело запроса POST в 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 { }
            }
        }
    }
}

1 ответ

Вы должны реализовать ITelemetryInitializer, Введите IHttpContextAccessor к классу и читать поток ответов в пределах Initialize метод. Убедитесь, что прошло ITelemetry объект от типа RequestTelemetry и что запрос HttpRequest был либо постом, либо путом. Затем вы можете прочитать ответ, используя IHttpContext.HttpContext.Response.Body и зарегистрируйте его, используя Application Insight.

Наконец, зарегистрируйте свой класс в методе ConfigureService в вашем Startup.cs

Я решил это, добавив промежуточное ПО, которое сохраняет тело запроса как функцию в HttpContext. Важно, чтобы промежуточное ПО было зарегистрировано доapp.UseMvc() поскольку фреймворк Mvc располагает потоком.

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();
}

Затем я получаю такое тело, когда вхожу в ApplicationInsights из моего ExceptionFilter:

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

Я пришел к такому выводу после прочтения этой проблемы на странице github ApplicationInsights и этой проблемы на странице github AspNetCore.

Я решил вышеуказанную проблему, я объяснил решение в следующем блоге. В основном это включает в себя сохранение ответа в сообщении запроса с использованием обработчика сообщений и его получение в классе, реализующем ITelemetryInitialize.

Вот блог, который подробно объясняет.

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

Другие вопросы по тегам