@@ -38,7 +38,7 @@ def unregister(self, metric):
3838 self ._collectors .remove (collector )
3939
4040 def collect (self ):
41- """ Yields metrics from the collectors in the registry."""
41+ ''' Yields metrics from the collectors in the registry.'''
4242 collectors = None
4343 with self ._lock :
4444 collectors = copy .copy (self ._collectors )
@@ -47,10 +47,10 @@ def collect(self):
4747 yield metric
4848
4949 def get_sample_value (self , name , labels = None ):
50- """ Returns the sample value, or None if not found.
50+ ''' Returns the sample value, or None if not found.
5151
5252 This is inefficient, and intended only for use in unittests.
53- """
53+ '''
5454 if labels is None :
5555 labels = {}
5656 for metric in self .collect ():
@@ -71,7 +71,7 @@ def __init__(self, name, documentation, typ):
7171 self ._name = name
7272 self ._documentation = documentation
7373 if typ not in _METRIC_TYPES :
74- raise ValueError (" Invalid metric type: " + typ )
74+ raise ValueError (' Invalid metric type: ' + typ )
7575 self ._type = typ
7676 self ._samples = []
7777
@@ -94,19 +94,19 @@ def __init__(self, wrappedClass, labelnames):
9494 raise InvalidLabelName (l )
9595
9696 def labels (self , * labelvalues ):
97- """ Return the child for the given labelset."""
97+ ''' Return the child for the given labelset.'''
9898 if len (labelvalues ) != len (self ._labelnames ):
99- raise ValueError (" Incorrect label count" )
99+ raise ValueError (' Incorrect label count' )
100100 labelvalues = tuple (labelvalues )
101101 with self ._lock :
102102 if labelvalues not in self ._metrics :
103103 self ._metrics [labelvalues ] = self ._wrappedClass ()
104104 return self ._metrics [labelvalues ]
105105
106106 def remove (self , * labelvalues ):
107- """ Remove the given labelset from the metric."""
107+ ''' Remove the given labelset from the metric.'''
108108 if len (labelvalues ) != len (self ._labelnames ):
109- raise ValueError (" Incorrect label count" )
109+ raise ValueError (' Incorrect label count' )
110110 labelvalues = tuple (labelvalues )
111111 with self ._lock :
112112 del self ._metrics [labelvalues ]
@@ -125,9 +125,9 @@ def init(name, documentation, labelnames=(), namespace='', subsystem='', registr
125125 if labelnames :
126126 for l in labelnames :
127127 if not _METRIC_LABEL_NAME_RE .match (l ):
128- raise ValueError (" Invalid label metric name: " + l )
128+ raise ValueError (' Invalid label metric name: ' + l )
129129 if _RESERVED_METRIC_LABEL_NAME_RE .match (l ):
130- raise ValueError (" Reserved label metric name: " + l )
130+ raise ValueError (' Reserved label metric name: ' + l )
131131 collector = _LabelWrapper (cls , labelnames )
132132 else :
133133 collector = cls ()
@@ -140,7 +140,7 @@ def init(name, documentation, labelnames=(), namespace='', subsystem='', registr
140140 full_name += name
141141
142142 if not _METRIC_NAME_RE .match (full_name ):
143- raise ValueError (" Invalid metric name: " + full_name )
143+ raise ValueError (' Invalid metric name: ' + full_name )
144144
145145 def collect ():
146146 metric = Metric (full_name , documentation , cls ._type )
@@ -162,28 +162,33 @@ def __init__(self):
162162 self ._lock = Lock ()
163163
164164 def inc (self , amount = 1 ):
165- """ Increment counter by the given amount."""
165+ ''' Increment counter by the given amount.'''
166166 if amount < 0 :
167- raise ValueError (" Counters can only be incremented by non-negative amounts." )
167+ raise ValueError (' Counters can only be incremented by non-negative amounts.' )
168168 with self ._lock :
169169 self ._value += amount
170170
171- @contextmanager
172- def countBlockExceptions (self ):
173- """Decorator to increment if a block raises an exception."""
174- try :
175- yield
176- except Exception , e :
177- self .inc ()
178- raise e
179-
180- def countFunctionExceptions (self , f ):
181- """Decorator to increment if a function raises an exception."""
182- @wraps (f )
183- def wrapper (* args , ** kwargs ):
184- with self .countBlockExceptions ():
185- return f (* args , ** kwargs )
186- return wrapper
171+ def countExceptions (self , exception = Exception ):
172+ '''Count exceptions in a block of code or function.
173+
174+ Can be used as a function decorator or context manager.
175+ Increments the counter when an exception of the given
176+ type is raised up out of the code.
177+ '''
178+ class ExceptionCounter (object ):
179+ def __init__ (self , counter ):
180+ self ._counter = counter
181+ def __enter__ (self ): pass
182+ def __exit__ (self , typ , value , traceback ):
183+ if isinstance (value , exception ):
184+ self ._counter .inc ()
185+ def __call__ (self , f ):
186+ @wraps (f )
187+ def wrapped (* args , ** kwargs ):
188+ with self :
189+ return f (* args , ** kwargs )
190+ return wrapped
191+ return ExceptionCounter (self )
187192
188193 def _samples (self ):
189194 with self ._lock :
@@ -197,40 +202,45 @@ def __init__(self):
197202 self ._lock = Lock ()
198203
199204 def inc (self , amount = 1 ):
200- """ Increment gauge by the given amount."""
205+ ''' Increment gauge by the given amount.'''
201206 with self ._lock :
202207 self ._value += amount
203208
204209 def dec (self , amount = 1 ):
205- """ Decrement gauge by the given amount."""
210+ ''' Decrement gauge by the given amount.'''
206211 with self ._lock :
207212 self ._value -= amount
208213
209214 def set (self , value ):
210- """ Set gauge to the given value."""
215+ ''' Set gauge to the given value.'''
211216 with self ._lock :
212217 self ._value = float (value )
213218
214219 def setToCurrentTime (self , value ):
215- """ Set gauge to the current unixtime."""
220+ ''' Set gauge to the current unixtime.'''
216221 self .set (time .time ())
217222
218- @contextmanager
219- def trackBlockInprogress (self ):
220- """Decorator to track how many of a block are in progress."""
221- self .inc ()
222- try :
223- yield
224- finally :
225- self .dec ()
226-
227- def trackFunctionInprogress (self , f ):
228- """Decorator to track how many of a function are in progress."""
229- @wraps (f )
230- def wrapper (* args , ** kwargs ):
231- with self .trackBlockInprogress ():
232- return f (* args , ** kwargs )
233- return wrapper
223+ def trackInprogress (self ):
224+ '''Track inprogress blocks of code or functions.
225+
226+ Can be used as a function decorator or context manager.
227+ Increments the gauge when the code is entered,
228+ and decrements when it is exited.
229+ '''
230+ class InprogressTracker (object ):
231+ def __init__ (self , gauge ):
232+ self ._gauge = gauge
233+ def __enter__ (self ):
234+ self ._gauge .inc ()
235+ def __exit__ (self , typ , value , traceback ):
236+ self ._gauge .dec ()
237+ def __call__ (self , f ):
238+ @wraps (f )
239+ def wrapped (* args , ** kwargs ):
240+ with self :
241+ return f (* args , ** kwargs )
242+ return wrapped
243+ return InprogressTracker (self )
234244
235245 def _samples (self ):
236246 with self ._lock :
@@ -245,28 +255,31 @@ def __init__(self):
245255 self ._lock = Lock ()
246256
247257 def observe (self , amount ):
248- """ Observe the given amount."""
258+ ''' Observe the given amount.'''
249259 with self ._lock :
250260 self ._count += 1
251261 self ._sum += amount
252262
253- @contextmanager
254- def timeBlock (self ):
255- """Context manager to time how long a block of code takes in seconds."""
256- start = time .time ()
257- try :
258- yield
259- finally :
260- # Time can go backwards.
261- self .observe (max (time .time () - start , 0 ))
262-
263- def timeFunction (self , f ):
264- """Decorator to time long a function takes in seconds."""
265- @wraps (f )
266- def wrapper (* args , ** kwargs ):
267- with self .timeBlock ():
268- return f (* args , ** kwargs )
269- return wrapper
263+ def time (self ):
264+ '''Time a block of code or function, and observe the duration in seconds.
265+
266+ Can be used as a function decorator or context manager.
267+ '''
268+ class Timer (object ):
269+ def __init__ (self , summary ):
270+ self ._summary = summary
271+ def __enter__ (self ):
272+ self ._start = time .time ()
273+ def __exit__ (self , typ , value , traceback ):
274+ # Time can go backwards.
275+ self ._summary .observe (max (time .time () - self ._start , 0 ))
276+ def __call__ (self , f ):
277+ @wraps (f )
278+ def wrapped (* args , ** kwargs ):
279+ with self :
280+ return f (* args , ** kwargs )
281+ return wrapped
282+ return Timer (self )
270283
271284 def _samples (self ):
272285 with self ._lock :
@@ -276,11 +289,11 @@ def _samples(self):
276289
277290
278291
279- CONTENT_TYPE_004 = 'text-plain; version=0.0.4; charset=utf-8'
280- '''Content type of the text format v0.0.4 '''
292+ CONTENT_TYPE_LATEST = 'text-plain; version=0.0.4; charset=utf-8'
293+ '''Content type of the latest text format'''
281294
282- def generate004 (registry = REGISTRY ):
283- '''Returns the metrics from the registry in text format v0.0.4 as a string.'''
295+ def generate_latest (registry = REGISTRY ):
296+ '''Returns the metrics from the registry in latest text format as a string.'''
284297 output = []
285298 for metric in registry .collect ():
286299 output .append (u'# HELP %s %s' % (
@@ -290,7 +303,7 @@ def generate004(registry=REGISTRY):
290303 if labels :
291304 labelstr = u'{%s}' % ',' .join (
292305 [u'%s="%s"' % (
293- k , v .replace ('\\ ' , r'\\' ).replace ('\n ' , r'\n' ).replace ('"' , r'\" ' ))
306+ k , v .replace ('\\ ' , r'\\' ).replace ('\n ' , r'\n' ).replace ('\' ' , r'\' ' ))
294307 for k , v in labels .items ()])
295308 else :
296309 labelstr = u''
@@ -301,9 +314,9 @@ def generate004(registry=REGISTRY):
301314class MetricsHandler (BaseHTTPRequestHandler ):
302315 def do_GET (self ):
303316 self .send_response (200 )
304- self .send_header ('Content-Type' , CONTENT_TYPE_004 )
317+ self .send_header ('Content-Type' , CONTENT_TYPE_LATEST )
305318 self .end_headers ()
306- self .wfile .write (generate004 (REGISTRY ))
319+ self .wfile .write (generate_latest (REGISTRY ))
307320
308321
309322if __name__ == '__main__' :
0 commit comments