77import os
88import time
99import threading
10- from contextlib import contextmanager
1110try :
1211 from BaseHTTPServer import BaseHTTPRequestHandler
1312except ImportError :
2524_MINUS_INF = float ("-inf" )
2625
2726
28-
2927class CollectorRegistry (object ):
3028 '''Metric collector registry.
31-
29+
3230 Collectors must have a no-argument method 'collect' that returns a list of
3331 Metric objects. The returned metrics should be consistent with the Prometheus
3432 exposition formats.
@@ -58,7 +56,7 @@ def collect(self):
5856
5957 def get_sample_value (self , name , labels = None ):
6058 '''Returns the sample value, or None if not found.
61-
59+
6260 This is inefficient, and intended only for use in unittests.
6361 '''
6462 if labels is None :
@@ -75,6 +73,7 @@ def get_sample_value(self, name, labels=None):
7573
7674_METRIC_TYPES = ('counter' , 'gauge' , 'summary' , 'histogram' , 'untyped' )
7775
76+
7877class Metric (object ):
7978 '''A single metric and it's samples.'''
8079 def __init__ (self , name , documentation , typ ):
@@ -169,10 +168,12 @@ def collect():
169168
170169 return init
171170
171+
172172@_MetricWrapper
173173class Counter (object ):
174174 _type = 'counter'
175175 _reserved_labelnames = []
176+
176177 def __init__ (self ):
177178 self ._value = 0.0
178179 self ._lock = Lock ()
@@ -194,10 +195,14 @@ def count_exceptions(self, exception=Exception):
194195 class ExceptionCounter (object ):
195196 def __init__ (self , counter ):
196197 self ._counter = counter
197- def __enter__ (self ): pass
198+
199+ def __enter__ (self ):
200+ pass
201+
198202 def __exit__ (self , typ , value , traceback ):
199203 if isinstance (value , exception ):
200204 self ._counter .inc ()
205+
201206 def __call__ (self , f ):
202207 @wraps (f )
203208 def wrapped (* args , ** kwargs ):
@@ -210,10 +215,12 @@ def _samples(self):
210215 with self ._lock :
211216 return (('' , {}, self ._value ), )
212217
218+
213219@_MetricWrapper
214220class Gauge (object ):
215221 _type = 'gauge'
216222 _reserved_labelnames = []
223+
217224 def __init__ (self ):
218225 self ._value = 0.0
219226 self ._lock = Lock ()
@@ -247,10 +254,13 @@ def track_inprogress(self):
247254 class InprogressTracker (object ):
248255 def __init__ (self , gauge ):
249256 self ._gauge = gauge
257+
250258 def __enter__ (self ):
251259 self ._gauge .inc ()
260+
252261 def __exit__ (self , typ , value , traceback ):
253262 self ._gauge .dec ()
263+
254264 def __call__ (self , f ):
255265 @wraps (f )
256266 def wrapped (* args , ** kwargs ):
@@ -263,10 +273,12 @@ def _samples(self):
263273 with self ._lock :
264274 return (('' , {}, self ._value ), )
265275
276+
266277@_MetricWrapper
267278class Summary (object ):
268279 _type = 'summary'
269280 _reserved_labelnames = ['quantile' ]
281+
270282 def __init__ (self ):
271283 self ._count = 0.0
272284 self ._sum = 0.0
@@ -286,11 +298,14 @@ def time(self):
286298 class Timer (object ):
287299 def __init__ (self , summary ):
288300 self ._summary = summary
301+
289302 def __enter__ (self ):
290303 self ._start = time .time ()
304+
291305 def __exit__ (self , typ , value , traceback ):
292306 # Time can go backwards.
293307 self ._summary .observe (max (time .time () - self ._start , 0 ))
308+
294309 def __call__ (self , f ):
295310 @wraps (f )
296311 def wrapped (* args , ** kwargs ):
@@ -305,6 +320,7 @@ def _samples(self):
305320 ('_count' , {}, self ._count ),
306321 ('_sum' , {}, self ._sum ))
307322
323+
308324def _floatToGoString (d ):
309325 if d == _INF :
310326 return '+Inf'
@@ -313,14 +329,16 @@ def _floatToGoString(d):
313329 else :
314330 return repr (d )
315331
332+
316333@_MetricWrapper
317334class Histogram (object ):
318335 _type = 'histogram'
319336 _reserved_labelnames = ['histogram' ]
337+
320338 def __init__ (self , buckets = (.005 , .01 , .025 , .05 , .075 , .1 , .25 , .5 , .75 , 1.0 , 2.5 , 5.0 , 7.5 , 10.0 , _INF )):
321339 self ._sum = 0.0
322340 self ._lock = Lock ()
323- buckets = [float (b ) for b in buckets ]
341+ buckets = [float (b ) for b in buckets ]
324342 if buckets != sorted (buckets ):
325343 # This is probably an error on the part of the user,
326344 # so raise rather than sorting for them.
@@ -349,11 +367,14 @@ def time(self):
349367 class Timer (object ):
350368 def __init__ (self , histogram ):
351369 self ._histogram = histogram
370+
352371 def __enter__ (self ):
353372 self ._start = time .time ()
373+
354374 def __exit__ (self , typ , value , traceback ):
355375 # Time can go backwards.
356376 self ._histogram .observe (max (time .time () - self ._start , 0 ))
377+
357378 def __call__ (self , f ):
358379 @wraps (f )
359380 def wrapped (* args , ** kwargs ):
@@ -373,10 +394,11 @@ def _samples(self):
373394 samples .append (('_sum' , {}, self ._sum ))
374395 return tuple (samples )
375396
376-
397+
377398CONTENT_TYPE_LATEST = 'text/plain; version=0.0.4; charset=utf-8'
378399'''Content type of the latest text format'''
379400
401+
380402def generate_latest (registry = REGISTRY ):
381403 '''Returns the metrics from the registry in latest text format as a string.'''
382404 output = []
@@ -403,6 +425,7 @@ def do_GET(self):
403425 self .end_headers ()
404426 self .wfile .write (generate_latest (REGISTRY ))
405427
428+
406429def write_to_textfile (path , registry ):
407430 '''Write metrics to the given path.
408431
@@ -418,13 +441,13 @@ def write_to_textfile(path, registry):
418441if __name__ == '__main__' :
419442 c = Counter ('cc' , 'A counter' )
420443 c .inc ()
421-
444+
422445 g = Gauge ('gg' , 'A gauge' )
423446 g .set (17 )
424-
447+
425448 s = Summary ('ss' , 'A summary' , ['a' , 'b' ])
426449 s .labels ('c' , 'd' ).observe (17 )
427-
450+
428451 h = Histogram ('hh' , 'A histogram' )
429452 h .observe (.6 )
430453
0 commit comments