Prometheus start_http_server验证及bycounter取值None问题排查
问题根因
你获取不到bycounter指标值、注册表看似为空的核心原因有3个:
- 查询的标签序列不存在:你在
_set_counters方法里仅对标签组合by='test', level0top='test'执行了inc(),整个注册表里只存了这一组标签对应的Counter序列。测试代码里查询的是by='level1', level0top='WSJ2'的组合,这个序列从未被初始化/更新,Prometheus客户端不会自动生成不存在的时间序列,自然返回None。 - 指标名写错:
prometheus_client的Counter类型指标会自动在名称后加_total后缀,你注册时名字写的是bycounter,实际暴露的指标名是bycounter_total,直接查bycounter肯定拿不到值。 get_sample_value传参不规范:第一次调用传列表形式的标签值时,虽然顺序和定义的['by', 'level0top']一致,但对应序列本身不存在;传字典参数时要注意键名必须和标签名完全匹配,同时要对应已经初始化过的序列。
另外需要确认你测试用的TodayDataReporter和你贴的示例Reporter逻辑一致,没有在后续流程中重新给self.registry赋值新的CollectorRegistry实例,否则之前注册的指标会全部丢失。
你贴的核心监控类代码如下:
import logging from prometheus_client import ( CollectorRegistry, Counter, start_http_server ) class Reporter: def __init__(self): self._set_counters() start_http_server(8080, registry=self.registry) def _set_counters(self): self.registry = CollectorRegistry() self.bycounter = Counter( 'bycounter', 'blah blah', ['by', 'level0top'], registry=self.registry ) self.bycounter.labels(by='test', level0top='test').inc()
测试代码如下:
import unittest from sc_eol.monitoring import TodayDataReporter from sc_eol.sc_eol_utils import generate_query_url reporter = TodayDataReporter() class TestTodayDataReporter(unittest.TestCase): @staticmethod def test_publish(): by = 'level1' parse_query = {'level0top' : 'WSJ2', 'date' : '2021-11-01'} start = '2021-11-01' print(dir(reporter.registry)) reporter.registry.collect() before = reporter.registry.get_sample_value('bycounter', ['level1', 'WSJ2']) print("BEFOREEE", before) reporter.registry.collect() generate_query_url(by, start, parse_query, reporter) before = reporter.registry.get_sample_value('bycounter', {'by':'level1', 'level0top': 'WSJ2'}) reporter.registry.collect() print("After", before) if __name__ == "__main__": unittest.main()
修复方式
- 提前初始化需要查询的标签序列:要查询哪个标签组合的指标,必须先调用
labels(...).inc()完成初始化,比如要查by=level1, level0top=WSJ2的指标,要先执行:reporter.bycounter.labels(by='level1', level0top='WSJ2').inc() - 修正指标查询的名称:把查询的指标名改成
bycounter_total,推荐统一用字典形式传标签,避免顺序错误,正确写法:val = reporter.registry.get_sample_value( 'bycounter_total', labels={'by':'level1', 'level0top':'WSJ2'} ) - 校验注册表一致性:确保注册指标、启动HTTP服务、后续更新指标用的是同一个
CollectorRegistry实例,不要重复实例化新的注册表覆盖原有实例属性。
验证8080端口服务正常的方法
- 服务启动后在本机执行
curl http://127.0.0.1:8080/metrics,如果返回的文本中包含bycounter_total{by="test",level0top="test"} 1.0这类内容,说明服务运行正常、指标注册成功。 - 如果curl返回连接拒绝,先检查8080端口是否被其他进程占用,再确认实例化Reporter时没有抛出端口占用的异常。
- 可以在启动后打印
reporter.registry.collect()的返回结果,如果能拿到bycounter_total对应的指标样本,说明注册表内的指标是正常的。
内容的提问来源于stack exchange,提问作者Shivangi Singh
相关产品推荐
相关产品推荐

