深入研究 .NET 5 的开放式遥测

摘要:
Spans跨度上面Jaeger图中的每一行都称为Span,在.NET中的每一行均由System.Activities.Activity类型表示,它也具有唯一的标识符,开始和结束时间以及父范围的唯一标识符,所以这些可以形成调用链,并且Span还可以包含其他参数。不幸的是,.NET团队的命名大大偏离了官方的OpenTelemetry规范,我有点疑惑,不过我现在已经明白了大概。注意:在.NET5中才有ActivitySource,在之前可以用Activity。注意:在open-telemetryg规范中叫IsRecording,在.NETCore3.1中是Recorded,在.NET5中是IsAllDataRequested。

OpenTelemetry 介绍

OpenTelemetry是一种开放的源代码规范,工具和SDK,用于检测,生成,收集和导出遥测数据(指标,日志和跟踪),开放遥测技术得到了Cloud Native Computing Foundation(CNCF)的支持,该基金会支持一系列流行的优秀的开源项目,你可以去看一下CNCF景观图,https://landscape.cncf.io/ ,就明白了我的意思,这个SDK支持所有主要的编程语言,包括C#和ASP.NET Core。

在这篇文章中,我将讨论OpenTelemetry的全部含义,为什么要使用它以及如何在.NET中使用,对于典型的应用程序,通常需要记录三组数据:指标,日志和跟踪。

深入研究 .NET 5 的开放式遥测第1张

Logging 日志

可以监听程序的进程发出的消息日志,在.NET应用程序中,如果您使用NuGet包ILogger中的日志记录功能,就可以轻松的让OpenTelemetry支持 Microsoft.Extensions.Logging, 如果要构建ASP.NET Core应用程序,通常已经使用了此功能。

Metrics 指标

提供运行进程的指标信息,包括计数器,仪表盘和直方图,对OpenTelemetry中指标的支持仍在开发中, 但是已经确定下来了,指标包括以下:

  • CPU 使用百分比
  • 进程内存使用量
  • Http的请求数量

Tracing 追踪

也叫做分布式跟踪,它记录单个操作的开始和结束时间以及与该操作相关的参数,比如在ASP.NET Core中记录HTTP请求的跟踪,您可能会记录请求和响应的开始和结束时间,参数将是 Http的请求方式,请求参数,请求地址等,请求调用会形成链路,您可以深入了解时间耗费在哪个服务,或者服务中有异常报错发生。

Jaeger

收集指标,日志,追踪信息只是一部分,如何进行数据处理,展示是APM系统的功能,因为收集的数据遵循OpenTelemetry标准,所以可以和APM系统完美结合。

Jaeger和Zipkin是可以收集和显示并且与Open Telemetry兼容APM, Zipkin的话比较久了,并且没有很好的UI,因此我个人推荐Jaeger,看起来像这样:

深入研究 .NET 5 的开放式遥测第2张

上图显示了应用程序的跟踪,您可以看到它如何使用HTTP请求对MySQL,Redis和外部API进行调用, 每行的长度显示了执行所需的时间,您可以轻松地从头到尾查看跟踪中执行的所有主要操作,您还可以深入研究每一行,并查看与该部分跟踪有关的其他信息。

Spans 跨度

上面Jaeger图中的每一行都称为 Span,在.NET中的每一行均由System.Activities.Activity类型表示,它也具有唯一的标识符,开始和结束时间以及父范围的唯一标识符,所以这些可以形成调用链,并且Span还可以包含其他参数。

不幸的是,.NET团队的命名大大偏离了官方的OpenTelemetry规范,我有点疑惑,不过我现在已经明白了大概。

深入研究 .NET 5 的开放式遥测第3张

我的理解是.NET已经包含一个Activity的类型,因此.NET团队决定重用它,而不是重新创建一个 Span的新类型,这意味着很多命名与open-telemetry规范不匹配,在.NET中,你现在可以把 Span 和 Activity身份互换。

注意:在.NET 5中才有ActivitySource,在之前可以用 Activity。

使用Span记录行为非常简单,首先,我们必须创建一个ActivitySource可以记录Span或活动的对象:

private static ActivitySource activitySource = new ActivitySource(
    "companyname.product.library",
    "semver1.0.0");

然后,我们可以调用StartActivity开始记录,最后调用Dispose停止记录Span:

using (var activity = activitySource.StartActivity("ActivityName")
{
    // Pretend to do some work.
    await LongRunningAsync().ConfigureAwait(false);
} // Activity gets stopped automatically at end of this block during dispose.

Events 事件

当Span开启记录后,我们也可以在这期间记录事件,这些事件包含了时间戳信息:

using (var activity = activitySource.StartActivity("ActivityName")
{
    await LongRunningOperation().ConfigureAwait(false);
}

public async Task LongRunningOperationAsync()
{
    await Task.Delay(1000).ConfigureAwait(false);

    // Log timestamped events that can take place during an activity. 
    Activity.Current?.AddEvent(new ActivityEvent("Something happened."));
}

在LongRunningOperationAsync方法中,有一个问题是,如何把activity传入这个方法,如果我们定义了一个参数,这体验也太差了,但是,将两个操作分离的一个好的方法是使用Activity.Current。

一个常见的错误,我可以预见的是,Activity.Current可能是null,所以这里我加了null判断。

Attributes 属性

属性是数据的键值对,您可以将其记录为单个Span的一部分,比如Http的请求方式,请求状态码等。

注意,在Open Telemetry规范中叫 Attributes,在 我们.NET 中叫Tag

using (var activity = activitySource.StartActivity("ActivityName")
{
    await LongRunningOperation().ConfigureAwait(false);
}

public async Task LongRunningOperationAsync()
{
    await Task.Delay(1000).ConfigureAwait(false);

    // Log an attribute containing arbitrary data.
    Activity.Current?.SetTag("http.method", "GET");
}

IsRecording 记录

IsRecording是Span上的一个标志,如果返回false,表明该Span已结束,另外,如果你的数据量比较大的话,你需要抽样采集,比如10%,那么你也可以手动把这些span设置为false,它不会采集。

注意:在open-telemetryg规范中叫IsRecording,在.NET Core 3.1中是 Recorded,在.NET 5 中是 IsAllDataRequested。

using (var activity = activitySource.StartActivity("ActivityName")
{
    await LongRunningOperation().ConfigureAwait(false);
}

public async Task LongRunningOperationAsync()
{
    await Task.Delay(1000).ConfigureAwait(false);

    // It's possible to optionally request more data from a particular span.
    var activity = Activity.Current;
    if (activity != null && activity.IsAllDataRequested)
    {
        activity.SetTag("http.url", "http://www.mywebsite.com");
    }
}

Trace的语义约定

注意属性名称http.method,http.url,我在以上示例中使用了该属性,因为在open-telemetry规范中已经标准化了某些常用的属性名称,标准化常用属性名称可以在Jaeger等APM中很好的展示它们,属性名称已分类为几个不同的类别,你可以花点时间看一下:

  • General: 可用于描述不同种类的操作的常规语义属性
  • HTTP: 客户端和服务器的Http调用
  • Database: SQL 和 NoSql的调用
  • RPC/RMI: 远程调用,比如gRPC等
  • Messaging: 用于与消息传递系统(队列,发布/订阅等)
  • Exceptions: 用于记录与Span关联的异常的属性

Exporting 导出

有很多用于导出使用OpenTelemetry收集的数据的插件,我将在我的下一篇博客文章中讨论有关在ASP.NET Core中使用Open Telemetry的信息, 可以很方便的处理这些数据,您可以轻松地订阅然后消费OpenTelemetry数据,如下所示:

using var subscriber = DiagnosticListener.AllListeners.Subscribe(
    listener =>
    {
        Console.WriteLine($"Listener name {listener.Name}");

        listener.Subscribe(kvp => Console.WriteLine($"Received event {kvp.Key}:{kvp.Value}"));
    });

跨进程的追踪

为什么这些程序会形成调用链,它们是不同的进程,这个怎么实现的呢?

这就是W3C跟踪上下文标准,它定义了一系列HTTP Header,这些Header将有关当前正在记录的任何跟踪的信息从一个进程传递到另一个进程,它通过Http的Header来传递信息,规范中定义了两个HTTP Header:

  • traceparent-包含version,trace-id,parent-id和trace-flags

    • version - 在open-telemetry规范中,它始终是00
    • trace-id - 跟踪的唯一标识符。
    • parent-id -作为当前 patent span 的唯一标识符。
    • trace-flags -当前跟踪的一组标志,用于确定是否正在采样当前跟踪以及跟踪级别。
  • tracestate -由一组名称/值对表示的特定于供应商的数据。

traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
tracestate: asp=00f067aa0ba902b7,redis=t61rcWkgMzE

Baggage

与Attributes类似,Baggage是我们可以将数据作为键值对添加到跟踪的另一种方式,不同之处在于,Baggage使用W3C规范中baggage定义的HTTP Header跨进程边界传递,但是Attributes的值数据只在当前Span中可用

baggage: userId=alice,serverNode=DF:28,isProduction=false

使用的话,也有些相同之处:

using (var activity = activitySource.StartActivity("ActivityName")
{
    await LongRunningOperation().ConfigureAwait(false);
}

public async Task LongRunningOperationAsync()
{
    await Task.Delay(1000).ConfigureAwait(false);

    // Log an attribute containing arbitrary data.
    Activity.Current?.AddBaggage("http.method", "GET");
}

它的用途在于,比如说我需要传递一个订单ID,我就可以放到 Baggage 数据中,它在整个请求链路中都可以访问。

总结

.NET团队对OpenTelemetry非常重视,你可以看到Activity类型在.NET 5 中的增强,并且默认 HttpClient 调用时,它会自动传输W3C跟踪上下文HTTP Header, 基于ILogger的统一日志,也可以很好的收集和OpenTelemetry兼容的日志。

原文作者: Rehan Saeed
原文链接: https://rehansaeed.com/deep-dive-into-open-telemetry-for-net/

最后

欢迎扫码关注我们的公众号 【全球技术精选】,专注国外优秀博客的翻译和开源项目分享,也可以添加QQ群 897216102

深入研究 .NET 5 的开放式遥测第4张

免责声明:文章转载自《深入研究 .NET 5 的开放式遥测》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇mysql只显示表名和备注Libevent:2设置下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Android开发 设备横屏与竖屏的详解

需要了解横竖屏切换关键知识  1.在Android设备的横竖屏幕,每一次切换横竖屏其实是在重新创建Activity,Activity会重新走一遍生命周期.从onCreate 到 onDestroy   2.在Activity类里的变量也会重新创建,这点需要注意! 判断屏幕方向,方式一判断屏幕是否竖屏   @Override protected vo...

android软键盘的用法总结

1.软键盘的显示原理       软键盘其实是一个Dialog。InputMethodService为我们的输入法创建了一个Dialog,并且对某些参数进行了设置,使之能够在底部 或者全屏显示。当我们点击输入框时,系统会对当前的主窗口进行调整,以便留出相应的空间来显示该Dialog在底部,或者全屏。 2.活动主窗口调整       Android定义了一...

解决Activity启动黑屏及设置android:windowIsTranslucent不兼容activity切换动画问题

项目中遇到打开Activity后黑屏的问题,网上找到解决办法是通过设置theme和style属性可以实现 之前在做 APP 的时候不太关注这个问题,因为自己在使用其他 APP 的时候也会在应用启动的初始有一个黑屏闪过后才会出现应用的欢迎页。直到最近开发过程中发现自己在欢迎页启动的线程由于请求和处理的数据量过大而,导致欢迎页在出现之前界面上会有一个短暂的白色...

Oracle存储过程记录异常日志

  一般我们会将一些涉及到数据库的定时任务直接用存储过程搞定,省去了后端代码的开发、部署,简单、快速,但这种方式存在一个弊端——当存储过程执行出错了,我们无法感知。解决办法也简单,学代码那样去捕获异常、打印日志。   第一步,建日志表: create table TBL_WLF_SYS_LOG ( S_TIME VAR...

Android中finish()方法

finish()官方解析:Call this when your activity is done and should be closed. The ActivityResult is propagated back to whoever launched you via onActivityResult(). 也就是说,当你打开的Activity已经执...

Notification(Notification的通知栏常驻、Notification的各种样式、Notification点击无效)

转自:http://blog.csdn.net/xy_nyle/article/details/19853591 Android的Notification是android系统中很重要的一个机制, 产品人员常常利用通知栏的方式,跟用户进行弱沟通。拥有推送通知的app要比没有此类功能的app活跃率要高很多。另外类似于墨迹天气,清理大师等 app,也会将通知栏常...