timer.py
75 lines
| 2.3 KiB
| text/x-python
|
PythonLexer
r920 | from __future__ import absolute_import, division, unicode_literals | |||
import functools | ||||
# Use timer that's not susceptible to time of day adjustments. | ||||
try: | ||||
# perf_counter is only present on Py3.3+ | ||||
from time import perf_counter as time_now | ||||
except ImportError: | ||||
# fall back to using time | ||||
from time import time as time_now | ||||
def safe_wraps(wrapper, *args, **kwargs): | ||||
"""Safely wraps partial functions.""" | ||||
while isinstance(wrapper, functools.partial): | ||||
wrapper = wrapper.func | ||||
return functools.wraps(wrapper, *args, **kwargs) | ||||
class Timer(object): | ||||
"""A context manager/decorator for statsd.timing().""" | ||||
r1027 | def __init__(self, client, stat, rate=1, tags=None, use_decimals=True, auto_send=True): | |||
r920 | self.client = client | |||
self.stat = stat | ||||
self.rate = rate | ||||
r1005 | self.tags = tags | |||
r920 | self.ms = None | |||
self._sent = False | ||||
self._start_time = None | ||||
r1027 | self.use_decimals = use_decimals | |||
self.auto_send = auto_send | ||||
r920 | ||||
def __call__(self, f): | ||||
"""Thread-safe timing function decorator.""" | ||||
@safe_wraps(f) | ||||
def _wrapped(*args, **kwargs): | ||||
start_time = time_now() | ||||
try: | ||||
return f(*args, **kwargs) | ||||
finally: | ||||
elapsed_time_ms = 1000.0 * (time_now() - start_time) | ||||
r1027 | self.client.timing(self.stat, elapsed_time_ms, self.rate, self.tags, self.use_decimals) | |||
self._sent = True | ||||
r920 | return _wrapped | |||
def __enter__(self): | ||||
return self.start() | ||||
def __exit__(self, typ, value, tb): | ||||
r1027 | self.stop(send=self.auto_send) | |||
r920 | ||||
def start(self): | ||||
self.ms = None | ||||
self._sent = False | ||||
self._start_time = time_now() | ||||
return self | ||||
def stop(self, send=True): | ||||
if self._start_time is None: | ||||
raise RuntimeError('Timer has not started.') | ||||
dt = time_now() - self._start_time | ||||
self.ms = 1000.0 * dt # Convert to milliseconds. | ||||
if send: | ||||
self.send() | ||||
return self | ||||
def send(self): | ||||
if self.ms is None: | ||||
raise RuntimeError('No data recorded.') | ||||
if self._sent: | ||||
raise RuntimeError('Already sent data.') | ||||
self._sent = True | ||||
r1027 | self.client.timing(self.stat, self.ms, self.rate, self.tags, self.use_decimals) | |||