@@ -129,6 +129,48 @@ def normalize_authorization_result(result: str) -> str:
129129 return result
130130 return AUTHORIZATION_RESULT_ERROR
131131
132+
133+ QUOTA_TYPE_USER_ID : Final [str ] = "user_id"
134+ QUOTA_TYPE_ORG_ID : Final [str ] = "org_id"
135+ QUOTA_TYPE_SYSTEM_ID : Final [str ] = "system_id"
136+ QUOTA_TYPE_DISABLED : Final [str ] = "disabled"
137+ QUOTA_RESULT_SUCCESS : Final [str ] = "success"
138+ QUOTA_RESULT_FAILURE : Final [str ] = "failure"
139+ QUOTA_RESULT_SKIPPED : Final [str ] = "skipped"
140+ QUOTA_RESULT_ERROR : Final [str ] = "error"
141+
142+ ALLOWED_QUOTA_TYPES : Final [frozenset [str ]] = frozenset (
143+ {
144+ QUOTA_TYPE_USER_ID ,
145+ QUOTA_TYPE_ORG_ID ,
146+ QUOTA_TYPE_SYSTEM_ID ,
147+ QUOTA_TYPE_DISABLED ,
148+ }
149+ )
150+ ALLOWED_QUOTA_RESULTS : Final [frozenset [str ]] = frozenset (
151+ {
152+ QUOTA_RESULT_SUCCESS ,
153+ QUOTA_RESULT_FAILURE ,
154+ QUOTA_RESULT_SKIPPED ,
155+ QUOTA_RESULT_ERROR ,
156+ }
157+ )
158+
159+
160+ def normalize_quota_type (quota_type : str ) -> str :
161+ """Return a bounded quota type label for Prometheus cardinality safety."""
162+ if quota_type in ALLOWED_QUOTA_TYPES :
163+ return quota_type
164+ return QUOTA_TYPE_USER_ID
165+
166+
167+ def normalize_quota_result (result : str ) -> str :
168+ """Return a bounded quota result label for Prometheus cardinality safety."""
169+ if result in ALLOWED_QUOTA_RESULTS :
170+ return result
171+ return QUOTA_RESULT_ERROR
172+
173+
132174@contextmanager
133175def measure_response_duration (path : str ) -> Iterator [None ]:
134176 """Measure REST API response duration for a route path.
@@ -273,7 +315,6 @@ def record_llm_inference_duration(
273315 logger .warning ("Failed to update LLM inference duration metric" , exc_info = True )
274316
275317
276-
277318def record_auth_attempt (auth_module : str , result : str , reason : str ) -> None :
278319 """Record one authentication attempt.
279320
@@ -349,3 +390,28 @@ def record_authorization_duration(action: str, result: str, duration: float) ->
349390 ).observe (duration )
350391 except (AttributeError , TypeError , ValueError ):
351392 logger .warning ("Failed to update authorization duration metric" , exc_info = True )
393+
394+
395+ def record_quota_check (
396+ endpoint_path : str , quota_type : str , result : str , duration : float
397+ ) -> None :
398+ """Record a quota availability check.
399+
400+ Args:
401+ endpoint_path: API endpoint path for metric labeling.
402+ quota_type: Bounded quota subject type, not the subject identifier. Out-of-set
403+ values are recorded as ``user_id``.
404+ result: Bounded result label. Out-of-set values are recorded as ``error``.
405+ duration: Quota check duration in seconds.
406+ """
407+ normalized_quota_type = normalize_quota_type (quota_type )
408+ normalized_result = normalize_quota_result (result )
409+ try :
410+ metrics .quota_checks_total .labels (
411+ endpoint_path , normalized_quota_type , normalized_result
412+ ).inc ()
413+ metrics .quota_check_duration_seconds .labels (
414+ endpoint_path , normalized_quota_type , normalized_result
415+ ).observe (duration )
416+ except (AttributeError , TypeError , ValueError ):
417+ logger .warning ("Failed to update quota check metrics" , exc_info = True )
0 commit comments