DiagnosticSource DiagnosticListener 无侵入式分布式跟踪
|
ASP.NET Core 中的框架中发出大量诊断事件,包括当前请求进入请求完成事件,HttpClient发出收到与响应,EFCore查询等等。
我们可以利用DiagnosticListener来选择性地监听这些事件,然后通过自己的方式组织这些日志,实现无侵入的分布式跟踪。
下面我们通过DiagnosticSource监听EFCore,与HTTPClient,实现链路追踪。
创建监听
现在我们将配置一个DiagnosticListener来监听全部事件。
首先,我们需要一个IObserver,我们将使用它来订阅所有事件。- public class TestDiagnosticObserver : IObserver{ public void OnNext(DiagnosticListener value) { value.Subscribe(new TestKeyValueObserver()); } public void OnCompleted() { } public void OnError(Exception error) { }}
复制代码 其中重要的方法是OnNext。然后我们传入另一个自定义类型TestKeyValueObserver,这是实际接收实例发出的事件的类DiagnosticListener。该事件会接受KeyValuePair参数,我们后续可针对此参数做业务相关的筛选。- public class TestKeyValueObserver : IObserver{ public void OnNext(KeyValuePair 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 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{ public void OnNext(KeyValuePair 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的查询语句,开始事件等。
最后我们可以结构化这些数据,并将其持久化到自己的监控体系中,实现链路跟踪。
来源:https://www.cnblogs.com/chenyishi/p/18071178
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
|
|
|
发表于 2024-3-14 14:56:14
举报
回复
分享
|
|
|
|