| 52 | |
| 53 | |
| 54 | class Timer: |
| 55 | def __init__(self, metric, callback_name): |
| 56 | self._metric = metric |
| 57 | self._callback_name = callback_name |
| 58 | |
| 59 | def _new_timer(self): |
| 60 | return self.__class__(self._metric, self._callback_name) |
| 61 | |
| 62 | def __enter__(self): |
| 63 | self._start = default_timer() |
| 64 | return self |
| 65 | |
| 66 | def __exit__(self, typ, value, traceback): |
| 67 | # Time can go backwards. |
| 68 | duration = max(default_timer() - self._start, 0) |
| 69 | callback = getattr(self._metric, self._callback_name) |
| 70 | callback(duration) |
| 71 | |
| 72 | def labels(self, *args, **kw): |
| 73 | self._metric = self._metric.labels(*args, **kw) |
| 74 | |
| 75 | def __call__(self, f: "F") -> "F": |
| 76 | def wrapped(func, *args, **kwargs): |
| 77 | # Obtaining new instance of timer every time |
| 78 | # ensures thread safety and reentrancy. |
| 79 | with self._new_timer(): |
| 80 | return func(*args, **kwargs) |
| 81 | |
| 82 | return decorate(f, wrapped) |