feat(observability): persist forward pass metrics traces - #11110
Conversation
This comment has been minimized.
This comment has been minimized.
tedzhouhk
left a comment
There was a problem hiding this comment.
One additional lifecycle issue found while reviewing the persistence path.
WalkthroughAdds opt-in forward-pass-metrics (FPM) trace capture: a Python env parser (DYN_FPM_TRACE), a Rust fpm_trace module (config, telemetry bus, sink with sampled/full write modes), tap points in publisher paths, gzip segment retention across sinks, backend wiring in vLLM/sglang, and new documentation. ChangesForward Pass Metrics Tracing
Estimated code review effort: 4 (Complex) | ~60 minutes Related PRs: None specified. Suggested labels: observability, feature, rust, python, documentation Suggested reviewers: None specified. 🐇 A trace of hops, gzip-tucked and light, 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
components/src/dynamo/sglang/tests/test_sglang_unit.py (1)
469-496: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a precedence test for explicit port + trace both set.
The vLLM test suite covers the "explicit port wins when trace is enabled" case (
test_explicit_port_wins_when_trace_is_enabled); the sglang suite lacks a matching test even thoughparse_argsimplements the sameif explicit_fpm_port ... elif fpm_trace_enabled()precedence.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@components/src/dynamo/sglang/tests/test_sglang_unit.py` around lines 469 - 496, The sglang tests are missing coverage for the precedence path where both an explicit forward-pass metrics port and DYN_FPM_TRACE are set. Add a new async test alongside the existing parse_args tests in test_sglang_unit.py that sets DYN_FORWARDPASS_METRIC_PORT and DYN_FPM_TRACE together, invokes mock_sglang_cli and parse_args, and asserts server_args.enable_forward_pass_metrics remains enabled because the explicit port should win. Use the existing parse_args, mock_sglang_cli, and server_args.enable_forward_pass_metrics symbols to keep the test aligned with the current precedence logic.lib/llm/src/fpm_trace/config.rs (1)
60-86: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate numeric-parsing helpers.
positive_u64_from_envandpositive_usize_from_envare identical apart from the numeric type. Consider collapsing into one generic helper.♻️ Proposed generic helper
-fn positive_u64_from_env(name: &str, default: u64) -> anyhow::Result<u64> { - let Some(value) = std::env::var(name).ok() else { - return Ok(default); - }; - let parsed = value - .trim() - .parse::<u64>() - .map_err(|_| anyhow::anyhow!("{name} must be a positive integer"))?; - if parsed == 0 { - anyhow::bail!("{name} must be greater than zero"); - } - Ok(parsed) -} - -fn positive_usize_from_env(name: &str, default: usize) -> anyhow::Result<usize> { - let Some(value) = std::env::var(name).ok() else { - return Ok(default); - }; - let parsed = value - .trim() - .parse::<usize>() - .map_err(|_| anyhow::anyhow!("{name} must be a positive integer"))?; - if parsed == 0 { - anyhow::bail!("{name} must be greater than zero"); - } - Ok(parsed) -} +fn positive_from_env<T>(name: &str, default: T) -> anyhow::Result<T> +where + T: std::str::FromStr + Copy + PartialEq + Default, +{ + let Some(value) = std::env::var(name).ok() else { + return Ok(default); + }; + let parsed = value + .trim() + .parse::<T>() + .map_err(|_| anyhow::anyhow!("{name} must be a positive integer"))?; + if parsed == T::default() { + anyhow::bail!("{name} must be greater than zero"); + } + Ok(parsed) +}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/llm/src/fpm_trace/config.rs` around lines 60 - 86, The numeric env parsing logic is duplicated in positive_u64_from_env and positive_usize_from_env, differing only by the target type. Refactor them into a single generic helper in config.rs that parses any positive integer type and reuse it from the existing callers, keeping the same default handling, trim/parse flow, and zero-check behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@components/src/dynamo/sglang/tests/test_sglang_unit.py`:
- Around line 499-515: Move the dynamo.common.utils.env import out of
test_invalid_fpm_trace_warns_and_does_not_enable_metrics and place it with the
other top-level imports in test_sglang_unit.py; then update the test to use the
top-level common_env symbol for monkeypatching
_fpm_trace_invalid_warning_emitted and for
caplog.at_level(logger=common_env.__name__) without any in-function imports.
In `@components/src/dynamo/vllm/tests/test_vllm_unit.py`:
- Around line 1233-1262: The test `test_trace_only_starts_relay_on_default_port`
is doing in-function imports of `dynamo.llm` and `dynamo.vllm.main`, which
violates the import guideline. Move those imports to the top of the test file
and keep the test body focused on patching `FpmEventRelay`,
`get_dp_range_for_worker`, and `setup_fpm_relay` behavior using the
already-imported modules.
- Around line 1196-1216: The two vLLM tests still import
dynamo.common.utils.env, dynamo.vllm.main, and dynamo.llm inside the test
bodies, but this file expects imports at module scope. Hoist those imports to
the top of the test module near the other imports, and only keep them local if
there is a deliberate import-side-effect isolation reason; update
test_invalid_trace_warns_once_and_does_not_enable_fpm and
test_trace_only_starts_relay_on_default_port to use the module-level symbols.
---
Nitpick comments:
In `@components/src/dynamo/sglang/tests/test_sglang_unit.py`:
- Around line 469-496: The sglang tests are missing coverage for the precedence
path where both an explicit forward-pass metrics port and DYN_FPM_TRACE are set.
Add a new async test alongside the existing parse_args tests in
test_sglang_unit.py that sets DYN_FORWARDPASS_METRIC_PORT and DYN_FPM_TRACE
together, invokes mock_sglang_cli and parse_args, and asserts
server_args.enable_forward_pass_metrics remains enabled because the explicit
port should win. Use the existing parse_args, mock_sglang_cli, and
server_args.enable_forward_pass_metrics symbols to keep the test aligned with
the current precedence logic.
In `@lib/llm/src/fpm_trace/config.rs`:
- Around line 60-86: The numeric env parsing logic is duplicated in
positive_u64_from_env and positive_usize_from_env, differing only by the target
type. Refactor them into a single generic helper in config.rs that parses any
positive integer type and reuse it from the existing callers, keeping the same
default handling, trim/parse flow, and zero-check behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: bf455de6-1239-49a2-9479-5598aa8eda2d
📒 Files selected for processing (20)
components/src/dynamo/common/utils/env.pycomponents/src/dynamo/common/utils/tests/test_env.pycomponents/src/dynamo/sglang/args.pycomponents/src/dynamo/sglang/tests/test_sglang_unit.pycomponents/src/dynamo/vllm/args.pycomponents/src/dynamo/vllm/envs.pycomponents/src/dynamo/vllm/main.pycomponents/src/dynamo/vllm/tests/test_vllm_unit.pydocs/index.ymldocs/observability/README.mddocs/observability/forward-pass-metrics-tracing.mdlib/llm/src/audit/sink.rslib/llm/src/fpm_publisher.rslib/llm/src/fpm_trace/config.rslib/llm/src/fpm_trace/mod.rslib/llm/src/fpm_trace/sink.rslib/llm/src/lib.rslib/llm/src/request_trace/sink.rslib/llm/src/telemetry/jsonl_gz.rslib/runtime/src/config/environment_names.rs
Signed-off-by: Jason Zhou (Engrg-Hardware 1) <jasonzho@nvidia.com>
0a021ed to
1ccd7eb
Compare
|
@coderabbitai review |
✅ Action performedReview finished.
|
1ccd7eb to
7b52781
Compare
|
@coderabbitai resolve |
✅ Action performedComments resolved. Approval is disabled; enable |
Signed-off-by: Jason Zhou (Engrg-Hardware 1) <jasonzho@nvidia.com>
7b52781 to
6683334
Compare
|
/ok to test 7065d41 |
@sachalmalick, there was an error processing your request: See the following link for more information: https://docs.gha-runners.nvidia.com/cpr/e/2/ |
|
/ok to test 6683334 |
Overview:
Add opt-in, best-effort producer-side persistence for forward-pass metrics (FPM). Supported vLLM/SGLang relay paths and direct TensorRT-LLM/mocker publishers can write bounded rotating gzip JSONL traces without putting disk I/O on the inference path.
Details:
--fpm-trace/--no-fpm-tracethrough the shared runtime argument system (backed byDYN_FPM_TRACE), and auto-enable backend FPM only for vLLM/SGLang topologies that actually create a Dynamo relay. Legacy explicit-port activation keeps precedence; unified, snapshot, embedding, headless, and other unsupported paths warn instead of silently producing no trace.DYN_FPM_*settings and document configuration, topology support, record shape, sizing, retention, shutdown, shared-volume I/O, and Kubernetes storage.Where should the reviewer start?
lib/llm/src/fpm_trace/mod.rsandlib/llm/src/fpm_trace/sink.rsfor ownership, queueing, sampling, and shutdown.lib/llm/src/telemetry/jsonl_gz.rsfor segment allocation, retention, and awaited close.components/src/dynamo/common/configuration/groups/runtime_args.py,components/src/dynamo/vllm/args.py, andcomponents/src/dynamo/sglang/args.pyfor CLI/env resolution and topology-aware activation.docs/observability/forward-pass-metrics-tracing.mdfor the operator contract and limitations.Related Issues
🚫 This PR is NOT linked to an issue:
Validation
cargo test --offline -p dynamo-llm --lib --no-default-features: 1,325 passed, 0 failed, 3 ignored.cargo clippy --offline -p dynamo-llm --lib --tests --no-default-features -- -D warnings.cargo fmt --all -- --check, andgit diff --check.The backend-specific vLLM/SGLang suites were not collected locally because those optional backend packages are not installed on this host. A production GPU acceptance soak was not run; PR CI remains the authority for those environments.