Skip to content

[Metric] Support custom metric labels#7865

Open
liyonghua0910 wants to merge 1 commit into
PaddlePaddle:developfrom
liyonghua0910:develop+20260520_metric_labels
Open

[Metric] Support custom metric labels#7865
liyonghua0910 wants to merge 1 commit into
PaddlePaddle:developfrom
liyonghua0910:develop+20260520_metric_labels

Conversation

@liyonghua0910
Copy link
Copy Markdown
Collaborator

Motivation

Re-implement PR #4480 on current develop branch. The original PR introduced MetricsManagerInterface to support custom labels (e.g., model_id) on Prometheus metrics, but the codebase has changed significantly since then (WorkMetricsManager removed, new v1/serving_chat.py added, internal_adapter_utils.py no longer imports metrics, etc.).

Modifications

  1. New file fastdeploy/metrics/interface.py: Define MetricsManagerInterface with 4 abstract methods: set_value, inc_value, dec_value, obs_value.

  2. fastdeploy/metrics/metrics.py:

    • MetricsManager inherits from MetricsManagerInterface
    • Parse FD_DEFAULT_METRIC_LABEL_VALUES env var; when set to a valid non-empty JSON dict, enable metric labels
    • _patch_labelnames(): add label keys from _default_labelvalues to all metrics' labelnames
    • Implement the 4 interface methods: when labels enabled, call metric.labels(**merged).set()/inc()/dec()/observe(); otherwise, call metric.set()/inc()/dec()/observe() directly
    • Handle set_cache_config_info(), record_zmq_stats(), init_zmq_metrics(), _init_speculative_metrics() with label support
  3. fastdeploy/envs.py: Add FD_DEFAULT_METRIC_LABEL_VALUES environment variable

  4. 14 call-site files: Migrate all main_process_metrics.<metric>.set()/inc()/dec()/observe() calls to set_value()/inc_value()/dec_value()/obs_value()

  5. fastdeploy/metrics/metrics_middleware.py: Migrate HTTP metric .labels().inc()/.observe() to inc_value()/obs_value() with labelvalues parameter

Usage or Command

# Enable custom labels on all metrics
export FD_DEFAULT_METRIC_LABEL_VALUES='{"model_id":"qwen3-30b"}'

# Or with multiple labels
export FD_DEFAULT_METRIC_LABEL_VALUES='{"model_id":"qwen3-30b","version":"v2"}'

When not set (default {}), behavior is identical to current code — no labels are added.

Accuracy Tests

No model output changes. This only affects Prometheus metric formatting.

Checklist

  • Add at least a tag in the PR title.
  • Format your code, run pre-commit before commit.
  • Add unit tests. Please write the reason in this PR if no unit tests.
  • Provide accuracy results.
  • If the current PR is submitting to the release branch, make sure the PR has been submitted to the develop branch, then cherry-pick it to the release branch with the [Cherry-Pick] PR tag.

…e interface

Introduce MetricsManagerInterface with unified set_value/inc_value/dec_value/obs_value methods.
When FD_DEFAULT_METRIC_LABEL_VALUES is set to a valid non-empty JSON dict, metric labels
(e.g. model_id) are automatically applied. Otherwise, operations fall back to the raw
prometheus_client calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@paddle-bot
Copy link
Copy Markdown

paddle-bot Bot commented May 20, 2026

Thanks for your contribution!

Copy link
Copy Markdown

@PaddlePaddle-bot PaddlePaddle-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Paddle-CI-Agent | pr_review | 2026-05-20 18:25:06

📋 Review 摘要

PR 概述:为 Prometheus 指标添加自定义 label 支持(如 model_id),通过 FD_DEFAULT_METRIC_LABEL_VALUES 环境变量注入,并将全量 metric.set/inc/dec/observe() 调用迁移至统一接口方法 set_value/inc_value/dec_value/obs_value

变更范围fastdeploy/metrics/fastdeploy/engine/fastdeploy/cache_manager/fastdeploy/entrypoints/fastdeploy/output/fastdeploy/splitwise/

影响面 Tag[Engine] [KVCache] [Scheduler] [APIServer] [DataProcessor] [PD Disaggregation]

问题

级别 文件 概述
🟡 建议 fastdeploy/metrics/metrics.py:814 spec_decode_draft_single_head_acceptance_rate label 迁移逻辑矛盾,patched labelnames 被静默丢弃
📝 PR 规范 标题使用非官方 Tag [Metric],应改为 [Feature]

强制规则:表格中每一条有 文件:行号 的问题均已在 comments[] 中创建对应行间评论。

📝 PR 规范检查

标题 [Metric] 不在官方 Tag 列表中(官方无 [Metric] tag)。根据 diff 内容,本 PR 新增了自定义 label 注入特性,应使用 [Feature]。此外,Checklist 中 Add unit tests 未勾选,但 PR 正文未说明不写单测的原因,请补充说明(如"仅影响 metrics 格式化,无模型逻辑,暂不补充单测"等)。

标题建议(可直接复制):

  • [Feature] Support custom metric labels

PR 描述建议(可直接复制,必须复刻 checklist §D2 模板的完整结构):

## Motivation

Re-implement PR #4480 on current develop branch. The original PR introduced `MetricsManagerInterface` to support custom labels (e.g., `model_id`) on Prometheus metrics, but the codebase has changed significantly since then (`WorkMetricsManager` removed, new `v1/serving_chat.py` added, `internal_adapter_utils.py` no longer imports metrics, etc.).

## Modifications

1. **New file `fastdeploy/metrics/interface.py`**: Define `MetricsManagerInterface` with 4 abstract methods: `set_value`, `inc_value`, `dec_value`, `obs_value`.

2. **`fastdeploy/metrics/metrics.py`**:
   - `MetricsManager` inherits from `MetricsManagerInterface`
   - Parse `FD_DEFAULT_METRIC_LABEL_VALUES` env var; when set to a valid non-empty JSON dict, enable metric labels
   - `_patch_labelnames()`: add label keys from `_default_labelvalues` to all metrics' `labelnames`
   - Implement the 4 interface methods: when labels enabled, call `metric.labels(**merged).set()/inc()/dec()/observe()`; otherwise, call `metric.set()/inc()/dec()/observe()` directly
   - Handle `set_cache_config_info()`, `record_zmq_stats()`, `init_zmq_metrics()`, `_init_speculative_metrics()` with label support

3. **`fastdeploy/envs.py`**: Add `FD_DEFAULT_METRIC_LABEL_VALUES` environment variable

4. **14 call-site files**: Migrate all `main_process_metrics.<metric>.set()/inc()/dec()/observe()` calls to `set_value()/inc_value()/dec_value()/obs_value()`

5. **`fastdeploy/metrics/metrics_middleware.py`**: Migrate HTTP metric `.labels().inc()/.observe()` to `inc_value()/obs_value()` with `labelvalues` parameter

## Usage or Command

```bash
# Enable custom labels on all metrics
export FD_DEFAULT_METRIC_LABEL_VALUES='{"model_id":"qwen3-30b"}'

# Or with multiple labels
export FD_DEFAULT_METRIC_LABEL_VALUES='{"model_id":"qwen3-30b","version":"v2"}'
```

When not set (default `{}`), behavior is identical to current code — no labels are added.

## Accuracy Tests

No model output changes. This only affects Prometheus metric formatting.

## Checklist

- [x] Add at least a tag in the PR title.
  - Tag list: [`[FDConfig]`,`[APIServer]`,`[Engine]`, `[Scheduler]`, `[PD Disaggregation]`, `[Executor]`, `[Graph Optimization]`, `[Speculative Decoding]`, `[RL]`, `[Models]`, `[Quantization]`, `[Loader]`, `[OP]`, `[KVCache]`, `[DataProcessor]`, `[BugFix]`, `[Docs]`, `[CI]`, `[Optimization]`, `[Feature]`, `[Benchmark]`, `[Others]`, `[XPU]`, `[HPU]`, `[GCU]`, `[DCU]`, `[Iluvatar]`, `[Metax]`]
  - You can add new tags based on the PR content, but the semantics must be clear.
- [x] Format your code, run `pre-commit` before commit.
- [ ] Add unit tests. Please write the reason in this PR if no unit tests. <!-- 请补充说明不写单测的原因,例如:仅影响 Prometheus metrics 格式化,不涉及模型推理逻辑,暂不补充单测 -->
- [x] Provide accuracy results.
- [ ] If the current PR is submitting to the `release` branch, make sure the PR has been submitted to the `develop` branch, then cherry-pick it to the `release` branch with the `[Cherry-Pick]` PR tag.

总体评价

整体实现思路清晰,接口抽象合理,默认行为无变更(FD_DEFAULT_METRIC_LABEL_VALUES 未设置时与旧代码完全兼容)。建议修复 spec_decode_draft_single_head_acceptance_rate 的 label 迁移一致性问题,并完善 PR 规范(标题 Tag + 单测说明)。


patched_spec_metrics = self._patch_labelnames(self.SPECULATIVE_METRICS)

for metric_name, config in patched_spec_metrics.items():
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 建议 spec_decode_draft_single_head_acceptance_rate 的 label 迁移存在逻辑矛盾

_patch_labelnames 会对所有 SPECULATIVE_METRICS 条目(包括此条目)注入 labelnames;但随后 if 分支创建 per-head Gauge 列表时,是硬编码构造,完全不使用 config["kwargs"],导致 patched 的 labelnames 被静默丢弃。

实际效果:当 _enable_labels=True 时,其他投机解码指标(如 spec_decode_draft_acceptance_rate)会携带 model_id 等 default label,但 spec_decode_draft_single_head_acceptance_rate_0/1/... 不携带,造成指标体系不一致。

如果有意不对该指标迁移 label,建议在 _patch_labelnames 中显式跳过它(而非 patch 后再丢弃),例如:

def _patch_labelnames(self, metrics_dict: dict, skip_names: set = None) -> dict:
    skip_names = skip_names or set()
    for name, config in metrics_dict.items():
        if name in skip_names:
            patched[name] = copy.deepcopy(config)
            continue
        ...

然后调用:self._patch_labelnames(self.SPECULATIVE_METRICS, skip_names={"spec_decode_draft_single_head_acceptance_rate"})

@PaddlePaddle-bot
Copy link
Copy Markdown

PaddlePaddle-bot commented May 20, 2026

🤖 Paddle-CI-Agent | ci_status_monitor | 2026-05-21 04:36:18

CI报告基于以下代码生成(30分钟更新一次):


1 任务总览

Required 任务存在 3 个失败项(主单测、Approval、Pre Commit),当前不建议合入;需先修复单测/代码规范并完成人工审批。Optional 任务另有 3 个失败项,仅供参考。

总执行(rerun次数) 总任务 ✅ 通过 ❌ 失败 ⏳ 运行中 ⏸️ 等待中 跳过
41(0) 41 35 6 0 0 0

2 任务状态汇总

日志列说明:失败任务直接使用日志链接;运行中任务显示 Job 链接。

2.1 Required任务 : 7/10 通过

必选任务阻塞合并,失败需优先处理。

状态 任务 耗时 根因 修复建议 日志 重跑
Run FastDeploy Unit Tests and Coverage / run_tests_with_coverage 1h21m PR问题:指标接口迁移后测试桩未同步 同步测试 mock/stub 到 set_value 等接口 Job -
Approval 7s 需要 Approval 请通过人工审批 Job -
Pre Commit 38s PR问题:isort 自动修正2个导入顺序文件 运行 pre-commit 并提交 isort 修复 Job -
其余 7 个必选任务通过 - - - - -

2.2 可选任务 — 28/31 通过

可选任务不阻塞合并,失败仅供参考。

状态 任务 耗时 日志 重跑
Run iluvatar Tests / run_iluvatar_cases 1m35s Job -
Trigger Jenkins for PR 7m41s Job -
CI_HPU 1h3m Job -
其余 28 个可选任务通过 - - -

3 失败详情(仅 required)

Run FastDeploy Unit Tests and Coverage / run_tests_with_coverage — 测试失败(置信度: 高)

Run FastDeploy Unit Tests and Coverage / run_tests_with_coverage

  • 状态: ❌ 失败
  • 错误类型: 测试失败
  • 置信度: 高
  • 根因摘要: 指标接口迁移后测试桩未同步
  • 分析器: ci_analyze_unittest_fastdeploy

失败用例:

测试 错误 根因
tests/cache_manager/test_prefix_cache_manager.py::PrefixCacheManagerTest::test_free_cpu_block_ids_eviction TypeError: _DummyMetric object is not callable PrefixCacheManager 改为调用 main_process_metrics.set_value(...),测试替身未实现新接口
tests/engine/test_resource_manager.py::test_availability_and_sufficiency AttributeError: SimpleNamespace has no attribute set_value ResourceManager 初始化时调用 set_value("max_batch_size", ...),fixture 仍只模拟旧 metric 属性
tests/metrics/test_metrics_middleware.py::test_dispatch_successful_request AssertionError: labels called 0 times middleware 已改为 inc_value/obs_value,测试仍断言 .labels().inc()/observe()
tests/metrics/test_new_metrics.py::TestCoverageFix::test_recycle_resources_updates_metrics AssertionError: .available_batch_size.set called 0 times _recycle_resources 已改为统一 set_value,测试仍断言旧 Gauge.set
tests/output/test_token_processor.py::test_record_speculative_decoding_metrics_tracks_acceptance AttributeError: _Metrics has no attribute set_value _Metrics 测试桩未实现 set_value/inc_value 新接口
tests/engine/test_common_engine.py::TestCommonEngineAdditionalCoverage::test_insert_zmq_task_normal_request_with_worker_pid AssertionError: request_worker_map 为空 DummyMetrics 未实现 inc_value,请求插入流程异常后未完成映射断言

根因详情:
本 PR 将大量指标写入从 main_process_metrics.<metric>.set()/inc()/observe() 迁移为 main_process_metrics.set_value()/inc_value()/obs_value()(见 fastdeploy/metrics/metrics.py:739-769)。生产代码的迁移覆盖了 PrefixCacheManagerResourceManagerPrometheusMiddlewareTokenProcessorCommonEngine 等路径,但对应单测中的 mock、DummyMetrics、_Metrics 和断言仍按旧 Prometheus metric 对象接口编写,导致 AttributeError/TypeError 或旧调用断言失败。失败与本 PR 的 metric labels 接口改造直接相关,属于 PR 问题。

关键日志:

fastdeploy/cache_manager/prefix_cache_manager.py:134: TypeError: '_DummyMetric' object is not callable
fastdeploy/engine/resource_manager.py:73: AttributeError: 'types.SimpleNamespace' object has no attribute 'set_value'
tests/metrics/test_metrics_middleware.py:75: AssertionError: Expected 'labels' to be called once. Called 0 times.
tests/metrics/test_new_metrics.py:101: AssertionError: Expected 'set' to be called once. Called 0 times.
fastdeploy/output/token_processor.py:1138: AttributeError: '_Metrics' object has no attribute 'set_value'
tests/engine/test_common_engine.py:3360: AssertionError: 'normal-batch' not found in {}

修复建议:

  1. 将相关单测 mock/stub 同步到新接口:在 tests/output/test_token_processor.py_Metricstests/engine/test_common_engine.pyDummyMetricstests/engine/test_resource_manager.py / tests/cache_manager/test_prefix_cache_manager.py 的 metrics fixture 中实现 set_value/inc_value/dec_value/obs_value,按 name 分发到原 dummy metric。
  2. 更新 tests/metrics/test_metrics_middleware.py:74-79tests/metrics/test_new_metrics.py:100-101 的断言,改为校验 main_process_metrics.inc_value("http_requests_total", labelvalues=...)obs_value(...)set_value("available_batch_size", 8) 等新接口调用。
  3. 如需保持单测兼容旧替身,可在测试专用 dummy 类中同时保留旧 metric 属性与新统一接口,避免覆盖率补充用例因接口迁移失效。

修复建议摘要: 同步测试 mock/stub 到 set_value 等接口

关联变更: fastdeploy/metrics/metrics.py:739-769fastdeploy/metrics/metrics_middleware.py:55-60fastdeploy/cache_manager/prefix_cache_manager.py:134-138fastdeploy/engine/resource_manager.py:73fastdeploy/output/token_processor.py:1138-1160fastdeploy/engine/common_engine.py:1328

链接: 查看日志

Approval — 需要 Approval(置信度: 高)

该 Job 需要人工 Approval,完成审批后 CI 才会继续执行。

修复建议摘要: 请通过人工审批

链接: 查看日志

Pre Commit — 代码规范(置信度: 高)

Pre Commit

  • 状态: ❌ 失败
  • 错误类型: 代码规范
  • 置信度: 高
  • 根因摘要: isort 自动修正 2 个文件导入顺序
  • 分析器: 通用分析(fallback)

根因详情:
Check pre-commit 步骤中 isort 失败,日志显示 hook 自动修改了 fastdeploy/cache_manager/transfer_factory/kvcache_transfer/benchmark.pyfastdeploy/cache_manager/transfer_factory/kvcache_transfer/test.py。修改内容为调整 import rdma_commimport zmq 的排序/分组,属于 PR 未提交本地格式化结果导致的代码规范失败。

关键日志:

isort....................................................................Failed
- hook id: isort
- files were modified by this hook
Fixing /home/runner/work/FastDeploy/FastDeploy/fastdeploy/cache_manager/transfer_factory/kvcache_transfer/benchmark.py
Fixing /home/runner/work/FastDeploy/FastDeploy/fastdeploy/cache_manager/transfer_factory/kvcache_transfer/test.py
-import zmq
-
 import rdma_comm
+import zmq

修复建议:

  1. 在本地运行 pre-commit run --files fastdeploy/cache_manager/transfer_factory/kvcache_transfer/benchmark.py fastdeploy/cache_manager/transfer_factory/kvcache_transfer/test.py,提交 isort 自动修复后的导入顺序。
  2. 推送前可执行 CI 日志给出的完整 pre-commit run --files ... 命令,确保所有变更文件通过代码规范检查。

修复建议摘要: 运行 pre-commit 并提交 isort 修复

关联变更: fastdeploy/cache_manager/transfer_factory/kvcache_transfer/benchmark.py:34-37fastdeploy/cache_manager/transfer_factory/kvcache_transfer/test.py:14-17

链接: 查看日志

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 20, 2026

Codecov Report

❌ Patch coverage is 67.46988% with 54 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (develop@d54e207). Learn more about missing BASE report.

Files with missing lines Patch % Lines
fastdeploy/metrics/metrics.py 45.23% 37 Missing and 9 partials ⚠️
fastdeploy/engine/resource_manager.py 55.55% 4 Missing ⚠️
fastdeploy/engine/common_engine.py 66.66% 3 Missing ⚠️
fastdeploy/output/token_processor.py 95.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             develop    #7865   +/-   ##
==========================================
  Coverage           ?   62.71%           
==========================================
  Files              ?      463           
  Lines              ?    64506           
  Branches           ?     9898           
==========================================
  Hits               ?    40456           
  Misses             ?    21282           
  Partials           ?     2768           
Flag Coverage Δ
GPU 71.71% <67.46%> (?)
XPU 7.14% <13.85%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants