context_managers.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. from timeit import default_timer
  2. from types import TracebackType
  3. from typing import (
  4. Any, Callable, Literal, Optional, Tuple, Type, TYPE_CHECKING, TypeVar,
  5. Union,
  6. )
  7. from .decorator import decorate
  8. if TYPE_CHECKING:
  9. from . import Counter
  10. F = TypeVar("F", bound=Callable[..., Any])
  11. class ExceptionCounter:
  12. def __init__(self, counter: "Counter", exception: Union[Type[BaseException], Tuple[Type[BaseException], ...]]) -> None:
  13. self._counter = counter
  14. self._exception = exception
  15. def __enter__(self) -> None:
  16. pass
  17. def __exit__(self, typ: Optional[Type[BaseException]], value: Optional[BaseException], traceback: Optional[TracebackType]) -> Literal[False]:
  18. if isinstance(value, self._exception):
  19. self._counter.inc()
  20. return False
  21. def __call__(self, f: "F") -> "F":
  22. def wrapped(func, *args, **kwargs):
  23. with self:
  24. return func(*args, **kwargs)
  25. return decorate(f, wrapped)
  26. class InprogressTracker:
  27. def __init__(self, gauge):
  28. self._gauge = gauge
  29. def __enter__(self):
  30. self._gauge.inc()
  31. def __exit__(self, typ, value, traceback):
  32. self._gauge.dec()
  33. def __call__(self, f: "F") -> "F":
  34. def wrapped(func, *args, **kwargs):
  35. with self:
  36. return func(*args, **kwargs)
  37. return decorate(f, wrapped)
  38. class Timer:
  39. def __init__(self, metric, callback_name):
  40. self._metric = metric
  41. self._callback_name = callback_name
  42. def _new_timer(self):
  43. return self.__class__(self._metric, self._callback_name)
  44. def __enter__(self):
  45. self._start = default_timer()
  46. return self
  47. def __exit__(self, typ, value, traceback):
  48. # Time can go backwards.
  49. duration = max(default_timer() - self._start, 0)
  50. callback = getattr(self._metric, self._callback_name)
  51. callback(duration)
  52. def labels(self, *args, **kw):
  53. self._metric = self._metric.labels(*args, **kw)
  54. def __call__(self, f: "F") -> "F":
  55. def wrapped(func, *args, **kwargs):
  56. # Obtaining new instance of timer every time
  57. # ensures thread safety and reentrancy.
  58. with self._new_timer():
  59. return func(*args, **kwargs)
  60. return decorate(f, wrapped)