在Application Insights中查看POST请求正文

是否可以在Application Insights中查看POST请求正文?

我可以看到请求详细信息,但不能查看应用程序洞察中发布的有效负载。 我是否需要通过编码来跟踪这个问题?

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

POST请求

您可以简单地实现自己的遥测初始化器 :

例如,在提取有效负载并将其添加为请求遥测的自定义维度的实现下面:

public class RequestBodyInitializer : ITelemetryInitializer { public void Initialize(ITelemetry telemetry) { var requestTelemetry = telemetry as RequestTelemetry; if (requestTelemetry != null && (requestTelemetry.HttpMethod == HttpMethod.Post.ToString() || requestTelemetry.HttpMethod == HttpMethod.Put.ToString())) { using (var reader = new StreamReader(HttpContext.Current.Request.InputStream)) { string requestBody = reader.ReadToEnd(); requestTelemetry.Properties.Add("body", requestBody); } } } } 

然后通过配置文件或代码将其添加到配置中:

 TelemetryConfiguration.Active.TelemetryInitializers.Add(new RequestBodyInitializer()); 

然后在Google Analytics中查询:

 requests | limit 1 | project customDimensions.body 

@yonisha提供的解决方案在我看来是最干净的解决方案。 但是你仍然需要在那里获得你的httpcontext,为此你需要更多的代码。 我还插入了一些基于或取自上面的代码示例的注释。 重置您的请求的位置很重要,否则您将丢失它的数据。

这是我测试的解决方案,并给了我jsonbody:

 public class RequestBodyInitializer : ITelemetryInitializer { readonly IHttpContextAccessor httpContextAccessor; public RequestBodyInitializer(IHttpContextAccessor httpContextAccessor) { this.httpContextAccessor = httpContextAccessor; } public void Initialize(ITelemetry telemetry) { if (telemetry is RequestTelemetry requestTelemetry) { if ((httpContextAccessor.HttpContext.Request.Method == HttpMethods.Post || httpContextAccessor.HttpContext.Request.Method == HttpMethods.Put) && httpContextAccessor.HttpContext.Request.Body.CanRead) { const string jsonBody = "JsonBody"; if (requestTelemetry.Properties.ContainsKey(jsonBody)) { return; } //Allows re-usage of the stream httpContextAccessor.HttpContext.Request.EnableRewind(); var stream = new StreamReader(httpContextAccessor.HttpContext.Request.Body); var body = stream.ReadToEnd(); //Reset the stream so data is not lost httpContextAccessor.HttpContext.Request.Body.Position = 0; requestTelemetry.Properties.Add(jsonBody, body); } } } 

然后还要确保将其添加到Startup – > ConfigureServices中

 services.AddSingleton(); 

编辑:

如果您还想获得响应体,我发现创建一个中间件(dotnet核心不确定框架)是有用的。 起初我采用了上面的方法来记录响应和请求,但大多数时候你想要这些。

  public async Task Invoke(HttpContext context) { var reqBody = await this.GetRequestBodyForTelemetry(context.Request); var respBody = await this.GetResponseBodyForTelemetry(context); this.SendDataToTelemetryLog(reqBody, respBody, context); } 

这等待请求和响应,其中请求与上面几乎相同,而不是它是一个任务。

对于我使用下面代码的响应主体,我也排除了204,因为它导致了nullref:

 public async Task GetResponseBodyForTelemetry(HttpContext context) { Stream originalBody = context.Response.Body; try { using (var memStream = new MemoryStream()) { context.Response.Body = memStream; //await the responsebody await next(context); if (context.Response.StatusCode == 204) { return null; } memStream.Position = 0; var responseBody = new StreamReader(memStream).ReadToEnd(); //make sure to reset the position so the actual body is still available for the client memStream.Position = 0; await memStream.CopyToAsync(originalBody); return responseBody; } } finally { context.Response.Body = originalBody; } } 

我为此实现了一个中间件,

调用方法呢,

  if (context.Request.Method == "POST" || context.Request.Method == "PUT") { var bodyStr = GetRequestBody(context); var telemetryClient = new TelemetryClient(); var traceTelemetry = new TraceTelemetry { Message = bodyStr, SeverityLevel = SeverityLevel.Verbose }; //Send a trace message for display in Diagnostic Search. telemetryClient.TrackTrace(traceTelemetry); } 

在哪里,GetRequestBody就像,

 private static string GetRequestBody(HttpContext context) { var bodyStr = ""; var req = context.Request; //Allows using several time the stream in ASP.Net Core. req.EnableRewind(); //Important: keep stream opened to read when handling the request. using (var reader = new StreamReader(req.Body, Encoding.UTF8, true, 1024, true)) { bodyStr = reader.ReadToEnd(); } // Rewind, so the core is not lost when it looks the body for the request. req.Body.Position = 0; return bodyStr; } 

yonisha提供的解决方案很干净,但在.Net Core 2.0中对我不起作用。 如果你有一个JSON主体,这是有效的:

 public IActionResult MyAction ([FromBody] PayloadObject payloadObject) { //create a dictionary to store the json string var customDataDict = new Dictionary(); //convert the object to a json string string activationRequestJson = JsonConvert.SerializeObject( new { payloadObject = payloadObject }); customDataDict.Add("body", activationRequestJson); //Track this event, with the json string, in Application Insights telemetryClient.TrackEvent("MyAction", customDataDict); return Ok(); } 

对不起,@ yonisha的解决方案似乎不适用于.NET 4.7。 Application Insights部分工作正常,但实际上没有简单的方法可以在.NET 4.7中的遥测初始化程序中获取请求主体。 .NET 4.7使用GetBufferlessInputStream()来获取流,并且此流是“一次读取”。 一个潜在的代码是这样的:

 private static void LogRequestBody(ISupportProperties requestTelemetry) { var requestStream = HttpContext.Current?.Request?.GetBufferlessInputStream(); if (requestStream?.Length > 0) using (var reader = new StreamReader(requestStream)) { string body = reader.ReadToEnd(); requestTelemetry.Properties["body"] = body.Substring(0, Math.Min(body.Length, 8192)); } } 

但GetBufferlessInputStream()的返回已经消失,并且不支持搜索。 因此,身体将永远是一个空字符串。

我从来没有得到@ yonisha的答案,所以我使用了DelegatingHandler

 public class MessageTracingHandler : DelegatingHandler { protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // Trace the request await TraceRequest(request); // Execute the request var response = await base.SendAsync(request, cancellationToken); // Trace the response await TraceResponse(response); return response; } private async Task TraceRequest(HttpRequestMessage request) { try { var requestTelemetry = HttpContext.Current?.GetRequestTelemetry(); var requestTraceInfo = request.Content != null ? await request.Content.ReadAsByteArrayAsync() : null; var body = requestTraceInfo.ToString(); if (!string.IsNullOrWhiteSpace(body) && requestTelemetry != null) { requestTelemetry.Properties.Add("Request Body", body); } } catch (Exception exception) { // Log exception } } private async Task TraceResponse(HttpResponseMessage response) { try { var requestTelemetry = HttpContext.Current?.GetRequestTelemetry(); var responseTraceInfo = response.Content != null ? await response.Content.ReadAsByteArrayAsync() : null; var body = responseTraceInfo.ToString(); if (!string.IsNullOrWhiteSpace(body) && requestTelemetry != null) { requestTelemetry.Properties.Add("Response Body", body); } } catch (Exception exception) { // Log exception } } } 

.GetRequestTelemetry()是Microsoft.ApplicationInsights.Web的扩展方法。