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

2次阅读

Meter 是指标采集入口,负责创建管理 Counter、Histogram、Gauge;MeterListener 是需显式注册启用的监听者,用于订阅过滤导出指标。

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

什么是 MeterMeterListener

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

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

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

Meter meter = new Meter("myapp.http", "1.0"); Counter requestCounter = meter.CreateCounter("http.requests.total");  // 每次请求调用 requestCounter.Add(1, new KeyValuePair("method", "GET")); requestCounter.Add(1, new KeyValuePair("method", "POST"));
  • 标签(KeyValuePair)必须是只读且不可变的;传入可变字典或匿名对象会抛 ArgumentException
  • 不要在热路径反复新建 Tag 实例,建议缓存复用 new[] { new KeyValuePair("method", "GET") }
  • 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() 只对 ObservableCounter/ObservableGauge 生效,普通 CounterMeasurementRecorded

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

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

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

真正容易被忽略的是生命周期管理:Meter 无需释放,但 MeterListener 应在应用退出前调用 Stop(),否则可能持有对 Meter 的引用导致 GC 延迟;同时,多个 MeterListener 实例之间不共享状态,各自独立过滤和回调。

text=ZqhQzanResources