Просмотреть тело ответа на запрос в приложении 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/