变更内容: - 删除 `start_metrics.sh` 脚本,精简项目结构,移除不再需要的启动逻辑。 - 优化 HTTP 请求指标记录,新增健康检查端点过滤和路径参数规范化功能。 - 更新文档,添加指标过滤及路径规范化的详细说明。 - 提高 Prometheus 指标的性能和可维护性,避免标签基数爆炸。
3.5 KiB
3.5 KiB
指标过滤和路径规范化
变更说明
本次修改优化了 HTTP 请求指标的记录逻辑,主要包括两个方面:
1. 跳过健康检查端点
以下端点不再记录到 Prometheus 指标中:
/metrics- 指标端点本身/healthz- 存活检查/readyz- 就绪检查
原因:这些端点通常被频繁调用(如 Kubernetes 健康检查、Prometheus 抓取),但对业务监控意义不大,会产生大量噪音数据。
2. 路径参数规范化
带有路径参数的端点会被规范化为模板形式:
| 原始路径 | 规范化后 |
|---|---|
GET /jobs/a1b2c3d4e5f6 |
GET /jobs/{job_id} |
GET /jobs/xyz123456789 |
GET /jobs/{job_id} |
原因:避免因为不同的路径参数值产生过多的指标标签,导致指标基数爆炸(cardinality explosion),影响 Prometheus 性能。
实现细节
代码修改
文件:src/functional_scaffold/main.py
- 添加
normalize_path()函数:
def normalize_path(path: str) -> str:
"""规范化路径,将路径参数替换为模板形式"""
if path.startswith("/jobs/") and len(path) > 6:
return "/jobs/{job_id}"
return path
- 修改
track_metrics中间件:
# 跳过不需要记录指标的端点
skip_paths = {"/metrics", "/readyz", "/healthz"}
if request.url.path in skip_paths:
return await call_next(request)
# 使用规范化后的路径记录指标
normalized_path = normalize_path(request.url.path)
incr("http_requests_total",
{"method": request.method, "endpoint": normalized_path, "status": status})
测试覆盖
文件:tests/test_middleware.py
新增 6 个测试用例:
test_normalize_jobs_path- 测试任务路径规范化test_normalize_other_paths- 测试其他路径保持不变test_normalize_jobs_root- 测试 /jobs 根路径test_skip_health_endpoints- 测试跳过健康检查端点test_record_normal_endpoints- 测试记录普通端点test_normalize_job_path- 测试规范化任务路径的集成测试
所有测试通过:✅ 56/56 passed
验证方法
手动测试
使用提供的测试脚本:
./scripts/test_metrics_filtering.sh
预期结果
访问 /metrics 端点后,应该看到:
✅ 应该出现的指标:
http_requests_total{method="POST",endpoint="/invoke",status="success"} 1
http_requests_total{method="GET",endpoint="/jobs/{job_id}",status="error"} 2
❌ 不应该出现的指标:
http_requests_total{method="GET",endpoint="/healthz",...}
http_requests_total{method="GET",endpoint="/readyz",...}
http_requests_total{method="GET",endpoint="/metrics",...}
http_requests_total{method="GET",endpoint="/jobs/a1b2c3d4e5f6",...}
扩展性
如果需要添加更多路径规范化规则,只需修改 normalize_path() 函数:
def normalize_path(path: str) -> str:
"""规范化路径,将路径参数替换为模板形式"""
# 任务路径
if path.startswith("/jobs/") and len(path) > 6:
return "/jobs/{job_id}"
# 用户路径(示例)
if path.startswith("/users/") and len(path) > 7:
return "/users/{user_id}"
# 其他路径保持不变
return path
影响范围
- ✅ 不影响现有功能
- ✅ 不影响 API 行为
- ✅ 仅影响指标记录逻辑
- ✅ 向后兼容
- ✅ 所有测试通过