Skip to content

Commit abe7449

Browse files
Add Prometheus gauges for IGW-compatible metrics scraping
1 parent 789494f commit abe7449

1 file changed

Lines changed: 57 additions & 2 deletions

File tree

tensorrt_llm/metrics/collector.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,19 @@ class MetricsCollector:
4040
trtllm_request_queue_time_seconds
4141
trtllm_kv_cache_hit_rate
4242
trtllm_kv_cache_utilization
43+
trtllm_num_requests_waiting
44+
trtllm_num_requests_running
45+
trtllm_cache_config_info
4346
"""
4447
labelname_finish_reason = "finished_reason"
4548

4649
def __init__(self, labels: Dict[str, str]) -> None:
50+
"""Initialize Prometheus metrics with the given labels.
51+
52+
Args:
53+
labels: Key-value pairs added as metadata to all metrics
54+
(e.g. ``{"model_name": "llama", "engine_type": "trtllm"}``).
55+
"""
4756
from prometheus_client import Counter, Gauge, Histogram
4857
self.last_log_time = time.time()
4958
self.labels = labels
@@ -109,6 +118,28 @@ def __init__(self, labels: Dict[str, str]) -> None:
109118
documentation="KV cache utilization",
110119
labelnames=self.labels.keys())
111120

121+
self.num_requests_waiting = Gauge(
122+
name=self.metric_prefix + "num_requests_waiting",
123+
documentation=
124+
"Current number of requests waiting in the queue.",
125+
labelnames=self.labels.keys())
126+
self.num_requests_running = Gauge(
127+
name=self.metric_prefix + "num_requests_running",
128+
documentation=
129+
"Current number of requests actively being processed.",
130+
labelnames=self.labels.keys())
131+
132+
self.cache_config_info = Gauge(
133+
name=self.metric_prefix + "cache_config_info",
134+
documentation=
135+
"Information about the KV cache configuration.",
136+
labelnames=[*self.labels.keys(), "block_size", "num_gpu_blocks"])
137+
138+
# Initialize gauges so they appear in /prometheus/metrics at startup
139+
self._log_gauge(self.num_requests_waiting, 0)
140+
self._log_gauge(self.num_requests_running, 0)
141+
self._log_gauge(self.kv_cache_utilization, 0)
142+
112143
def _label_merge(self, labels: Dict[str, str]) -> Dict[str, str]:
113144
if labels is None or len(labels) == 0:
114145
return self.labels
@@ -182,16 +213,22 @@ def log_iteration_stats(self, iteration_stats: dict) -> None:
182213
This method updates Prometheus metrics including:
183214
- kv_cache_hit_rate
184215
- kv_cache_utilization
216+
- num_requests_waiting
217+
- num_requests_running
218+
- cache_config_info
185219
186220
Args:
187221
iteration_stats: A JSON dict returned from `BaseLLM.get_stats()` containing iteration-level statistics
188222
with the following expected structure:
223+
- "numQueuedRequests" (int): Number of requests waiting in the queue.
224+
- "numActiveRequests" (int): Number of requests actively being processed.
189225
- "kvCacheStats" (dict): KV cache statistics containing:
190226
- "cacheHitRate" (float): Cache hit rate (0.0 to 1.0). If present (including zero),
191227
the kv_cache_hit_rate gauge is updated.
192228
- "usedNumBlocks" (int): Number of KV cache blocks currently in use.
193229
- "maxNumBlocks" (int): Maximum number of KV cache blocks available. Should always be
194230
non-zero.
231+
- "tokensPerBlock" (int): Number of tokens per KV cache block.
195232
196233
Returns:
197234
None: Metrics are logged to Prometheus; nothing is returned.
@@ -201,12 +238,30 @@ def log_iteration_stats(self, iteration_stats: dict) -> None:
201238
- KV cache utilization is only calculated and logged when both "usedNumBlocks" and
202239
"maxNumBlocks" are present in kvCacheStats and "maxNumBlocks" is non-zero.
203240
"""
241+
num_queued = iteration_stats.get("numQueuedRequests")
242+
if num_queued is not None:
243+
self._log_gauge(self.num_requests_waiting, num_queued)
244+
245+
num_active = iteration_stats.get("numActiveRequests")
246+
if num_active is not None:
247+
self._log_gauge(self.num_requests_running, num_active)
248+
204249
if kv_stats := iteration_stats.get("kvCacheStats"):
205250
cache_hit_rate = kv_stats.get("cacheHitRate")
206251
if cache_hit_rate is not None:
207252
self._log_gauge(self.kv_cache_hit_rate, cache_hit_rate)
208-
if "usedNumBlocks" in kv_stats and "maxNumBlocks" in kv_stats:
209-
max_num_blocks = kv_stats["maxNumBlocks"]
253+
254+
max_num_blocks = kv_stats.get("maxNumBlocks")
255+
if "usedNumBlocks" in kv_stats and max_num_blocks is not None:
210256
if max_num_blocks:
211257
utilization = kv_stats["usedNumBlocks"] / max_num_blocks
212258
self._log_gauge(self.kv_cache_utilization, utilization)
259+
260+
tokens_per_block = kv_stats.get("tokensPerBlock")
261+
if tokens_per_block is not None and max_num_blocks is not None:
262+
cache_config_labels = {
263+
**self.labels,
264+
"block_size": str(tokens_per_block),
265+
"num_gpu_blocks": str(max_num_blocks),
266+
}
267+
self.cache_config_info.labels(**cache_config_labels).set(1)

0 commit comments

Comments
 (0)