From 485bfedadae2c02be534b5dde2c41e1fa7b86dab Mon Sep 17 00:00:00 2001 From: Seiji Eicher Date: Mon, 14 Jul 2025 16:37:42 -0700 Subject: [PATCH 1/2] Add add_logger API to AsyncLLM Signed-off-by: Seiji Eicher --- tests/v1/metrics/test_ray_metrics.py | 4 ++-- vllm/v1/engine/async_llm.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/tests/v1/metrics/test_ray_metrics.py b/tests/v1/metrics/test_ray_metrics.py index 0898ae65e7c..e9bf3d9727f 100644 --- a/tests/v1/metrics/test_ray_metrics.py +++ b/tests/v1/metrics/test_ray_metrics.py @@ -43,8 +43,8 @@ async def run(self): disable_log_stats=False, ) - engine = AsyncLLM.from_engine_args( - engine_args, stat_loggers=[RayPrometheusStatLogger]) + engine = AsyncLLM.from_engine_args(engine_args) + await engine.add_logger(RayPrometheusStatLogger) for i, prompt in enumerate(example_prompts): results = engine.generate( diff --git a/vllm/v1/engine/async_llm.py b/vllm/v1/engine/async_llm.py index 3754570dfaa..97f84bc24cc 100644 --- a/vllm/v1/engine/async_llm.py +++ b/vllm/v1/engine/async_llm.py @@ -608,6 +608,25 @@ async def collective_rpc(self, return await self.engine_core.collective_rpc_async( method, timeout, args, kwargs) + async def add_logger(self, logger_factory: StatLoggerFactory) -> None: + if not self.log_stats: + raise RuntimeError( + "Stat logging is disabled. Set `disable_log_stats=False` " + "argument to enable.") + + engine_num = self.vllm_config.parallel_config.data_parallel_size + if len(self.stat_loggers) == 0: + self.stat_loggers = [[] for _ in range(engine_num)] + + logger_type = type(logger_factory) + for logger in self.stat_loggers[0]: + if type(logger) is logger_type: + raise KeyError( + f"Logger with type {logger_type} already exists.") + + for i, logger_list in enumerate(self.stat_loggers): + logger_list.append(logger_factory(self.vllm_config, i)) + @property def is_running(self) -> bool: # Is None before the loop is started. From ba96afc6534a917b46e5f1a6c2c0b253f429d2d3 Mon Sep 17 00:00:00 2001 From: Seiji Eicher Date: Tue, 15 Jul 2025 17:05:21 -0700 Subject: [PATCH 2/2] Simplify by avoiding duplicate logger checks Signed-off-by: Seiji Eicher --- tests/v1/metrics/test_engine_logger_apis.py | 29 +++++++++++++++++++++ tests/v1/metrics/test_ray_metrics.py | 4 +-- vllm/v1/engine/async_llm.py | 6 ----- 3 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 tests/v1/metrics/test_engine_logger_apis.py diff --git a/tests/v1/metrics/test_engine_logger_apis.py b/tests/v1/metrics/test_engine_logger_apis.py new file mode 100644 index 00000000000..c633a2d4a4f --- /dev/null +++ b/tests/v1/metrics/test_engine_logger_apis.py @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project +import pytest + +from vllm.v1.engine.async_llm import AsyncEngineArgs, AsyncLLM +from vllm.v1.metrics.loggers import PrometheusStatLogger + + +@pytest.mark.asyncio +async def test_async_llm_add_logger(): + # Minimal model config for test + model_name = "distilbert/distilgpt2" + dtype = "half" + engine_args = AsyncEngineArgs( + model=model_name, + dtype=dtype, + disable_log_stats=False, + enforce_eager=True, + ) + + # Force empty list to avoid default loggers + engine = AsyncLLM.from_engine_args(engine_args, stat_loggers=[]) + + # Add PrometheusStatLogger and verify no exception is raised + await engine.add_logger(PrometheusStatLogger) + + # Verify that logger is present in the first DP rank + assert len(engine.stat_loggers[0]) == 1 + assert isinstance(engine.stat_loggers[0][0], PrometheusStatLogger) \ No newline at end of file diff --git a/tests/v1/metrics/test_ray_metrics.py b/tests/v1/metrics/test_ray_metrics.py index e9bf3d9727f..0898ae65e7c 100644 --- a/tests/v1/metrics/test_ray_metrics.py +++ b/tests/v1/metrics/test_ray_metrics.py @@ -43,8 +43,8 @@ async def run(self): disable_log_stats=False, ) - engine = AsyncLLM.from_engine_args(engine_args) - await engine.add_logger(RayPrometheusStatLogger) + engine = AsyncLLM.from_engine_args( + engine_args, stat_loggers=[RayPrometheusStatLogger]) for i, prompt in enumerate(example_prompts): results = engine.generate( diff --git a/vllm/v1/engine/async_llm.py b/vllm/v1/engine/async_llm.py index 97f84bc24cc..30e01a43903 100644 --- a/vllm/v1/engine/async_llm.py +++ b/vllm/v1/engine/async_llm.py @@ -618,12 +618,6 @@ async def add_logger(self, logger_factory: StatLoggerFactory) -> None: if len(self.stat_loggers) == 0: self.stat_loggers = [[] for _ in range(engine_num)] - logger_type = type(logger_factory) - for logger in self.stat_loggers[0]: - if type(logger) is logger_type: - raise KeyError( - f"Logger with type {logger_type} already exists.") - for i, logger_list in enumerate(self.stat_loggers): logger_list.append(logger_factory(self.vllm_config, i))