博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
「译」 .NET 5 新增的Http, Sockets, DNS 和 TLS 遥测
阅读量:4035 次
发布时间:2019-05-24

本文共 8279 字,大约阅读时间需要 27 分钟。

.NET 一直在稳定的增加和改善对应用程序进行跨平台的诊断分析,在.NET Core 3.0, 我们看到了 EventCounters[1] 的介绍,用于观察和分析指标测量。

我最近在几个 .NET Core 的应用程序中使用 counters,来跟踪服务一段时间内 http 的请求数量。

.NET 5 一直在进步,我一直在关注 runtime repository [2] 的动态和工作,在 http 发生外部调用时,添加了新的遥测计数器和一些核心组件的事件,包括 HttpClient, Sockets, DNS 和 Security。

在这篇文章中,我将展示如何在 runtime(运行时)消费这些信息,需要注意的是,本文的代码仅仅是简单的实现,如果在生产中使用话,你还需要考虑到性能开销或者其他。

定义 EventListener

.NET 中已经有了 EventListener 抽象类,我们可以在代码中继承这个类,来自定义一个 listener

internal sealed class TelemetryListener : EventListener{    ...}

接下来,我们重写 OnEventSourceCreated 方法,来处理下边的几种特定事件的消息

protected override void OnEventSourceCreated(EventSource eventSource){    if (eventSource.Name.Equals("System.Net.Sockets")         || eventSource.Name.Equals("System.Net.Http")        || eventSource.Name.Equals("System.Net.NameResolution")        || eventSource.Name.Equals("System.Net.Security"))    {        EnableEvents(eventSource, EventLevel.Verbose, EventKeywords.All, new Dictionary
{ {"EventCounterIntervalSec", "2"} }); }}

在上面的代码中,我们获取到 eventSource.Name, 然后过滤我们感兴趣的类型的消息,例如, HttpTelemetry 类定义了 EventSource(事件源)的名字叫 System.Net.Http。

[EventSource(Name = "System.Net.Http")]internal sealed class HttpTelemetry : EventSource{  ...}

在这个例子中,我们感兴趣的 event (事件) 和 counters (计数器)来自四个 event sources (事件源)

•NameResolution Telemetry – DNS lookups•Sockets Telemetry – Underlying network connections to a server•Security Telemetry – Establish TLS•Http Telemetry – HttpClient

当 EventSource 匹配一个我们想要监听的名字时,我们调用 EnableEvents 方法,在这个代码示例中,我们接收所有等级的 event(事件)和关键字,我们可以定义一个字典,可能会有其他额外的参数,当 EventCounters 开始消费时,我们可以设置频率来更新计数器,上面的代码表示我们希望计数器每两秒发送信息。

下边的代码我们重写 OnEventWritten 方法

protected override void OnEventWritten(EventWrittenEventArgs eventData){    ...}

在这种方法中,我们将添加一些代码,来监听事件计数器,然后更新当前值,并且输出到控制台。

if (eventData.EventName == "EventCounters"){    if (eventData.Payload?.Count <= 0                    || eventData.Payload?[0] is not IDictionary
data || !data.TryGetValue("CounterType", out var ct) || !data.TryGetValue("Name", out var n) || ct is not string counterType || n is not string name) return; var metricValue = metricType switch { "Sum" when data.TryGetValue("Increment", out var increment) => Convert.ToInt64(increment), "Mean" when data.TryGetValue("Mean", out var mean) => Convert.ToInt64(mean), _ => 0 }; switch (name) { case "dns-lookups-duration": Console.WriteLine($"Event Counter = Avg Duration of Lookup: {metricValue}ms"); Console.WriteLine(); break; case "dns-lookups-requested": Console.WriteLine($"Event Counter = Name Resolution Lookups: {metricValue}"); Console.WriteLine(); break; case "total-tls-handshakes": Console.WriteLine($"Event Counter = Total TLS Handshakes: {metricValue}"); Console.WriteLine(); break; case "requests-started": Console.WriteLine($"Event Counter = HTTP Requests Started: {metricValue}"); Console.WriteLine(); break; case "requests-failed": Console.WriteLine($"Event Counter = HTTP Requests Failed: {metricValue}"); Console.WriteLine(); break; case "outgoing-connections-established": Console.WriteLine($"Event Counter = Outgoing Connections Established: {metricValue}"); Console.WriteLine(); break; case "http11-connections-current-total": Console.WriteLine($"Event Counter = HTTP1.1 Connections Established: {metricValue}"); Console.WriteLine(); break; case "http20-connections-current-total": Console.WriteLine($"Event Counter = HTTP2.0 Connections Established: {metricValue}"); Console.WriteLine(); break; case "bytes-sent": Console.WriteLine($"Event Counter = Bytes Sent: {metricValue}"); Console.WriteLine(); break; case "bytes-received": Console.WriteLine($"Event Counter = Bytes Received: {metricValue}"); Console.WriteLine(); break; }}

上面的代码,我通过 eventData 的属性过滤了我感兴趣的日志,你可以注意到,上面我用了一些 C# 9.0 的语法 not 在判断条件中。

if (eventData.Payload?.Count <= 0  || eventData.Payload?[0] is not IDictionary
data || !data.TryGetValue("CounterType", out var ct) || !data.TryGetValue("Name", out var n) || ct is not string counterType || n is not string name) return;

下边的代码,我用了 C# 8.0的 switch 表达式来定义指标值,根据指标的类型,EventCounters 主体包含一个自增值或者平均值。

var metricValue = counterType switch  {      "Sum" when data.TryGetValue("Increment", out var increment) => Convert.ToInt64(increment),      "Mean" when data.TryGetValue("Mean", out var mean) => Convert.ToInt64(mean),      _ => 0  };

下边的例子中,我使用 switch 指定了我们感兴趣的事件来源的名称,然后记录到控制台

switch (name){    case "dns-lookups-duration":        Console.WriteLine($"Event Counter = Avg Duration of Lookup: {metricValue}ms");        Console.WriteLine();        break;    case ...}

我们需要每过2s把但当前事件计数器的值输出到控制台,你可以选择把这些指标数据放到其他的指标服务,在过去,我把一些事件计数器的值发送到了 Datadog。

下边的这一块代码,我判断了 EventName, 如果不是 EventCounters,为了演示,我把这些信息都输出到了控制台

if (eventData.EventName != "EventCounters"){    Console.WriteLine($"Event = {eventData.EventSource.Name} - {eventData.EventId}:{eventData.EventName}");    for (var i = 0; i < eventData.PayloadNames?.Count; i++)    {        Console.WriteLine(            $" - {eventData.PayloadNames[i]}: {eventData.Payload?[i]?.ToString() ?? string.Empty}");    }}

使用 EventListener

我们在一个简单的控制台应用程序使用 TelemetryListener

internal class Program{    private static async Task Main()    {        using var listener = new TelemetryListener();        var client = new HttpClient();        try        {            await client.GetAsync("https://www.stevejgordon.co.uk");        }        catch        {            // ignore        }        await Task.Delay(2000);    }}

在这个 main 方法中,我创建了一个 TelemetryListener 实例,开始监听事件信息,我使用了 HttpClient 调用了我的博客主页,然后程序等待2s,这样我们的 listener 有足够的时间触发事件和接受消息。

运行程序后,我们可以在控制台看到这些信息

Event = System.Net.Http - 1:RequestStart - scheme: https - host: www.stevejgordon.co.uk - port: 443 - pathAndQuery: / - versionMajor: 1 - versionMinor: 1 - versionPolicy: 0Event = System.Net.NameResolution - 1:ResolutionStart - hostNameOrAddress:Event = System.Net.NameResolution - 2:ResolutionStopEvent = System.Net.NameResolution - 1:ResolutionStart - hostNameOrAddress: www.stevejgordon.co.ukEvent = System.Net.NameResolution - 2:ResolutionStopEvent = System.Net.Sockets - 1:ConnectStart - address: InterNetworkV6:28:{1,187,0,0,0,0,32,1,8,216,16,15,240,0,0,0,0,0,0,0,2,127,0,0,0,0}Event = System.Net.Sockets - 2:ConnectStopEvent = System.Net.Security - 1:HandshakeStart - isServer: False - targetHost: www.stevejgordon.co.ukEvent = System.Net.Security - 2:HandshakeStop - protocol: 3072Event = System.Net.Http - 4:ConnectionEstablished - versionMajor: 1 - versionMinor: 1Event = System.Net.Http - 7:RequestHeadersStartEvent = System.Net.Http - 8:RequestHeadersStopEvent = System.Net.Http - 11:ResponseHeadersStartEvent = System.Net.Http - 12:ResponseHeadersStopEvent = System.Net.Http - 13:ResponseContentStartEvent = System.Net.Http - 14:ResponseContentStopEvent = System.Net.Http - 2:RequestStopEvent Counter = HTTP Requests Started: 1Event Counter = HTTP Requests Failed: 0Event Counter = HTTP1.1 Connections Established: 1Event Counter = HTTP2.0 Connections Established: 0Event Counter = Name Resolution Lookups: 2Event Counter = Avg Duration of Lookup: 36msEvent Counter = Outgoing Connections Established: 1Event Counter = Bytes Received: 68222Event Counter = Bytes Sent: 354Event Counter = Total TLS Handshakes: 1

刚开始,我们看到的事件信息来自与我们订阅的4个来源,HttpClient 开始请求我的博客主页,这需要DNS来解析服务器的IP地址,Socket 连接创建,然后TLS握手开始,然后我有了一个TLS 连接,Http 请求发出信息并且接收到了响应,我们可以在控制台看到这些输出信息。

总结

这篇文章特别强调了.NET 的团队正在积极的添加新的遥测事件和事件计数器时, 这些诊断工具对于我们分析应用程序起到很关键的作用,这些事件和计数器可以在运行时进程内收集, 然后把这些信息发送到外部的指标服务,他们也支持跨平台进程跟踪和监视的应用程序行为,在未来的文章中,我希望将深入研究跟踪、可观测性,然后使用这些数据。

原文链接:https://www.stevejgordon.co.uk/additional-http-sockets-dns-and-tls-telemetry-in-dotnet-5

References

[1] EventCounters: https://devblogs.microsoft.com/dotnet/introducing-diagnostics-improvements-in-net-core-3-0/

[2] runtime : https://github.com/dotnet/runtime/

转载地址:http://kyudi.baihongyu.com/

你可能感兴趣的文章
自己动手写GC
查看>>
Java 8新特性终极指南
查看>>
logback高级特性使用(二) 自定义Pattern模板
查看>>
JVM并发机制探讨—内存模型、内存可见性和指令重排序
查看>>
可扩展、高可用服务网络设计方案
查看>>
如何构建高扩展性网站
查看>>
微服务架构的设计模式
查看>>
持续可用与CAP理论 – 一个系统开发者的观点
查看>>
nginx+tomcat+memcached (msm)实现 session同步复制
查看>>
c++字符数组和字符指针区别以及str***函数
查看>>
c++类的操作符重载注意事项
查看>>
c++模板与泛型编程
查看>>
STL::deque以及由其实现的queue和stack
查看>>
WAV文件解析
查看>>
DAC输出音乐2-解决pu pu 声
查看>>
WPF中PATH使用AI导出SVG的方法
查看>>
WPF UI&控件免费开源库
查看>>
QT打开项目提示no valid settings file could be found
查看>>
Win10+VS+ESP32环境搭建
查看>>
Ubuntu+win10远程桌面
查看>>