前言
工友们, .NET 6 Preview 7 已经在8月10号发布了, 除了众多的功能更新和性能改进之外, 在 preview 7 版本中, 也新增了全新的指标API, System.Diagnostics.Metrics
, 为了让应用能有更好的可观测性, 在之前的发布的.NET 5中, 也把 Activity 增强为 ActivitySource, 主要原因还是 .NET 运行时团队和 OpenTelemetry .NET SIG 进行了深度合作, 并且一起制定了 OpenTelemetry .NET 指标计划。
Metric support plans[1]
Metrics APIs Design[2]
目前 System.Diagnostics.Metrics 这个api还只能在 .NET preview 7 中使用, 当然后边也会像 System.Text.Json 库一样发布到Nuget平台, 让其他版本的 .NET 项目接入使用。
指标介绍
下边介绍了几个主要的类
•Meter 用来创建和跟踪指标Instrument•MeterListener 用来监听指标Instrument的值的更新•Counter 计数器, 一般记录累加的值, 比如程序中的错误数, 请求数 都可以用计数器•Histogram 直方图, 记录可统计的值, 比如记录下每一个接口的响应时间, 然后再根据时间进行汇总•ObservableCounter 可观察计数器, 一般记录累加的值, 比如 CPU 时间等•ObservableGauge 可观测仪表盘, 你可以用来记录应用的内存, GC 的内存等
Meter
Meter类用来创建各种指标Instrument, 包括计数器,直方图,仪表盘指标等等, Meter 类包含了 Name 和 Version 属性, 你可以设置meter的名称和版本。
var meter = new Meter("meter","v1.0");var requestCount = meter.CreateCounter<long>("RequestCount");var responseTime = meter.CreateHistogram<long>("ResponseTime");// ...
MeterListener
MeterListener 可以用来监听指标组件的值变化, 同样相对应的也有 ActivityListener。
MeterListener listener = new MeterListener(); listener.InstrumentPublished = (instrument, meterListener) =>
{Console.WriteLine($"EnableMeasurementEvents {instrument.Name} ");meterListener.EnableMeasurementEvents(instrument);
};listener.SetMeasurementEventCallback<long>((instrument, measurement, tags, state) =>
{Console.WriteLine($"Instrument: {instrument.Name} has recorded the measurement {measurement}");
});listener.MeasurementsCompleted = (instrument, state) =>
{listener.DisableMeasurementEvents(instrument);
};listener.Start();
属性
InstrumentPublished 当使用Meter类创建指标Instrument时, 这个回调可以接收到创建的指标信息。
MeasurementsCompleted 当停止指标的收集时,这个回调可以接收到相应的指标信息, 通常是执行了 Meter 和 MeterListener 的Dispose() 方法
方法
EnableMeasurementEvents 开启相应指标Instrument的监听
DisableMeasurementEvents 关闭相应指标Instrument的监听
SetMeasurementEventCallback 设置指标Instrument的测量值更新的回调
RecordObservableInstruments 记录所有监听的可观察指标(Observable instruments)的当前测量值。
Start 开启监听指标Instrument。
Counter 计数器
Counter是计数器指标,可以用来记录累加的值,使用非常简单,下边的示例中,模拟记录了程序的请求次数,首先调用 CreateCounter 函数创建一个计数器指标 requestCount, 然后调用Add 方法, 进行Counter的累加操作。
Meter meter = new Meter("meter","v1.0");var requestCount = meter.CreateCounter<long>("RequestCount");for (int i = 0; i < 10; i++)
{requestCount.Add(1);
}
然后使用上面的 MeterListener 来监听计数器指标, 程序的输出如下:
在第一行, MeterListener 检测到了上面创建的 RequestCount 计数器, 并且开启了指标的监听, 当我们调用 requestCount.Add(1) 后, MeterListener 捕获到了指标测量值的更新, 然后在控制台输出了相应的值, 需要注意的是, MeasurementEventCallback 回调方法只会捕获指标每次更新的测量值, 而不是汇总后的总数,所以这里的输出都是1。
Histogram 直方图
Histogram 是直方图指标,记录可统计的值, 比如记录下每一个接口的响应时间, 然后再根据时间进行汇总, 和 Counter 差不多, 不过指标的维度不一样, 而且 Histogram 使用Record()方法记录每次的值,而不是Add()方法。
Meter meter = new Meter("meter","v1.0");var responseTime = meter.CreateHistogram<long>("ResponseTime");for (int i = 0; i < 10; i++)
{var cost = new Random().Next(100,1000);responseTime.Record(cost);
}
用随机数表示了接口的响应耗时, 输出如下:
ObservableCounter 可观察计数器
ObservableCounter 是可观察的计数器, 和 Counter 不一样的是, 创建 ObservableCounter 需要传入一个Func委托, 来返回一个测量值, 当然也不需要手动调用 Add(), Record() 方法, 只需要定时调用 MeterListener的RecordObservableInstruments 方法, 获取当前的指标测量值。
class Program{static async Task Main(string[] args){MeterListener listener = new MeterListener();Start(listener);AutoRecord(listener);Meter meter = new Meter("meter","v1.0");_ = meter.CreateObservableCounter<long>("CPU_Counter",() => new Random().Next(100,1000));Console.ReadKey();}static void Start(MeterListener listener){listener.InstrumentPublished = (instrument, meterListener) =>{Console.WriteLine($"EnableMeasurementEvents {instrument.Name} ");meterListener.EnableMeasurementEvents(instrument);};listener.SetMeasurementEventCallback<long>((instrument, measurement, tags, state) =>{Console.WriteLine($"Instrument: {instrument.Name} has recorded the measurement {measurement}");});listener.MeasurementsCompleted = (instrument, state) =>{listener.DisableMeasurementEvents(instrument);};listener.Start();}static void AutoRecord(MeterListener listener){var cts = new CancellationTokenSource();_ = Task.Run(async () => {while (!cts.IsCancellationRequested){await Task.Delay(3000);listener.RecordObservableInstruments();}});}}
ObservableGauge 仪表盘指标
这个比较好理解, 你可以用来记录应用的内存,GC 的内存等, 同样是可观察指标, 也需要传入一个返回测量值的func委托。
MeterListener listener = new MeterListener();Start(listener);AutoRecord(listener);Meter meter = new Meter("meter","v1.0");_ = meter.CreateObservableGauge<long>("GC_Memory_Gauge",() => GC.GetTotalMemory(false));Console.ReadKey();
程序的输出如下:
总结
本文主要介绍了.NET 6 指标API System.Diagnostics.Metrics,通过这些API, 可以很方便的收集应用的指标数据, 但是本文好像没有提到数据的聚合汇总? 不要担心, 运行时团队针对相应的指标API已经开发了一系列高性能的聚合API, 预计在.NET 6 preview 8 中发布更新!
References
[1]
Metric support plans: https://github.com/open-telemetry/opentelemetry-dotnet/issues/1501[2]
Metrics APIs Design: https://github.com/dotnet/designs/blob/3ac77d55eb00999fb2b03b280f209d08d3cd6ce9/accepted/2021/System.Diagnostics/Metrics-Design.md