DiagnosticSource DiagnosticListener 无侵入式分布式跟踪
ASP.NET Core 中的框架中发出大量诊断事件,包括当前请求进入请求完成事件,HttpClient发出收到与响应,EFCore查询等等。
我们可以利用DiagnosticListener来选择性地监听这些事件,然后通过自己的方式组织这些日志,实现无侵入的分布式跟踪。
下面我们通过DiagnosticSource监听EFCore,与HTTPClient,实现链路追踪。
创建监听
现在我们将配置一个DiagnosticListener来监听全部事件。
首先,我们需要一个IObserver<DiagnosticListener>,我们将使用它来订阅所有事件。
public class TestDiagnosticObserver : IObserver<DiagnosticListener>
{
public void OnNext(DiagnosticListener value)
{
value.Subscribe(new TestKeyValueObserver());
}
public void OnCompleted() { }
public void OnError(Exception error) { }
}
public class TestKeyValueObserver : IObserver<KeyValuePair<string, object?>>
{
public void OnNext(KeyValuePair<string, object?> value)
{
var activity = Activity.Current; Console.WriteLine($"traceId {activity?.TraceId} Received event: {value.Key}");
}
public void OnCompleted() { }
public void OnError(Exception error) { }
}
最后一步是在应用程序中注册我们的程序TestDiagnosticObserver。
DiagnosticListener.AllListeners.Subscribe(new TestDiagnosticObserver());
创建HTTP请求与EFCore查询
我们新建一个接口,用来集成EF与HttpClient。并调用这个接口查看DiagnosticListener 监听到的内容
[HttpGet]
public async Task<string> GetAsync()
{
//HTTP
await _httpClient.GetAsync("https://www.baidu.com"); //EF
Item item = new Item()
{
Barcode = Guid.NewGuid().ToString(),
Brand = "Milky Way",
Name = "Milk",
PruchasePrice = 20.5,
SellingPrice = 25.5
};
_productsContext.Items.Add(item);
_productsContext.SaveChanges();
return "OK";
}
调用此接口来看看我们的DiagnosticListener的效果。
可以看到收到了很多Event,包括当前请求的各个阶段,HttpClient的各个阶段,与EFCore查询的各个阶段。

解析Event
然后修改TestKeyValueObserver,我们从中挑选我们需要的HTTPClient与EFCore相关的事件。
public class TestKeyValueObserver : IObserver<KeyValuePair<string, object?>>
{
public void OnNext(KeyValuePair<string, object?> value)
{
var activity = Activity.Current; //Console.WriteLine($"traceId {activity?.TraceId} Received event: {value.Key}");
if (value.Key.StartsWith("System.Net.Http.Request"))
{
var cEventStr = JsonConvert.SerializeObject(value.Value);
var cEvent = JsonConvert.DeserializeAnonymousType(cEventStr, new { Request = new { RequestUri = ""} , Timestamp = 2879029490722 });
Console.WriteLine($"traceId {activity?.TraceId} Request.Start: {cEvent.Timestamp} ");
Console.WriteLine($"traceId {activity?.TraceId} Request.Uri: {cEvent.Request.RequestUri} ");
}
if (value.Key.StartsWith("System.Net.Http.Response"))
{
var cEventStr = JsonConvert.SerializeObject(value.Value);
var cEvent = JsonConvert.DeserializeAnonymousType(cEventStr, new { Request = new { RequestUri = "" }, Timestamp = 2879029490722 });
Console.WriteLine($"traceId {activity?.TraceId} Http.Response: {cEvent.Timestamp} ");
} if (value.Key.StartsWith("Microsoft.EntityFrameworkCore.Database.Connection.ConnectionOpening"))
{
var cEvent = (Microsoft.EntityFrameworkCore.Diagnostics.ConnectionEventData)value.Value;
Console.WriteLine($"traceId {activity?.TraceId} Connection.ConnectionOpening: {cEvent?.StartTime.ToString("yyyy-MM-dd HH:mm:ss:fff")} ");
}
if (value.Key.StartsWith("Microsoft.EntityFrameworkCore.Database.Command.CommandExecuting"))
{
var cEvent = (Microsoft.EntityFrameworkCore.Diagnostics.CommandEventData)value.Value;
Console.WriteLine($"traceId {activity?.TraceId} {cEvent?.Command.CommandText} ");
}
if (value.Key.StartsWith("Microsoft.EntityFrameworkCore.Database.Connection.ConnectionClosed"))
{
var cEvent = (Microsoft.EntityFrameworkCore.Diagnostics.ConnectionEventData)value.Value;
Console.WriteLine($"traceId {activity?.TraceId} Connection.ConnectionClosed: {cEvent?.StartTime.ToString("yyyy-MM-dd HH:mm:ss:fff")} ");
}
}
public void OnCompleted() { }
public void OnError(Exception error) { }
}
再次启动,查看效果,可以看到已经获取到了http请求的开始结束事件,EF的查询语句,开始事件等。

最后我们可以结构化这些数据,并将其持久化到自己的监控体系中,实现链路跟踪。
DiagnosticSource DiagnosticListener 无侵入式分布式跟踪的更多相关文章
- Hook 无侵入式埋点(页面统计)
一.技术原理 Method-Swizzling 黑魔法 方法交换(不懂的可以查) 二.页面统计 某盟页面统计SDK需要开发者在APP基类里实现ViewDidAppear和viewDidDisappea ...
- 使用AOP思想无侵入式申请权限,解决组件化中权限问题(一)
首先介绍AspectJx使用 https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx 在根项目的build.gradle ...
- php使用装饰模式无侵入式加缓存
<?php namespace App\Services; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\ ...
- Spring Boot 无侵入式 实现RESTful API接口统一JSON格式返回
前言 现在我们做项目基本上中大型项目都是选择前后端分离,前后端分离已经成了一个趋势了,所以总这样·我们就要和前端约定统一的api 接口返回json 格式, 这样我们需要封装一个统一通用全局 模版api ...
- .NET无侵入自动化探针原理和主流实现
前言 最近,我在微信公众号和博客园分享了一篇关于.NET微服务系统迁移至.NET 6.0的故事的文章,引起了许多读者的关注.其中,许多人对基于 OpenTelemetry .NET 的观测指标和无侵入 ...
- Centos下分布式跟踪工具Pinpoint的完整部署记录
一.Pinpoint简单介绍Pinpoint是一款对Java编写的大规模分布式系统的APM工具,有些人也喜欢称呼这类工具为调用链系统.分布式跟踪系统.一般来说,前端向后台发起一个查询请求,后台服务可能 ...
- 图灵学院-微服务11-分布式链路跟踪Sleuth详解
当客户端访问到第一个service 1的时候,会生成当前链路追踪的一个全局的trance ID,在一次调用过Service1--Service2--Service3--Service4时,整个服务访问 ...
- Android平台免Root无侵入AOP框架Dexposed使用详解
Dexposed是基于久负盛名的开源Xposed框架实现的一个Android平台上功能强大的无侵入式运行时AOP框架. Dexposed的AOP实现是完全非侵入式的,没有使用任何注解处理器,编织器或者 ...
- Android新技术学习——阿里巴巴免Root无侵入AOP框架Dexposed
阿里巴巴无线事业部近期开源的Android平台下的无侵入运行期AOP框架Dexposed,该框架基于AOP思想,支持经典的AOP使用场景.可应用于日志记录,性能统计,安全控制.事务处理.异常处理等方面 ...
- 小议webpack下的AOP式无侵入注入
说起来, 面向切面编程(AOP)自从诞生之日起,一直都是计算机科学领域十分热门的话题,但是很奇怪的是,在前端圈子里,探讨AOP的文章似乎并不是多,而且多数拘泥在给出理论,然后实现个片段的定式)难免陷入 ...
随机推荐
- idea右键没有run
最近用idea打开一个用Eclipse创建的项目,发现右键没有运行,这是一个很常见的问题,网上一大堆解决方案,试了一通都不行,最后在Event Log里的提示解决了问题. 首先我去配置jdk,发现已经 ...
- Primo Ramdisk SCSI虚拟硬盘和Direct-IO虚拟硬盘
Primo Ramdisk 使用不同的虚拟技术可创建两种类型的虚拟硬盘:SCSI 虚拟硬盘和 Direct-IO 虚拟硬盘. 本篇主要比较两者之间的差异. SCSI 虚拟硬盘遵循SCSI规范,行为上几 ...
- 关于一些OJ上的\r以及\n以及字符串行输入的一些警示
\r,\n,\r\n的区别 - 小 天 - 博客园 (cnblogs.com) 这篇文章详细的解释了在Windows系统和Linux系统下的换行的区别 概括的说,就是Windows系统下的" ...
- OGG_Linux_x64_BigData启动ggsci时报错:error while loading shared libraries: libjvm.so: cannot open shared object file: No such file or directory
问题描述 [root@hadoop03 ggs]$ ./ggsci ./ggsci: error while loading shared libraries: libjvm.so: cannot o ...
- C语言程序设计之字符串处理
C语言程序设计-字符串处理 第一题:回文数判断 问题描述] 回文是正读和倒读都一样的句子.读入一个最大长度不超过50个字符的句子,判断其是否是回文. [输入形式] 输入一个最大长度不超过50个字符的句 ...
- windows远程连接centos及闪退异常解决记录
平时在学校实验室写代码用的环境是linux系统,放假回家之后之后笔记本的性能和系统多少有些不方便,因此使用服务器安装IDEA进行编程,记录一下远程桌面的安装及出现的问题解决. 一. 安装Centos ...
- STC89C52驱动MAX7219LED点阵级联, 文字滚动效果
级联下的传值方式 级联下, N个MAX7219相当于组成了一个8*N bit宽度的锁存器, 如果需要对第M个7219进行写入, 需要做M次寻址+写入后拉高CS, 才能到达这个7219. 如果仅仅对这个 ...
- CentOS7 开机网卡加载失败
服务器CentOS7一开,发现web服务无法访问.最终用ifconfig发现,网卡没有加载,连个IP地址都没有. 这时使用命令 service network restart 试图重启服务器网络.不料 ...
- Java8接口中抽象方法和default和static方法的区别和使用
Java接口说明 传统的理解是接口只能是抽象方法.但是程序员们在使用中,发现很不方便,实现接口必须重写所有方法,很麻烦.所以java设计者妥协了,在java8中,支持default和static方法, ...
- 使用 Oracle PL/SQL NOCOPY 提示
参考文献: official document: http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/tuning.htm#LNPL ...