22import os
33from typing import TYPE_CHECKING , Dict , NamedTuple
44
5- from prometheus_client import CollectorRegistry , Gauge , write_to_textfile # type: ignore
5+ from prometheus_client import CollectorRegistry , Gauge , start_http_server , write_to_textfile # type: ignore
6+
7+ from txstratum .utils import Periodic
68
79if TYPE_CHECKING :
810 from txstratum .manager import TxMiningManager
@@ -50,24 +52,16 @@ def collect_metrics(manager: 'TxMiningManager') -> MetricData:
5052 )
5153
5254
53- class PrometheusExporter :
54- """Class that sends hathor metrics to a node exporter that will be read by Prometheus ."""
55+ class BasePrometheusExporter :
56+ """Base class for prometheus exporters ."""
5557
56- def __init__ (self , manager : 'TxMiningManager' , path : str , filename : str = 'tx-mining-service.prom' ):
57- """Init PrometheusExporter .
58+ def __init__ (self , manager : 'TxMiningManager' ):
59+ """Init BasePrometheusExporter .
5860
5961 :param manager: Manager where the metrics will be collected from
60- :param path: Path to save the prometheus file
61- :param filename: Name of the prometheus file (must end in .prom)
6262 """
6363 self .manager = manager
6464
65- # Create full directory, if does not exist
66- os .makedirs (path , exist_ok = True )
67-
68- # Full filepath with filename
69- self .filepath : str = os .path .join (path , filename )
70-
7165 # Stores all Gauge objects for each metric (key is the metric name)
7266 self .metric_gauges : Dict [str , Gauge ] = {}
7367
@@ -77,8 +71,8 @@ def __init__(self, manager: 'TxMiningManager', path: str, filename: str = 'tx-mi
7771 # Interval in which the write data method will be called (in seconds)
7872 self .call_interval : int = 5
7973
80- # If exporter is running
81- self .running : bool = False
74+ # Periodic task to update metrics
75+ self .update_metrics_task : Periodic = Periodic ( self . update_metrics , self . call_interval )
8276
8377 def _initial_setup (self ) -> None :
8478 """Start a collector registry to send data to node exporter."""
@@ -87,28 +81,61 @@ def _initial_setup(self) -> None:
8781 for name , comment in METRIC_INFO .items ():
8882 self .metric_gauges [name ] = Gauge (name , comment , registry = self .registry )
8983
90- def start (self ) -> None :
91- """Start exporter."""
92- self .running = True
93- self ._schedule_and_write_data ()
94-
95- def update_metrics (self ) -> None :
84+ async def update_metrics (self ) -> None :
9685 """Update metric_gauges dict with new data from metrics."""
9786 data = collect_metrics (self .manager )
9887 for metric_name in METRIC_INFO .keys ():
9988 self .metric_gauges [metric_name ].set (getattr (data , metric_name ))
10089
90+ def start (self ) -> None :
91+ """Start exporter."""
92+ asyncio .ensure_future (self .update_metrics_task .start ())
93+
94+ def stop (self ) -> None :
95+ """Stop exporter."""
96+ asyncio .ensure_future (self .update_metrics_task .stop ())
97+
98+
99+ class PrometheusExporter (BasePrometheusExporter ):
100+ """Class that sends hathor metrics to a node exporter that will be read by Prometheus."""
101+
102+ def __init__ (self , manager : 'TxMiningManager' , path : str , filename : str = 'tx-mining-service.prom' ):
103+ """Init PrometheusExporter.
104+
105+ :param manager: Manager where the metrics will be collected from
106+ :param path: Path to save the prometheus file
107+ :param filename: Name of the prometheus file (must end in .prom)
108+ """
109+ super ().__init__ (manager )
110+
111+ # Create full directory, if does not exist
112+ os .makedirs (path , exist_ok = True )
113+
114+ # Full filepath with filename
115+ self .filepath : str = os .path .join (path , filename )
116+
117+ async def update_metrics (self ) -> None :
118+ """Update metric_gauges dict with new data from metrics."""
119+ await super ().update_metrics ()
120+
101121 write_to_textfile (self .filepath , self .registry )
102122
103- def _schedule_and_write_data (self ) -> None :
104- """Update metrics and schedule to be called again."""
105- if self .running :
106- self .update_metrics ()
107123
108- # Schedule next call
109- loop = asyncio .get_event_loop ()
110- loop .call_later (self .call_interval , self ._schedule_and_write_data )
124+ class HttpPrometheusExporter (BasePrometheusExporter ):
125+ """Class that exposes metrics in a http endpoint."""
111126
112- def stop (self ) -> None :
113- """Stop exporter."""
114- self .running = False
127+ def __init__ (self , manager : 'TxMiningManager' , port : int ):
128+ """Init HttpPrometheusExporter.
129+
130+ :param manager: Manager where the metrics will be collected from
131+ :param port: Port to expose the metrics
132+ """
133+ super ().__init__ (manager )
134+
135+ self .port = port
136+
137+ def start (self ) -> None :
138+ """Start exporter."""
139+ super ().start ()
140+
141+ start_http_server (self .port , registry = self .registry )
0 commit comments