项目场景:.net 7 sqlserver apm-server版本7.7 Elastic.Apm.NetCoreAll版本1.25.3
问题描述
题主最近使用了Elastic Apm的net core版本代理,但是对分布式追踪概念没了解,以为只是简单的记录日志和耗时等操作,但是发现本地调接口是可以正常记录sql,http等日志,但是部署到服务器发现别的服务调用没有记录sql相关日志,于是进行了断断续续的排查过程..
一、有apm记录的应用启用了加密中间件,没有日志时一开始以为时加解密中间件问题,因为这个加密会替换request的body,后面测试取消解密也是一样没记录,只能转向其他方向排查
二、升级Elastic.Apm.NetCoreAll版本,以为是包版本太低了,进行了了一个升级,发现还是没有记录
三、查看官方文档:HTTP configuration options | APM .NET Agent Reference [1.x] | Elastic
由于题主此时还是认为是加解密的问题,所以看了文档也没发现什么配置和加解密或请求body有关
四、以上方式都没定位到问题,只能试试查看源码看看能不能有点发现了,接下来就进入漫长的源码阅读理解了.....
1、首先下载APM Dotnet代理的源码 GitHub - elastic/apm-agent-dotnet
2、查看源码,因为我们用的sqlsugar(底层用的是Microsoft.Data.SqlClient),而APM .NET支持Microsoft.Data.SqlClient和System.Data.SqlClient包的追踪
所以题主看的就是下图这些类了,代码中的Span就是一个操作,多个Span组合就可以组合出调用链,SqlClientDiagnosticListener类中的HandleStartCommand、HandleStopCommand顾名思义就是命令执行前后,既然题主的sql没监控到那就看看HandleStopCommand的逻辑,可以看到里面有一个EndSpan调用
看到上图断点位置,有个判断是否发送到ApmServer,再点击到这个定义,判断IsSampled和!_isDropped,重点就是IsSampled取值,这里取的Transaction的IsSampled(Transaction我理解是Span的集合,多个Span组合就成了Transaction),也就是说Transaction如果IsSampled为True就表示会进行采样,现在就要看看哪里赋值了这个字段
直接查看Transaction类的构造函数引用,是直接由Trace(表示整个请求的最顶层)直接生成的Transaction,查看Trace有一个StartTransaction,也就是每次请求都会生成一个Transaction?所以题主又找了找,发现确实是这样,有一个AspNetCoreDiagnosticListener类会调用WebRequestTransactionCreator.StartTransactionAsync其实也是调用Trace的StartTransaction
重点来啦!!!这里就是读取请求头的traceparent、tracestate来判断当前请求要不要进行采样记录,然后会包装DistributedTracingData数据传给Transaction,而.NET 5后HttpClient默认不采样,导致跨服务Http调用没保存到APM Server!!!
APM .NET Agent的源码其实也说明了在TraceContext类中TryExtractTracingData方法,感兴趣可以自己研究下
解决方案:
知道原因就很简单啦!按照官网配置下 "TraceContinuationStrategy": "restart_external"就好了