webman的/metrics路由必须单例初始化collectorregistry、返回标准openmetrics文本(#help开头,name{label} value timestamp格式)、响应头为content-type: text/plain; version=0.0.4,且全程无异常;否则prometheus抓取失败或报invalid。

Webman 暴露的 /metrics 路由必须是单例、标准格式、无异常执行的纯文本输出,否则 Prometheus 抓不到指标或持续报 INVALID —— 不是配置没生效,是出口本身不可用。
如何让 Webman 的 /metrics 返回合法 OpenMetrics 文本
关键不在“有没有定义指标”,而在“render() 前是否已注册且未出错”。Prometheus 只认以 # HELP 开头、每行形如 name{label="value"} 123.45 1716850000000 的纯文本。任何 PHP 异常、空值传入、非法标签字符(如空格、/、控制符)都会导致 render() 中断并返回 500 或空响应。
- 确保
app/controller/MetricsController.php的index()方法只做三件事:取 registry 实例 → 调用$registry->render()→ 设置响应头Content-Type: text/plain; version=0.0.4 - 不要在
render()前加日志、DB 查询、网络请求等可能抛异常的操作 - 标签值必须经过
str_replace([' ', '/', '\', '"'], '_', $value)过滤,避免解析失败 - 手动验证:
curl -v http://your-domain.com/metrics,检查响应体是否有# TYPE行、所有数值行末尾无空格、时间戳为 13 位毫秒级整数
为什么多 Worker 下指标重复或跳变
Webman 默认启动多个 Worker 进程,若每个进程都独立 new CollectorRegistry,Prometheus 抓到的就是 N 份完全独立的时间序列——Counter 会反复从 0 开始计数,Gauge 值在不同进程间来回跳变,Grafana 图表直接失真。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
-
CollectorRegistry必须全局单例,唯一初始化入口只能是app/Bootstrap.php,绑定到Container::set('prometheus.registry', $registry)或静态属性 - 所有中间件、控制器中通过
Container::get('prometheus.registry')获取实例,禁止在after()钩子或构造函数里 new - 别信“共享内存”或“APCu 缓存 registry”的方案——PHP-FPM 模式下进程隔离严格,跨 Worker 共享对象不可行
- 上线前用
curl http://your-domain.com/metrics | grep webman_http_requests_total看是否只出现一次,重复即说明 registry 初始化失控
用对指标类型:别把耗时当 Counter,也别用 Gauge 记请求数
指标语义错配会导致 PromQL 查询结果完全错误。比如用 Gauge 存请求数,rate() 就无法计算速率;用 Counter 存耗时,histogram_quantile() 直接失效。
- 请求总量、错误数、重定向次数 → 用
Counter(如$counter = $registry->addCounter(...)),调用$counter->inc(['status' => '200']) - 当前内存占用、活跃连接数、队列长度 → 用
Gauge(如$gauge = $registry->addGauge(...)),调用$gauge->set($value) - 请求耗时、SQL 执行时间 → 必须用
Histogram(非Gauge!),调用$histogram->observe($duration_ms),才能支持histogram_quantile(0.99, ...) - 避免在
before()中 set Gauge,在after()中再 set 一次——这会让值变成“结束时快照”,丢失中间波动
composer require prometheus/client_php 是唯一可靠选择
社区存在多个非标封装库(如某些 laravel-prometheus 包),它们绕过官方 CollectorRegistry 生命周期管理,或擅自修改响应头、指标格式,导致与 Prometheus Server 协议不兼容。
- 必须执行
composer require prometheus/client_php:^3.0(PHP 8.0+)或^2.5(PHP 7.4) - 禁用所有带 “webman-plugin” “laravel-prometheus” 字样的第三方包,它们通常未适配 Webman 的多进程模型
- 确认 vendor/autoload.php 加载后,
use PrometheusCollectorRegistry;能正常解析,且new CollectorRegistry()不报错 - 如果已有非标库,删除其
src/和config/,改用官方客户端 + 手动绑定 registry 到 Container
最易被忽略的是标签值的合法性校验和 registry 初始化时机——这两点不出问题,/metrics 就不会空;一旦出问题,所有后续告警、图表、PromQL 查询都建立在错误数据之上。










