用 libprometheus 暴露 /metrics 端点需用 registry 全局单例、cpp-httplib 提供 http 服务、collect() 返回 text/plain; version=0.0.4;counter 用于计数,histogram 用于延迟分布;指标更新须用 increment/observe/set 接口,避免直接访问成员变量;排查抓取失败需检查状态码、响应格式、网络及 label 转义。

如何用 libprometheus 暴露 HTTP 指标端点
直接暴露 /metrics 是最常见需求,但别自己手写文本格式——Prometheus 官方不保证兼容性,且易出格式错误(比如漏换行、标签值没转义)。用 libprometheus(C++17+)是目前最稳的选择。
实操建议:
- 用
prometheus::Registry全局单例注册指标,避免多线程竞争;每个Counter/Gauge构造时必须传入 registry - HTTP 服务推荐用
cpp-httplib而非 Boost.Beast 或 libcurl:轻量、头文件即用、无依赖冲突风险 -
httplib::Server的Get("/metrics", ...)回调里,必须调用registry.Collect()并返回text/plain; version=0.0.4(注意 MIME 类型和版本号,漏掉或写错会导致 Prometheus 抓取失败) - 别在每次请求都 new 一个
Registry:内存泄漏 + 指标重置,所有指标生命周期应与进程一致
Counter 和 Histogram 该选哪个?
不是“功能越强越好”,而是看你要回答什么问题。用错类型会导致查询困难甚至数据失真。
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 用
Counter记录单次请求耗时(单位 ms)→ 所有值累加成巨大数字,无法看出分布 - 用
Histogram统计错误码出现次数(离散枚举)→ bucket 配置冗余,查询反而要sum by (code)再聚合
使用场景对照:
-
Counter:只用于单调递增事件计数,如http_requests_total{method="POST",status="200"} -
Histogram:测延迟、大小等连续分布,如http_request_duration_seconds_bucket{le="0.1"};注意默认 bucket(0.005, 0.01, …, 10)不适合高延迟服务,得手动传prometheus::Histogram::Options{.buckets = {0.05, 0.1, 0.25, 0.5, 1.0, 2.5}}
多线程下更新指标为何数值乱跳?
libprometheus 的 Counter 和 Gauge 默认线程安全,但前提是——你没绕过它自带的原子操作接口。
容易踩的坑:
- 直接读写
Gauge::value_成员变量(私有字段,但 C++ 没 runtime 封装)→ 竞态,值突变或崩溃 - 用
std::atomic包裹自定义变量再塞进指标 label → Prometheus 不认,label 值不会自动刷新 - 在异步回调(如 libuv 回调)中调用
Counter::Increment()前没检查 registry 是否已初始化 → 首次请求可能 segfault
正确做法:
- 所有指标更新走
Increment()/Observe()/Set()接口 - 若需跨模块共享指标对象,传递指针或引用,别拷贝(
Counter禁拷贝) - 初始化顺序:先 new
Registry,再构造指标,最后启动 HTTP server
为什么 Prometheus 抓不到指标?排查三件事
90% 的“抓不到”问题不出在代码逻辑,而出在边界配置上。
检查清单:
- HTTP 返回状态码不是
200→cpp-httplib默认 404,需显式res.status = 200 - 响应 body 末尾多了空行或 BOM 字节 → Prometheus parser 严格,多一个
\n就报text format parsing error in line 1: invalid metric name - 服务监听地址不是
0.0.0.0:9090或未开放防火墙端口 → 本地curl http://localhost:9090/metrics能通 ≠ 外部 Prometheus 能通
最常被忽略的是:指标 label 值含空格或特殊字符(如 service_name = "my service"),必须用双引号包裹并转义,libprometheus 不自动处理——得自己调用 prometheus::client::EscapeLabelValue










