C# Meter和MeterListener方法 C#如何使用System.Diagnostics.Metrics记录指标

来源:这里教程网 时间:2026-02-21 17:41:12 作者:

什么是
Meter
MeterListener

Meter
是指标采集的入口,负责创建和管理计数器(
Counter
)、直方图(
Histogram
)、仪表(
Gauge
)等指标对象;
MeterListener
则是监听者,用于订阅、过滤、采样或导出指标数据——它不自动收集,必须显式启用(
meterListener.Register() 
)才能生效。

如何创建并使用
Counter
记录请求次数

最常用的是整数计数器,适合记录 HTTP 请求、消息处理等离散事件:

Meter meter = new Meter("myapp.http", "1.0");
Counter<long> requestCounter = meter.CreateCounter<long>("http.requests.total");
// 每次请求调用
requestCounter.Add(1, new KeyValuePair<string, object?>("method", "GET"));
requestCounter.Add(1, new KeyValuePair<string, object?>("method", "POST"));
标签(
KeyValuePair
)必须是只读且不可变的;传入可变字典或匿名对象会抛
ArgumentException
不要在热路径反复新建
Tag
实例,建议缓存复用
new[] { new KeyValuePair<string object>("method", "GET") }</string>
Add()
是线程安全的,但避免在锁内调用——它内部有无锁优化

为什么
MeterListener
没有收到指标?

常见原因是没启用监听或过滤太严。默认情况下

MeterListener
不监听任何
Meter
,必须显式注册并设置匹配逻辑:

MeterListener listener = new MeterListener();
listener.InstrumentPublished = (instrument, meter) =>
{
    if (meter.Name == "myapp.http" && instrument.Name == "http.requests.total")
        listener.EnableMeasurementReporting(instrument);
};
listener.Start(); // 必须调用!
Start()
必须在
InstrumentPublished
回调中调用
EnableMeasurementReporting()
之后,否则指标被丢弃
如果应用启动时
Meter
已创建(如 DI 容器提前构造),需在
listener.Start()
前调用
listener.RecordObservableInstrument()
或确保监听器注册早于指标初始化
SetMeasurementEventCallback<t>()</t>
只对
ObservableCounter
/
ObservableGauge
生效,普通
Counter
MeasurementRecorded

直方图
Histogram
怎么记录延迟并避免性能抖动?

Histogram
适合记录响应时间等分布型指标,但要注意:它的
Record()
方法默认不采样,高频打点会显著影响性能:

Histogram<double> latencyHist = meter.CreateHistogram<double>("http.request.duration", unit: "ms");
latencyHist.Record(elapsedMs, new KeyValuePair<string, object?>("status_code", 200));
若每秒调用超千次,建议搭配
MeterListener
在回调中做采样(如每 10 次取 1 次),而不是在业务代码里判断
内置分位数计算(如 P95)由导出端(如 OpenTelemetry Collector)完成,
Histogram
本身只存原始观测值 + 边界桶(bucket)
不要用
double.NaN
double.PositiveInfinity
调用
Record()
,会触发静默丢弃(无异常,但不计入)

真正容易被忽略的是生命周期管理:

Meter
无需释放,但
MeterListener
应在应用退出前调用
Stop()
,否则可能持有对
Meter
的引用导致 GC 延迟;同时,多个
MeterListener
实例之间不共享状态,各自独立过滤和回调。

相关推荐