1414
1515from prometheus_client import start_http_server
1616from prometheus_client .core import CollectorRegistry
17- from prometheus_client .core import GaugeMetricFamily
1817from prometheus_client .core import CounterMetricFamily
19- from prometheus_client .core import UntypedMetricFamily
18+ from prometheus_client .core import GaugeMetricFamily
2019from prometheus_client .core import HistogramMetricFamily
2120from prometheus_client .core import REGISTRY
22- from opencensus . stats . exporters import base
23- from opencensus . stats import aggregation_data as aggregation_data_module
21+ from prometheus_client . core import UntypedMetricFamily
22+
2423from opencensus .common .transports import sync
24+ from opencensus .stats import aggregation_data as aggregation_data_module
25+ from opencensus .stats .exporters import base
2526
2627
2728class Options (object ):
@@ -82,10 +83,12 @@ def address(self):
8283class Collector (object ):
8384 """ Collector represents the Prometheus Collector object
8485 """
85- def __init__ (self , options = Options (), view_data = {}):
86+ def __init__ (self , options = Options (), view_name_to_data_map = None ):
87+ if view_name_to_data_map is None :
88+ view_name_to_data_map = {}
8689 self ._options = options
8790 self ._registry = options .registry
88- self ._view_data = view_data
91+ self ._view_name_to_data_map = view_name_to_data_map
8992 self ._registered_views = {}
9093
9194 @property
@@ -101,11 +104,11 @@ def registry(self):
101104 return self ._registry
102105
103106 @property
104- def view_data (self ):
107+ def view_name_to_data_map (self ):
105108 """ Map with all view data objects
106109 that will be sent to Prometheus
107110 """
108- return self ._view_data
111+ return self ._view_name_to_data_map
109112
110113 @property
111114 def registered_views (self ):
@@ -117,51 +120,58 @@ def register_view(self, view):
117120 """ register_view will create the needed structure
118121 in order to be able to sent all data to Prometheus
119122 """
120- count = 0
121-
122- signature = view_signature (self .options .namespace , view )
123+ v_name = get_view_name (self .options .namespace , view )
123124
124- if signature not in self .registered_views :
125- desc = {'name' : view_name ( self . options . namespace , view ) ,
125+ if v_name not in self .registered_views :
126+ desc = {'name' : v_name ,
126127 'documentation' : view .description ,
127- 'labels' : tag_keys_to_labels (view .columns )}
128- self .registered_views [signature ] = desc
129- count += 1
128+ 'labels' : list (view .columns )}
129+ self .registered_views [v_name ] = desc
130130 self .registry .register (self )
131131
132132 def add_view_data (self , view_data ):
133133 """ Add view data object to be sent to server
134134 """
135135 self .register_view (view_data .view )
136- signature = view_signature (self .options .namespace , view_data .view )
137- self .view_data [ signature ] = view_data
136+ v_name = get_view_name (self .options .namespace , view_data .view )
137+ self .view_name_to_data_map [ v_name ] = view_data
138138
139- def to_metric (self , desc , view ):
139+ # TODO: add start and end timestamp
140+ def to_metric (self , desc , tag_values , agg_data ):
140141 """ to_metric translate the data that OpenCensus create
141142 to Prometheus format, using Prometheus Metric object
142143
143- :type desc: str
144- :param desc: The view descriptor
144+ :type desc: dict
145+ :param desc: The map that describes view definition
145146
146- :type view: object of :class:
147- `~opencensus.stats.view.View`
148- :param object of opencensus.stats.view.View view:
149- View object to translate
147+ :type tag_values: tuple of :class:
148+ `~opencensus.tags.tag_value.TagValue`
149+ :param object of opencensus.tags.tag_value.TagValue:
150+ TagValue object used as label values
151+
152+ :type agg_data: object of :class:
153+ `~opencensus.stats.aggregation_data.AggregationData`
154+ :param object of opencensus.stats.aggregation_data.AggregationData:
155+ Aggregated data that needs to be converted as Prometheus samples
150156
151157 :rtype: :class:`~prometheus_client.core.CounterMetricFamily` or
152158 :class:`~prometheus_client.core.HistogramMetricFamily` or
153159 :class:`~prometheus_client.core.UntypedMetricFamily` or
154160 :class:`~prometheus_client.core.GaugeMetricFamily`
155161 :returns: A Prometheus metric object
156162 """
157- agg_data = view .aggregation .aggregation_data
163+ metric_name = desc ['name' ]
164+ metric_description = desc ['documentation' ]
165+ label_keys = desc ['labels' ]
158166
159167 if isinstance (agg_data , aggregation_data_module .CountAggregationData ):
160- labels = desc ['labels' ] if agg_data .count_data is None else None
161- return CounterMetricFamily (name = desc ['name' ],
162- documentation = desc ['documentation' ],
163- value = float (agg_data .count_data ),
164- labels = labels )
168+ metric = CounterMetricFamily (name = metric_name ,
169+ documentation = metric_description ,
170+ labels = label_keys )
171+ metric .add_metric (labels = list (tag_values ),
172+ value = agg_data .count_data )
173+ return metric
174+
165175 elif isinstance (agg_data ,
166176 aggregation_data_module .DistributionAggregationData ):
167177
@@ -171,28 +181,31 @@ def to_metric(self, desc, view):
171181 for ii , bound in enumerate (agg_data .bounds ):
172182 cum_count += agg_data .counts_per_bucket [ii ]
173183 points [str (bound )] = cum_count
174- labels = desc ['labels' ] if points is None else None
175- return HistogramMetricFamily (name = desc ['name' ],
176- documentation = desc ['documentation' ],
177- buckets = list (points .items ()),
178- sum_value = agg_data .sum ,
179- labels = labels )
184+ metric = HistogramMetricFamily (name = metric_name ,
185+ documentation = metric_description ,
186+ labels = label_keys )
187+ metric .add_metric (labels = list (tag_values ),
188+ buckets = list (points .items ()),
189+ sum_value = agg_data .sum ,)
190+ return metric
180191
181192 elif isinstance (agg_data ,
182193 aggregation_data_module .SumAggregationDataFloat ):
183- labels = desc ['labels' ] if agg_data .sum_data is None else None
184- return UntypedMetricFamily (name = desc ['name' ],
185- documentation = desc ['documentation' ],
186- value = agg_data .sum_data ,
187- labels = labels )
194+ metric = UntypedMetricFamily (name = metric_name ,
195+ documentation = metric_description ,
196+ labels = label_keys )
197+ metric .add_metric (labels = list (tag_values ),
198+ value = agg_data .sum_data )
199+ return metric
188200
189201 elif isinstance (agg_data ,
190202 aggregation_data_module .LastValueAggregationData ):
191- labels = desc ['labels' ] if agg_data .value is None else None
192- return GaugeMetricFamily (name = desc ['name' ],
193- documentation = desc ['documentation' ],
194- value = agg_data .value ,
195- labels = labels )
203+ metric = GaugeMetricFamily (name = metric_name ,
204+ documentation = metric_description ,
205+ labels = label_keys )
206+ metric .add_metric (labels = list (tag_values ),
207+ value = agg_data .value )
208+ return metric
196209
197210 else :
198211 raise ValueError ("unsupported aggregation type %s"
@@ -201,30 +214,16 @@ def to_metric(self, desc, view):
201214 def collect (self ): # pragma: NO COVER
202215 """Collect fetches the statistics from OpenCensus
203216 and delivers them as Prometheus Metrics.
204- Collect is invoked everytime a prometheus.Gatherer is run
217+ Collect is invoked every time a prometheus.Gatherer is run
205218 for example when the HTTP endpoint is invoked by Prometheus.
206219 """
207- for v_data in list (self .view_data ):
208- signature = view_signature (self .options .namespace ,
209- self .view_data [v_data ].view )
210- desc = self .registered_views [signature ]
211- metric = self .to_metric (desc ,
212- self .view_data [v_data ].view )
213- yield metric
214-
215- def describe (self ):
216- """ describe will be used by Prometheus Client
217- to retrieve all registered views.
218- """
219- registered = {}
220- for sign in self .registered_views :
221- registered [sign ] = self .registered_views [sign ]
222- for v_data in list (self .view_data ): # pragma: NO COVER
223- if not isinstance (v_data , str ):
224- signature = view_signature (self .options .namespace , v_data .view )
225- desc = self .registered_views [signature ]
226- metric = self .to_metric (desc ,
227- self .view_data [v_data ].view )
220+ for v_name , view_data in self .view_name_to_data_map .items ():
221+ if v_name not in self .registered_views :
222+ continue
223+ desc = self .registered_views [v_name ]
224+ for tag_values in view_data .tag_value_aggregation_data_map :
225+ agg_data = view_data .tag_value_aggregation_data_map [tag_values ]
226+ metric = self .to_metric (desc , tag_values , agg_data )
228227 yield metric
229228
230229
@@ -332,15 +331,6 @@ def new_stats_exporter(option):
332331 return exporter
333332
334333
335- def tag_keys_to_labels (tag_keys ):
336- """ Translate Tag keys to labels
337- """
338- labels = []
339- for key in tag_keys :
340- labels .append (key )
341- return labels
342-
343-
344334def new_collector (options ):
345335 """ new_collector should be used
346336 to create instance of Collector class in order to
@@ -349,19 +339,10 @@ def new_collector(options):
349339 return Collector (options = options )
350340
351341
352- def view_name (namespace , view ):
342+ def get_view_name (namespace , view ):
353343 """ create the name for the view
354344 """
355345 name = ""
356346 if namespace != "" :
357347 name = namespace + "_"
358348 return name + view .name
359-
360-
361- def view_signature (namespace , view ):
362- """ create the signature for the view
363- """
364- sign = view_name (namespace , view )
365- for key in view .columns :
366- sign += "-" + key
367- return sign
0 commit comments