From 77847752fafa253aeac2e34b4b3ceacc3ba16c6b Mon Sep 17 00:00:00 2001 From: harish-berri Date: Sat, 25 Apr 2026 00:21:33 +0000 Subject: [PATCH] feat(auth): add Prometheus metrics for combined_view SQL queries - Introduced `litellm_auth_combined_view_queries_total` metric to track the number of combined_view SQL queries issued for virtual-key authentication. - Added `AuthMetrics` class to encapsulate metric incrementing logic. - Updated relevant code to increment the new metric on database lookups, aiding in the validation of Redis cache effectiveness. - Updated Prometheus metric definitions to include the new auth diagnostic metrics. --- litellm/integrations/prometheus.py | 14 +++++++ litellm/proxy/auth/auth_checks.py | 2 + litellm/proxy/auth/auth_metrics.py | 52 ++++++++++++++++++++++++ litellm/types/integrations/prometheus.py | 7 ++++ 4 files changed, 75 insertions(+) create mode 100644 litellm/proxy/auth/auth_metrics.py diff --git a/litellm/integrations/prometheus.py b/litellm/integrations/prometheus.py index 723b142dfad..1a899cf0e83 100644 --- a/litellm/integrations/prometheus.py +++ b/litellm/integrations/prometheus.py @@ -265,6 +265,20 @@ class PrometheusLogger(CustomLogger): ######################################## # LiteLLM Virtual API KEY metrics ######################################## + + # Auth DB load diagnostic: count direct combined_view SQL queries. + # Each increment means a virtual-key cache miss that hit the DB. + # Useful for validating that enable_redis_auth_cache is working. + self.litellm_auth_combined_view_queries_total = self._counter_factory( + "litellm_auth_combined_view_queries_total", + "Number of times the combined_view SQL query was issued for virtual-key auth. " + "Each count is a cache miss that hit the database. Use to validate " + "enable_redis_auth_cache is reducing DB load.", + labelnames=self.get_labels_for_metric( + "litellm_auth_combined_view_queries_total" + ), + ) + # Remaining MODEL RPM limit for API Key self.litellm_remaining_api_key_requests_for_model = self._gauge_factory( "litellm_remaining_api_key_requests_for_model", diff --git a/litellm/proxy/auth/auth_checks.py b/litellm/proxy/auth/auth_checks.py index 7b1d1c234d1..3cce911cd0c 100644 --- a/litellm/proxy/auth/auth_checks.py +++ b/litellm/proxy/auth/auth_checks.py @@ -60,6 +60,7 @@ from litellm.proxy._types import ( SpecialModelNames, UserAPIKeyAuth, ) +from litellm.proxy.auth.auth_metrics import AuthMetrics from litellm.proxy.auth.route_checks import RouteChecks from litellm.proxy.db.exception_handler import PrismaDBExceptionHandler from litellm.proxy.guardrails.tool_name_extraction import ( @@ -2257,6 +2258,7 @@ async def _fetch_key_object_from_db_with_reconnect( Fetch key object from DB and retry once if a DB connection error can be healed. """ try: + AuthMetrics.inc_combined_view_query(hashed_token) return await prisma_client.get_data( token=hashed_token, table_name="combined_view", diff --git a/litellm/proxy/auth/auth_metrics.py b/litellm/proxy/auth/auth_metrics.py new file mode 100644 index 00000000000..0b463cc920f --- /dev/null +++ b/litellm/proxy/auth/auth_metrics.py @@ -0,0 +1,52 @@ +""" +Prometheus metric helpers for the auth layer. + +All metrics are thin wrappers around the shared ``PrometheusLogger`` instance so +that every counter follows the same registration path (``_counter_factory``, +label-filter config) as the rest of LiteLLM's metrics. + +Usage:: + + from litellm.proxy.auth.auth_metrics import AuthMetrics + + AuthMetrics.inc_combined_view_query(hashed_token="sk-xxx") +""" + +from litellm._logging import verbose_proxy_logger + + +class AuthMetrics: + """Static helpers for incrementing auth-layer Prometheus counters.""" + + @staticmethod + def _get_prom(): + """Return the active PrometheusLogger, or None if Prometheus is not configured.""" + try: + from litellm.router_utils.cooldown_callbacks import ( + _get_prometheus_logger_from_callbacks, + ) + + return _get_prometheus_logger_from_callbacks() + except Exception: + return None + + @staticmethod + def inc_combined_view_query(hashed_token: str) -> None: + """ + Increment ``litellm_auth_combined_view_queries_total``. + + Called once per virtual-key DB lookup (combined_view query). Each + increment represents a cache miss that hit the database — use this to + validate that ``enable_redis_auth_cache`` is reducing DB load. + """ + try: + prom = AuthMetrics._get_prom() + if prom is not None: + prom.litellm_auth_combined_view_queries_total.labels( + hashed_api_key=hashed_token + ).inc() + except Exception as e: + verbose_proxy_logger.debug( + "AuthMetrics.inc_combined_view_query: failed to increment counter: %s", + e, + ) diff --git a/litellm/types/integrations/prometheus.py b/litellm/types/integrations/prometheus.py index 43a287f29bc..a4573535f72 100644 --- a/litellm/types/integrations/prometheus.py +++ b/litellm/types/integrations/prometheus.py @@ -228,6 +228,8 @@ DEFINED_PROMETHEUS_METRICS = Literal[ "litellm_guardrail_latency_seconds", "litellm_guardrail_errors_total", "litellm_guardrail_requests_total", + # Auth DB diagnostic metrics + "litellm_auth_combined_view_queries_total", # Cache metrics "litellm_cache_hits_metric", "litellm_cache_misses_metric", @@ -307,6 +309,11 @@ class PrometheusMetricLabels: litellm_guardrail_errors_total: List[str] = [] litellm_guardrail_requests_total: List[str] = [] + # Auth DB diagnostic - label by key so you can see which virtual key causes DB hits + litellm_auth_combined_view_queries_total = [ + UserAPIKeyLabelNames.API_KEY_HASH.value, + ] + litellm_proxy_total_requests_metric = [ UserAPIKeyLabelNames.END_USER.value, UserAPIKeyLabelNames.API_KEY_HASH.value,