问题
What is the best way to log the HTTP request body when a request fails?
I'm logging unhandled exceptions by overriding the Exception logger:
public class AiExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
if (context != null && context.Exception != null)
{
ExceptionTelemetry telemetry = new ExceptionTelemetry(context.Exception);
// the requestBody is always empty because the stream is non-rewinadable?
string requestBody = context.Request.Content.ReadAsStringAsync().Result;
telemetry.Properties.Add("Request Body", requestBody);
Logger.LogException(telemetry);
}
base.Log(context);
}
}
With the above code, the request content is always empty. I also tried this, but that throws an unsupported method exception due to calling GetBufferlessInputStream. So that doesn't work either.
I could log all request content using a DelegatingHandler, but I'd only like to log the request body on failed requests caused by unhandled exceptions.
Any ideas?
回答1:
With the above code, the request content is always empty.
You could get the request stream using ReadAsStreamAsync method and reset the position of this stream. After that, you can read the content from this steam using StreamReader. Code below is for your reference. I tested it and it worked fine on my side.
ExceptionTelemetry telemetry = new ExceptionTelemetry(context.Exception);
//Get request stream and reset the position of this stream
Stream requestBodyStream = context.Request.Content.ReadAsStreamAsync().Result;
requestBodyStream.Position = 0;
string requestBody = string.Empty;
using (StreamReader sr = new StreamReader(requestBodyStream))
{
requestBody = sr.ReadToEnd();
}
telemetry.Properties.Add("Request Body", requestBody);
回答2:
You are right. You can't reset the Position property the same way you can with Streams. Instead, copy the content and read the copy.
if (context != null && context.Exception != null)
{
HttpContent requestContent = new HttpContent();
request.Content.CopyToAsync(requestContent);
ExceptionTelemetry telemetry = new ExceptionTelemetry(context.Exception);
// the requestBody is always empty because the stream is non-rewinadable?
string requestBody = requestContent.ReadAsStringAsync().Result;
telemetry.Properties.Add("Request Body", requestBody);
Logger.LogException(context.Exception);
}
回答3:
Here's an alternative to Amor - MSFT's answer using CopyTo
public class AiExceptionLogger : ExceptionLogger
{
public override async void Log(ExceptionLoggerContext context)
{
if (context != null && context.Exception != null)
{
ExceptionTelemetry telemetry = new ExceptionTelemetry(context.Exception);
using (var ms = new MemoryStream())
{
await context.Request.Content.CopyToAsync(ms);
var requestBody = Encoding.UTF8.GetString(ms.ToArray());
telemetry.Properties.Add("Request Body", requestBody);
}
Logger.LogException(telemetry);
}
base.Log(context);
}
}
来源:https://stackoverflow.com/questions/43769413/what-is-the-best-practice-to-log-request-body-on-failed-requests-in-application