22
33import logging
44from dataclasses import dataclass , field
5- from typing import Dict , Optional , Any
5+ from enum import Enum
6+ from typing import Dict , Optional
67
78from prometheus_client import ( # type: ignore[import-not-found]
89 REGISTRY ,
1112 Gauge ,
1213 Histogram ,
1314 generate_latest ,
14- push_to_gateway ,
15- start_http_server ,
1615)
1716
17+ from cadence ._internal .visibility .metrics import MetricsEmitter
18+
1819
1920logger = logging .getLogger (__name__ )
2021
2324class PrometheusConfig :
2425 """Configuration for Prometheus metrics."""
2526
26- # HTTP server configuration
27- enable_http_server : bool = False
28- http_port : int = 8000
29- http_addr : str = "0.0.0.0"
30-
31- # Push gateway configuration
32- enable_push_gateway : bool = False
33- push_gateway_url : str = "localhost:9091"
34- push_job_name : str = "cadence_client"
35-
3627 # Metric name prefix
3728 metric_prefix : str = "cadence_"
3829
@@ -43,7 +34,7 @@ class PrometheusConfig:
4334 registry : Optional [CollectorRegistry ] = None
4435
4536
46- class PrometheusMetrics :
37+ class PrometheusMetrics ( MetricsEmitter ) :
4738 """Prometheus metrics collector implementation."""
4839
4940 def __init__ (self , config : Optional [PrometheusConfig ] = None ):
@@ -55,12 +46,6 @@ def __init__(self, config: Optional[PrometheusConfig] = None):
5546 self ._gauges : Dict [str , Gauge ] = {}
5647 self ._histograms : Dict [str , Histogram ] = {}
5748
58- # HTTP server handle
59- self ._http_server : Optional [Any ] = None
60-
61- if self .config .enable_http_server :
62- self .start_http_server ()
63-
6449 def _get_metric_name (self , name : str ) -> str :
6550 """Get the full metric name with prefix."""
6651 return f"{ self .config .metric_prefix } { name } "
@@ -126,23 +111,6 @@ def _get_or_create_histogram(
126111
127112 return self ._histograms [metric_name ]
128113
129- def _get_or_create_timer (
130- self , name : str , labels : Optional [Dict [str , str ]]
131- ) -> Histogram :
132- """Get or create a timer metric (implemented as histogram)."""
133- metric_name = self ._get_metric_name (name )
134-
135- if metric_name not in self ._histograms :
136- label_names = list (self ._merge_labels (labels ).keys ()) if labels else []
137- self ._histograms [metric_name ] = Histogram (
138- metric_name ,
139- f"Timer metric for { name } " ,
140- labelnames = label_names ,
141- registry = self .registry ,
142- )
143- logger .debug (f"Created timer metric: { metric_name } " )
144-
145- return self ._histograms [metric_name ]
146114
147115 def counter (
148116 self , key : str , n : int = 1 , tags : Optional [Dict [str , str ]] = None
@@ -176,21 +144,6 @@ def gauge(
176144 except Exception as e :
177145 logger .error (f"Failed to send gauge { key } : { e } " )
178146
179- def timer (
180- self , key : str , duration : float , tags : Optional [Dict [str , str ]] = None
181- ) -> None :
182- """Send a timer metric - implemented as histogram."""
183- try :
184- timer = self ._get_or_create_timer (key , tags )
185- merged_tags = self ._merge_labels (tags )
186-
187- if merged_tags :
188- timer .labels (** merged_tags ).observe (duration )
189- else :
190- timer .observe (duration )
191-
192- except Exception as e :
193- logger .error (f"Failed to send timer { key } : { e } " )
194147
195148 def histogram (
196149 self , key : str , value : float , tags : Optional [Dict [str , str ]] = None
@@ -208,44 +161,6 @@ def histogram(
208161 except Exception as e :
209162 logger .error (f"Failed to send histogram { key } : { e } " )
210163
211- def start_http_server (self ) -> None :
212- """Start HTTP server to expose metrics."""
213- if self ._http_server is not None :
214- logger .warning ("HTTP server already started" )
215- return
216-
217- try :
218- server_result = start_http_server (
219- self .config .http_port ,
220- addr = self .config .http_addr ,
221- registry = self .registry ,
222- )
223- self ._http_server = server_result
224- logger .info (
225- f"Prometheus metrics HTTP server started on "
226- f"{ self .config .http_addr } :{ self .config .http_port } "
227- )
228- except Exception as e :
229- logger .error (f"Failed to start HTTP server: { e } " )
230- raise
231-
232- def push_to_gateway (self ) -> None :
233- """Push metrics to Prometheus Push Gateway."""
234- if not self .config .enable_push_gateway :
235- logger .warning ("Push gateway not enabled" )
236- return
237-
238- try :
239- push_to_gateway (
240- self .config .push_gateway_url ,
241- job = self .config .push_job_name ,
242- registry = self .registry ,
243- )
244- logger .debug (f"Pushed metrics to gateway: { self .config .push_gateway_url } " )
245- except Exception as e :
246- logger .error (f"Failed to push to gateway: { e } " )
247- raise
248-
249164 def get_metrics_text (self ) -> str :
250165 """Get metrics in Prometheus text format."""
251166 try :
@@ -255,19 +170,9 @@ def get_metrics_text(self) -> str:
255170 logger .error (f"Failed to generate metrics text: { e } " )
256171 return ""
257172
258- def shutdown (self ) -> None :
259- """Shutdown the metrics collector."""
260- if self ._http_server :
261- try :
262- self ._http_server .shutdown ()
263- self ._http_server = None
264- logger .info ("Prometheus HTTP server shutdown" )
265- except Exception as e :
266- logger .error (f"Failed to shutdown HTTP server: { e } " )
267-
268173
269174# Default Cadence metrics names
270- class CadenceMetrics :
175+ class CadenceMetrics ( Enum ) :
271176 """Standard Cadence client metrics."""
272177
273178 # Workflow metrics
0 commit comments