什么是 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实例之间不共享状态,各自独立过滤和回调。
