在现今微服务流行的年代相信一定有了解APM,对于APM核心来说是数据来源,一般各自的APM都有对应的组件帮助完成这些工作。如果需要制作自己的APM系统 ,那需要考虑服务程序调用埋点问题;在这里介绍使用BeetleX.Tracks组件进行代码埋点,组件基于Activity机制实现,它可以轻松方便地对代码处理逻辑进行埋点,并可实现跨线程跨组调用链跟踪记录,最终过订阅的方式提交到相应的服务中。
基础实现
组件通过.NetCore内置Activity对象实现代码调用链记录,并通过DiagnosticSource对象进行调用记录发布。这样做的好处是不管其他组件是不是使用BeetleX.Tracks组件记录,只要其内部使用Activity即可保持各组件调用的关系链信息串连起来达到不同组件都能构建完整跟踪信息。
由于Activity和DiagnosticSource是框架内部集成,因此只需要按规则实现即可共享之间代码调用的关系链数据。
使用
在使用组件埋点的时候需要先引用它,可能通过以下地址安装下载:https://www.nuget.org/packages/BeetleX.Tracks/
安装组件后你只需要通过以下方式对代码进行跟踪
public async Task Hello() { using (CodeTrackFactory.Track("/Hello", CodeTrackLevel.Bussiness, null)) { var host = new Http.Clients.HttpHost("https://www.baidu.com"); var request = host.Get("/"); var txt = await request.Execute(); await DefaultRedis.Instance.Flushall(); await DefaultRedis.Get<Employee>("nonexisting"); await DefaultRedis.Set("emp3", Northwind.Data.DataHelper.Defalut.Employees[3]); await DefaultRedis.Get<Employee>("emp3"); var wss = new TextClient("wss://echo.websocket.org"); await wss.ReceiveFrom("henry"); } }
通过CodeTrackFactory.Track方法创建一个跟踪对象,以上示例是创建一个/Hello的跟踪标签,等级是Bussiness。没指定父ID通过组件内部自动获取上一层的Activity的ID信息作为父信息,这个父ID一般用于不同服务进程间交互指定,用于指定当前执行代码是由那个服务路由过来;还有一种情况就是跨队列任务处理难以确定关系的时候也可以显式指定ID,一般同一代码块下来的都无须指定(即使不同组件间调用)。以下是针对上面代码的运行效果:
跟踪标签
组件提供两种跟踪标签,上面示例用到的Track是一种,它的信息最终通过订单来获取;实际应用中可能在执行完成就需要一个详细信息,这个时候就需要TrackReport方法来创建。
using (var track = CodeTrackFactory.TrackReport(actionUrl, CodeTrackLevel.Module, parentID, "HTTP", "Action")) { //.... } Console.Write($"{CodeTrackFactory.Activity.GetReport()}")
以上是建立TrackReport的示例,并在后面把结果打印出来。在上面的使用代码中定义TrackReport标签,在处理完成后即可把完整结果打印出来。由于TrackReport是组件单独扩展的,所以只能把BeetleX.Tracks自己的跟踪链串起来;如果想和其他方式的关系串起来只能自己通过DiagnosticSource订阅后再自行处理。
跟踪等级
组件跟踪分为以下几个等级
All = 0, Code = 1, Function = 2, Class = 4, Module = 8, Bussiness = 16, Off = 512,
通过等级配置来实现当前的跟踪信息是否需要发布,因此在写完所有埋点信息后还可以通过配置来设置那些埋点信息需要启用;特别在不同的运行状态下有些埋点信息是不需要的。可以通过以下方式配置输出的埋点信息级别
public static CodeTrackLevel Level { get; set; } = CodeTrackLevel.Off;
设置级别越低输出信息越多,当设置为Off后则所有跟踪信息都无效;为了性能上的考虑组件针对不输出的信息是不会创建对应的Activity对象也不会发布订阅信息,只是一个没有任何逻辑的Track结构处理。
订阅
单一进程的跟踪数据只是一个数据孤岛,它存在的作用非常有限;通过订阅的方式来获取跟踪数据并提交到服务上做整合才能发挥其主要作用。
CodeTrackFactory.SubscribeTrack((name, data) =>{ //...});
组件可以通过CodeTrackFactory.SubscribeTrack方法来订阅相关跟踪数据,然后加工后传送到相应的服务上。
多服务关系链
一个完整的业务往往需要关联到多个服务应用,对这个关系的维护只需要在服务之前传递个Activity的ParentID即可,每个服务在接管数据处理后只需要把ParentID传递给每个创建跟踪的Activity上即可以实现不同服务的关系链引用。
总结
BeetleX.Tracks只针对本地程序埋点,APM整合需要自行订阅跟踪信息并发布到相关服务器上,在多服务关系链处理上需要自动传递事件的ParentID用于保证各服务之前的执行关系。由于实现是基于Activity和DiagnosticSource所以无法在.NETFramework上运行。