diff --git a/python/sglang/srt/utils/common.py b/python/sglang/srt/utils/common.py index 74fbbe57a..7799ca903 100644 --- a/python/sglang/srt/utils/common.py +++ b/python/sglang/srt/utils/common.py @@ -1502,7 +1502,7 @@ def add_prometheus_middleware(app): def add_prometheus_track_response_middleware(app): - from prometheus_client import Counter + from prometheus_client import Counter, Gauge http_request_counter = Counter( name="sglang:http_requests_total", @@ -1516,6 +1516,13 @@ def add_prometheus_track_response_middleware(app): labelnames=["endpoint", "status_code", "method"], ) + http_requests_active = Gauge( + name="sglang:http_requests_active", + documentation="Number of currently active HTTP requests", + labelnames=["endpoint", "method"], + multiprocess_mode="livesum", + ) + @app.middleware("http") async def track_http_status_code(request, call_next): # With recording all requests, we have the risk of high cardinality if requests have arbitrary unhandled paths. @@ -1524,16 +1531,20 @@ def add_prometheus_track_response_middleware(app): method = request.method http_request_counter.labels(endpoint=path, method=method).inc() + http_requests_active.labels(endpoint=path, method=method).inc() - response = await call_next(request) + try: + response = await call_next(request) - http_response_counter.labels( - endpoint=path, - method=method, - status_code=str(response.status_code), - ).inc() + http_response_counter.labels( + endpoint=path, + method=method, + status_code=str(response.status_code), + ).inc() - return response + return response + finally: + http_requests_active.labels(endpoint=path, method=method).dec() # https://github.com/blueswen/fastapi-observability/blob/132a3c576f8b09e5311c68bd553215013bc75685/fastapi_app/utils.py#L98 diff --git a/test/srt/test_metrics.py b/test/srt/test_metrics.py index 9fed8451a..373318201 100644 --- a/test/srt/test_metrics.py +++ b/test/srt/test_metrics.py @@ -127,6 +127,7 @@ class TestEnableMetrics(CustomTestCase): "sglang:time_to_first_token_seconds", "sglang:inter_token_latency_seconds", "sglang:e2e_request_latency_seconds", + "sglang:http_requests_active", ] for metric in essential_metrics: self.assertIn(metric, metrics_text, f"Missing metric: {metric}")