@@ -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