要统计Nginx各类HTTP状态码占比并接入Prometheus,需通过nginxlog-exporter解析access log生成带code和host标签的分子指标,并额外添加总请求数作为分母,再用PromQL计算比例;也可用OpenResty+shared dict内存聚合实现零IO实时统计。

要统计 Nginx 各类 HTTP 状态码的占比分布并接入 Prometheus,核心是把原始状态码($status)或上游状态码($upstream_status)转化为带标签的时序指标,并按时间窗口聚合计算比例。不能只存总数,得有分母(总请求数)和分子(各状态码数),才能算出准确占比。
用 nginxlog-exporter 提取状态码指标
这是最常用、低侵入的方案。它能从 Nginx access log 实时解析,自动暴露为 Prometheus 格式指标:
- 需先在 Nginx 中启用含
$status和$upstream_status的自定义日志格式,并写入独立日志文件 - 启动 nginxlog-exporter 时指定该日志路径和正则表达式,例如匹配
upstream_status:(\d+)或" (\d{3}) - 它会暴露类似
nginx_http_request_count_total{code="200", host="api.example.com"}和nginx_http_request_count_total{code="502", host="api.example.com"}的指标 - 注意:默认不带总请求数,建议额外加一条规则匹配所有行,生成
nginx_http_request_total{host="..."}作为分母
用 Prometheus 查询计算实时占比
有了分子和分母指标,就能用 PromQL 算出任意时间窗口内的占比。例如最近 5 分钟各状态码占本域名请求的比例:
-
200 占比:
sum(rate(nginx_http_request_count_total{code="200", host=~".+"}[5m])) by (host) / sum(rate(nginx_http_request_count_total{host=~".+"}[5m])) by (host) -
5xx 总占比:
sum(rate(nginx_http_request_count_total{code=~"5..", host=~".+"}[5m])) by (host) / sum(rate(nginx_http_request_count_total{host=~".+"}[5m])) by (host) - 结果是 0~1 的浮点数,Grafana 中可乘以 100 显示为百分比
按后端节点或静态/动态路径做细分统计
占比分析的价值在于定位问题,所以需要多维下钻:
- 若已用
$upstream_addr记录后端地址,可在 exporter 正则中提取并打标,得到{code="502", upstream="10.0.1.12:8080"},再算单节点错误率 - 对静态资源路径(如
/static/或.js),单独配置 location 并写入static_access.log,用另一个 nginxlog-exporter 实例监控,避免和动态接口混在一起 - 想看缓存效果?对比
status="304"和status="200"的比例变化,突降说明 ETag 失效或 CDN 配置异常
替代方案:OpenResty + shared dict 内存聚合
对超大流量或毫秒级响应要求的场景,可跳过日志落盘,直接在 Nginx 内存中统计:
- 用
log_by_lua_block在每个请求结束时,对ngx.var.status或ngx.var.upstream_status做原子自增 - 共享字典(
lua_shared_dict status_metrics 10m)存储200: 12489、502: 37等键值对 - 配一个
/metrics接口,用content_by_lua_block遍历字典,输出 OpenMetrics 格式,Prometheus 直接抓取 - 优势是零 IO、无延迟;缺点是需维护 OpenResty 环境,且 worker 间不自动同步(可用定时广播或中心化存储补足)


















