You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 7中System.Diagnostics.Metrics.Histogram桶值不符合预期问题

问题描述

我正在学习遥测指标并将其发送至Prometheus,编写了一个.NET 7的C#控制台应用,希望将ping时间计入带有自定义边界的Histogram中。

配置代码如下:

using System.Diagnostics.Metrics;

var meter = new Meter("MeterUsing");
var pingHistogram = meter.CreateHistogram<int>("ping", "ms", "The ping time");
var meterProvider = Sdk.CreateMeterProviderBuilder()
    .AddMeter(meter.Name)
    .AddView(pingHistogram.Name, 
        new ExplicitBucketHistogramConfiguration { Boundaries = new double[] { 100, 200, 500, 1000 } })
    .Build();

记录值的代码为:

pingHistogram.Record(rand.Next(30, 2000));

我将数据推送至OpenTelemetry Collector后,由Prometheus抓取数据。查看Collector的指标端点时,得到如下内容:

# HELP ping The ping time
# TYPE ping histogram
ping_bucket{instance="280616b2-1c17-426a-9cf0-f33183ef7dfc",job="MeterUsing",le="100"} 2
ping_bucket{instance="280616b2-1c17-426a-9cf0-f33183ef7dfc",job="MeterUsing",le="200"} 5
ping_bucket{instance="280616b2-1c17-426a-9cf0-f33183ef7dfc",job="MeterUsing",le="500"} 13
ping_bucket{instance="280616b2-1c17-426a-9cf0-f33183ef7dfc",job="MeterUsing",le="1000"} 23
ping_bucket{instance="280616b2-1c17-426a-9cf0-f33183ef7dfc",job="MeterUsing",le="+Inf"} 64
ping_sum{instance="280616b2-1c17-426a-9cf0-f33183ef7dfc",job="MeterUsing"} 69801
ping_count{instance="280616b2-1c17-426a-9cf0-f33183ef7dfc",job="MeterUsing"} 64

这与我的预期不符,我期望每个桶统计对应区间内的数值数量,但当前桶内计数是按le递增的累积值,且ping_count等于ping_bucket{le="+Inf"}。请问是否可以配置视图来统计特定桶内的计量值?


解答

首先明确:Prometheus的Histogram指标规范本身就是使用累积桶(cumulative buckets)来表示的,这是Prometheus定义的标准格式,并非OpenTelemetry或代码配置的问题。le="X"代表所有小于等于X的样本总数,这种设计是为了方便计算分位数、区间占比等统计指标,比如要获取100<值≤200区间的样本数,只需执行ping_bucket{le="200"} - ping_bucket{le="100"}即可。

关于是否能通过OpenTelemetry视图配置改为非累积桶:

  • 目前OpenTelemetry的.NET SDK没有直接提供将Histogram转换为非累积桶(即每个桶单独统计区间内数量)的视图配置选项。因为OpenTelemetry的Metric API遵循官方规范,而规范中Histogram的默认导出格式为累积型,以兼容Prometheus等主流监控系统的要求。

如果确实需要单独的区间计数指标,有两种替代方案:

  1. Prometheus侧处理:通过PromQL计算区间值并创建记录规则(Recording Rule),示例:

    ping_bucket_range_0_100 = ping_bucket{le="100"}
    ping_bucket_range_101_200 = ping_bucket{le="200"} - ping_bucket{le="100"}
    ping_bucket_range_201_500 = ping_bucket{le="500"} - ping_bucket{le="200"}
    ping_bucket_range_501_1000 = ping_bucket{le="1000"} - ping_bucket{le="500"}
    ping_bucket_range_1001_inf = ping_bucket{le="+Inf"} - ping_bucket{le="1000"}
    

    这种方式可以在Prometheus中生成单独的区间计数指标,方便直接查询。

  2. 应用侧自定义指标:放弃使用Histogram,改用多个Counter分别统计每个区间的样本数,示例:

    var meter = new Meter("MeterUsing");
    var pingCounter0_100 = meter.CreateCounter<long>("ping_0_100", "ms", "Ping time 0-100ms count");
    var pingCounter101_200 = meter.CreateCounter<long>("ping_101_200", "ms", "Ping time 101-200ms count");
    var pingCounter201_500 = meter.CreateCounter<long>("ping_201_500", "ms", "Ping time 201-500ms count");
    var pingCounter501_1000 = meter.CreateCounter<long>("ping_501_1000", "ms", "Ping time 501-1000ms count");
    var pingCounter1001_Inf = meter.CreateCounter<long>("ping_1001_inf", "ms", "Ping time >1000ms count");
    
    // 记录时判断区间
    var pingValue = rand.Next(30, 2000);
    if (pingValue <= 100)
        pingCounter0_100.Add(1);
    else if (pingValue <= 200)
        pingCounter101_200.Add(1);
    else if (pingValue <= 500)
        pingCounter201_500.Add(1);
    else if (pingValue <= 1000)
        pingCounter501_1000.Add(1);
    else
        pingCounter1001_Inf.Add(1);
    

    这种方式可以直接导出每个区间的独立计数,但缺点是失去了Histogram自带的sum、count以及分位数计算能力,需要自行维护这些统计值。

内容的提问来源于stack exchange,提问作者MirrorBoy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 18:55:09