.NET使用Application Insights时如何关联请求/响应与依赖日志
针对问题1:自定义请求/失败日志的关联
只要正确接入Application Insights SDK,同一次异步调用流(即同一次Foo方法执行的async上下文)内的所有自定义日志,默认会自动携带相同的Operation_Id全局追踪标识,在日志查询时直接按该字段过滤,就能直接关联同一次调用产生的"Invoked API"和"Failed API"日志。
如果需要更精准的匹配(比如同一个方法内存在多次HTTP调用,需要区分每一次调用的日志),可以显式读取当前上下文的追踪标识打到日志里,参考修改:
async Task Foo(Dto data) { // 读取当前链路的追踪ID var traceId = Activity.Current?.TraceId.ToString(); var callSpanId = Activity.Current?.SpanId.ToString(); _logger.LogDebug("Invoked API {ApiName}, TraceId: {TraceId}, SpanId: {SpanId}, Data: {@Data}", nameof(Foo), traceId, callSpanId, data); var requestContent = new StringContent(JsonSerializer.Serialize(data)); var httpResponse = await _httpClient.PostAsync(url, requestContent); // 原代码存在两个问题:一是漏写await会导致异步上下文丢失,二是ReadAsStringAsync是HttpContent的扩展方法,需要调用Content属性 string responseStr = await httpResponse.Content.ReadAsStringAsync(); if (!httpResponse.IsSuccessStatusCode) { _logger.LogError("Failed API {ApiName}, TraceId: {TraceId}, SpanId: {SpanId}, Response: {Response}", nameof(Foo), traceId, callSpanId, responseStr); } }
注意:原示例代码漏写await关键字、调用ReadAsStringAsync的对象错误,这两个问题都会导致异步执行上下文断裂,直接破坏追踪标识的传递,必须修正才能保证默认关联逻辑生效。
针对问题2:HttpClient自动生成依赖项日志的关联
完全可以实现自动全链路关联,不需要额外写大量自定义代码,满足两个前提即可:
- 项目中正确启用了Application Insights的依赖收集模块:如果是通过通用宿主的
AddApplicationInsightsTelemetry()接入,默认会自动引入依赖收集组件,不需要额外配置;如果是手动接入,需要单独安装依赖收集包并启用对应模块。 - 用
IHttpClientFactory创建HttpClient实例,不要直接手动new HttpClient():依赖收集模块是通过IHttpClientFactory的诊断钩子自动注入拦截逻辑的,手动new的HttpClient默认无法被自动采集。
满足以上条件后,HttpClient发起调用时自动生成的依赖项(dependencies类型)日志,会自动继承当前异步上下文的Operation_Id、父SpanId等追踪属性,和自定义日志、上游服务传入的追踪头(W3C标准的traceparent头或者旧版Request-Id头)自动打通。在Application Insights中打开任意一条相关日志的端到端事务视图,就能看到从上游请求、自定义业务日志、到HTTP依赖调用的完整链路。
如果因为特殊场景必须手动new HttpClient,只需要在发请求前把当前Activity的追踪头手动加到HttpRequestMessage的请求头里,也能实现关联。注意不要手动覆盖SDK自动注入的追踪请求头,否则会导致链路断裂。
内容的提问来源于stack exchange,提问作者Liero

