From 4b2b1fca5e9d494089b60cf6e554cf3561ed2a58 Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 00:00:37 -0500 Subject: [PATCH 01/14] implement @timer Signed-off-by: Jason Ray --- statman/__init__.py | 1 + statman/decorators.py | 17 ++++++++++++++ statman/tests/test_timer_decorator.py | 34 +++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 statman/decorators.py create mode 100644 statman/tests/test_timer_decorator.py diff --git a/statman/__init__.py b/statman/__init__.py index 61ef0eb..9d3299f 100644 --- a/statman/__init__.py +++ b/statman/__init__.py @@ -4,5 +4,6 @@ from .history import History from .calculation import Calculation from .metric import Metric +from .decorators import timer __all__ = ['Statman', 'Stopwatch'] \ No newline at end of file diff --git a/statman/decorators.py b/statman/decorators.py new file mode 100644 index 0000000..b2b8fcd --- /dev/null +++ b/statman/decorators.py @@ -0,0 +1,17 @@ +from .statman import Statman + + +def timer(name): + + def timer_inner_decorator(func): + + def timer_wrapper(*args, **kwargs): + sw = Statman.stopwatch(name=name, enable_history=True) + sw.start() + result = func(*args, **kwargs) + sw.stop() + return result + + return timer_wrapper + + return timer_inner_decorator diff --git a/statman/tests/test_timer_decorator.py b/statman/tests/test_timer_decorator.py new file mode 100644 index 0000000..389e4b0 --- /dev/null +++ b/statman/tests/test_timer_decorator.py @@ -0,0 +1,34 @@ +import unittest +import time +import statman +from statman import Statman +from statman.stopwatch import Stopwatch + + +class TestStopwatch(unittest.TestCase): + + def test_decorator_stopwatch(self): + delay = 7 + result = self.sut('moto', delay=delay) + self.assertEqual(result, 'hello moto') + + self.assertIsNotNone(Statman.stopwatch('sut.timer')) + self.assertEqual(Statman.stopwatch('sut.timer').name, 'sut.timer') + self.assertAlmostEqual(Statman.stopwatch('sut.timer').value, delay, delta=0.1) + + @statman.timer(name="sut.timer") + def sut(self, n: str, delay: int = 1): + msg = f'hello {n}' + print(msg) + time.sleep(delay) + return msg + + def test_decorator_stopwatch_2(self): + delay = 5 + result = self.sut('moto2', delay=delay) + self.assertEqual(result, 'hello moto2') + # self.assertAlmostEqual(stopwatch.read(), test_time_s, delta=self._accepted_variance) + + self.assertIsNotNone(Statman.stopwatch('sut.timer')) + self.assertEqual(Statman.stopwatch('sut.timer').name, 'sut.timer') + self.assertAlmostEqual(Statman.stopwatch('sut.timer').value, delay, delta=0.1) From 9a99e97e2507ad3851a1d9920ab7635d2f8279ad Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 22:05:53 -0500 Subject: [PATCH 02/14] refactor statman tests --- statman/tests/test_statman.py | 101 ++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 48 deletions(-) diff --git a/statman/tests/test_statman.py b/statman/tests/test_statman.py index cdc6ed5..fe77a93 100644 --- a/statman/tests/test_statman.py +++ b/statman/tests/test_statman.py @@ -12,13 +12,51 @@ def run_before_and_after_tests(data): print('reset registry between tests') Statman.reset() - def test_create_stopwatch_directly(self): - from statman import Stopwatch - sw = Stopwatch() - sw.start() + def log(self, message): + print(f'{TestStatman} {message}') + +class TestGaugeViaStatman(TestStatman): + def test_create_gauge_via_statman_package(self): + import statman + gauge = statman.Gauge() + gauge.value = 1 + self.assertEqual(gauge.value, 1) + + def test_access_gauge_through_registry(self): + g1 = Statman.gauge('g1') + g1.value = 1 + + Statman.gauge(name='g2', value=2).increment() + + Statman.gauge('g3') + Statman.gauge('g3').value = 20 + Statman.gauge('g3').increment(10) + + self.assertEqual(Statman.gauge('g1').name, 'g1') + self.assertEqual(Statman.gauge('g1').value, 1) + self.assertEqual(Statman.gauge('g2').value, 3) + self.assertEqual(Statman.gauge('g3').value, 30) + + def test_report(self): + Statman.gauge('g1').value = 1 + Statman.gauge('g2').value = 2 + Statman.gauge('g3') + Statman.gauge('g4').increment() + Statman.stopwatch('sw1', autostart=True, enable_history=True) time.sleep(1) - self.assertAlmostEqual(sw.read(), 1, delta=0.1) + Statman.stopwatch('sw1').stop() + Statman.stopwatch('sw1', autostart=True, enable_history=True) + Statman.stopwatch('sw2', autostart=True, enable_history=True) + Statman.stopwatch('sw3', autostart=False, enable_history=True) + Statman.stopwatch('sw4', autostart=True, enable_history=True) + time.sleep(2) + Statman.stopwatch('sw1').stop() + Statman.stopwatch('sw4').stop() + message = Statman.report(output_stdout=False, log_method=self.log) + print('raw message:', message) + +class TestStopwatchViaStatman(TestStatman): def test_create_stopwatch_via_statman_package(self): import statman sw = statman.Stopwatch() @@ -26,6 +64,14 @@ def test_create_stopwatch_via_statman_package(self): time.sleep(1) self.assertAlmostEqual(sw.read(), 1, delta=0.1) + def test_create_stopwatch_directly(self): + from statman import Stopwatch + sw = Stopwatch() + sw.start() + time.sleep(1) + self.assertAlmostEqual(sw.read(), 1, delta=0.1) + + def test_create_stopwatch_via_statman_constructor(self): sw = Statman.stopwatch() sw.start() @@ -134,49 +180,8 @@ def test_manually_registry(self): time.sleep(1) self.assertAlmostEqual(sw.read(), 1, delta=0.1) - def test_create_gauge_via_statman_package(self): - import statman - gauge = statman.Gauge() - gauge.value = 1 - self.assertEqual(gauge.value, 1) - - def test_access_gauge_through_registry(self): - g1 = Statman.gauge('g1') - g1.value = 1 - - Statman.gauge(name='g2', value=2).increment() - - Statman.gauge('g3') - Statman.gauge('g3').value = 20 - Statman.gauge('g3').increment(10) - - self.assertEqual(Statman.gauge('g1').name, 'g1') - self.assertEqual(Statman.gauge('g1').value, 1) - self.assertEqual(Statman.gauge('g2').value, 3) - self.assertEqual(Statman.gauge('g3').value, 30) - - def test_report(self): - Statman.gauge('g1').value = 1 - Statman.gauge('g2').value = 2 - Statman.gauge('g3') - Statman.gauge('g4').increment() - Statman.stopwatch('sw1', autostart=True, enable_history=True) - time.sleep(1) - Statman.stopwatch('sw1').stop() - Statman.stopwatch('sw1', autostart=True, enable_history=True) - Statman.stopwatch('sw2', autostart=True, enable_history=True) - Statman.stopwatch('sw3', autostart=False, enable_history=True) - Statman.stopwatch('sw4', autostart=True, enable_history=True) - time.sleep(2) - Statman.stopwatch('sw1').stop() - Statman.stopwatch('sw4').stop() - - message = Statman.report(output_stdout=False, log_method=self.log) - print('raw message:', message) - - def log(self, message): - print('XX ' + message) +class TestCalculationViaStatman(TestStatman): def test_calculation_metric(self): Statman.stopwatch('sw').start() time.sleep(0.5) @@ -207,4 +212,4 @@ def test_mutated_registry_during_reporting(self): Statman.stopwatch('sw') Statman.calculation( 'messages_per_second').calculation_function = lambda: (Statman.gauge('messages_processed').value / Statman.stopwatch('sw').value) - Statman.report(output_stdout=True) + Statman.report(output_stdout=True) \ No newline at end of file From 3a4a21a54b60b6ddb8dd3e4c4a3c499f725c47af Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 22:06:17 -0500 Subject: [PATCH 03/14] formatting --- statman/tests/test_statman.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/statman/tests/test_statman.py b/statman/tests/test_statman.py index fe77a93..2a04a56 100644 --- a/statman/tests/test_statman.py +++ b/statman/tests/test_statman.py @@ -15,7 +15,9 @@ def run_before_and_after_tests(data): def log(self, message): print(f'{TestStatman} {message}') + class TestGaugeViaStatman(TestStatman): + def test_create_gauge_via_statman_package(self): import statman gauge = statman.Gauge() @@ -56,7 +58,9 @@ def test_report(self): message = Statman.report(output_stdout=False, log_method=self.log) print('raw message:', message) + class TestStopwatchViaStatman(TestStatman): + def test_create_stopwatch_via_statman_package(self): import statman sw = statman.Stopwatch() @@ -71,7 +75,6 @@ def test_create_stopwatch_directly(self): time.sleep(1) self.assertAlmostEqual(sw.read(), 1, delta=0.1) - def test_create_stopwatch_via_statman_constructor(self): sw = Statman.stopwatch() sw.start() @@ -182,6 +185,7 @@ def test_manually_registry(self): class TestCalculationViaStatman(TestStatman): + def test_calculation_metric(self): Statman.stopwatch('sw').start() time.sleep(0.5) @@ -212,4 +216,4 @@ def test_mutated_registry_during_reporting(self): Statman.stopwatch('sw') Statman.calculation( 'messages_per_second').calculation_function = lambda: (Statman.gauge('messages_processed').value / Statman.stopwatch('sw').value) - Statman.report(output_stdout=True) \ No newline at end of file + Statman.report(output_stdout=True) From ceb030da484e3d2ba6d1284e912ca61b816592de Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 23:09:53 -0500 Subject: [PATCH 04/14] provide threadsafe stopwatch Signed-off-by: Jason Ray --- statman/history.py | 3 +-- statman/statman.py | 24 +++++++++++++++++++++++- statman/stopwatch.py | 8 ++++++-- statman/tests/test_statman.py | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/statman/history.py b/statman/history.py index 94baa8a..ebdcb67 100644 --- a/statman/history.py +++ b/statman/history.py @@ -9,8 +9,7 @@ class History(): def __init__(self): self._data = [] - def __str__(self): - pass + # def __str__(self): def append(self, dt: datetime = None, value: float = None) -> str: event = self.create_event(dt=dt, value=value) diff --git a/statman/statman.py b/statman/statman.py index afbce91..1a1d2e3 100644 --- a/statman/statman.py +++ b/statman/statman.py @@ -1,3 +1,5 @@ +import threading +import uuid from .stopwatch import Stopwatch from .gauge import Gauge from .calculation import Calculation @@ -24,8 +26,11 @@ def count() -> int: return len(Statman.metric_registry().keys()) @staticmethod - def stopwatch(name: str = None, autostart: bool = False, initial_delta: float = None, enable_history=False) -> Stopwatch: + def stopwatch(name: str = None, autostart: bool = False, initial_delta: float = None, enable_history=False, thread_safe=False) -> Stopwatch: ''' Returns a stopwatch instance. If there is a registered stopwatch with this name, return it. If there is no registered stopwatch with this name, create a new instance, register it, and return it. ''' + if thread_safe: + return Statman._stopwatch_threadsafe(name=name, autostart=autostart, initial_delta=initial_delta, enable_history=enable_history) + sw = Statman.metric_registry().get(name) if not sw: @@ -35,6 +40,23 @@ def stopwatch(name: str = None, autostart: bool = False, initial_delta: float = Statman.register(name, sw) return sw + + def _stopwatch_threadsafe(name: str = None, autostart: bool = False, initial_delta: float = None, enable_history=False): + parent_sw = Statman.metric_registry().get(name) + + if not parent_sw: + with threading.Lock(): + parent_sw = Statman.metric_registry().get(name) + if not parent_sw: + parent_sw = Stopwatch(name=name, autostart=autostart, initial_delta=initial_delta, enable_history=enable_history) + if not name is None: + Statman.register(name, parent_sw) + print(f'_stopwatch_threadsafe-{name}: add to registry {parent_sw=}') + + child_name = f'{name}.{uuid.uuid4()}' + child_sw= Stopwatch(name=child_name, autostart=autostart, initial_delta=initial_delta, enable_history=enable_history, history=parent_sw.history) + + return child_sw @staticmethod def gauge(name: str = None, value: float = 0) -> Gauge: diff --git a/statman/stopwatch.py b/statman/stopwatch.py index 8ff35da..094623d 100644 --- a/statman/stopwatch.py +++ b/statman/stopwatch.py @@ -10,12 +10,15 @@ class Stopwatch(Metric): _read_units = 'ms' _history = None - def __init__(self, name=None, autostart=False, initial_delta=None, enable_history=False): + def __init__(self, name=None, autostart=False, initial_delta=None, enable_history=False, history:History=None): super().__init__(name=name) self.reset() self._initial_delta = initial_delta if enable_history: - self._history = History() + if history: + self._history = history + else: + self._history = History() if autostart: self.start() @@ -44,6 +47,7 @@ def stop(self, units: str = 's', precision: int = None) -> float: if self.history: self.history.append(value=self.value) + print(f'sw.stop {self.name=} {self.history=} {self.history.count()=}') return self.read(units=units, precision=precision) diff --git a/statman/tests/test_statman.py b/statman/tests/test_statman.py index 2a04a56..8a9e1ed 100644 --- a/statman/tests/test_statman.py +++ b/statman/tests/test_statman.py @@ -183,6 +183,39 @@ def test_manually_registry(self): time.sleep(1) self.assertAlmostEqual(sw.read(), 1, delta=0.1) +class TestStopwatchViaStatmanConcurrency(TestStatman): + def test_concurrent_access(self): + from statman import Statman as SM + + sw1 = SM.stopwatch(name='sw', autostart=False, enable_history=True, thread_safe=True) + self.assertIsNotNone(sw1) + sw1.start() + + time.sleep(0.5) + + sw2 = SM.stopwatch(name='sw', autostart=False, enable_history=True, thread_safe=True) + self.assertIsNotNone(sw2) + sw2.start() + + time.sleep(1) + + sw1.stop() + + time.sleep(1) + + sw2.stop() + + + self.assertIsNot(sw1, sw2) + print(sw1.history) + print(sw2.history) + self.assertIs(sw1.history , sw2.history) + self.assertAlmostEqual(sw1.value , 1.5 , places=0) + self.assertAlmostEqual(sw2.value , 2.0 , places=0) + + self.assertEqual(sw1.history.count() , 2) + self.assertEqual(sw2.history.count() , 2) + class TestCalculationViaStatman(TestStatman): From ccf5cd0bb63c01c61734905c27659ddabdf75b62 Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 23:10:29 -0500 Subject: [PATCH 05/14] formatting Signed-off-by: Jason Ray --- statman/statman.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/statman/statman.py b/statman/statman.py index 1a1d2e3..e5f83f5 100644 --- a/statman/statman.py +++ b/statman/statman.py @@ -40,7 +40,7 @@ def stopwatch(name: str = None, autostart: bool = False, initial_delta: float = Statman.register(name, sw) return sw - + def _stopwatch_threadsafe(name: str = None, autostart: bool = False, initial_delta: float = None, enable_history=False): parent_sw = Statman.metric_registry().get(name) @@ -53,8 +53,12 @@ def _stopwatch_threadsafe(name: str = None, autostart: bool = False, initial_del Statman.register(name, parent_sw) print(f'_stopwatch_threadsafe-{name}: add to registry {parent_sw=}') - child_name = f'{name}.{uuid.uuid4()}' - child_sw= Stopwatch(name=child_name, autostart=autostart, initial_delta=initial_delta, enable_history=enable_history, history=parent_sw.history) + child_name = f'{name}.{uuid.uuid4()}' + child_sw = Stopwatch(name=child_name, + autostart=autostart, + initial_delta=initial_delta, + enable_history=enable_history, + history=parent_sw.history) return child_sw From db8389b54281fb2976cef79a587fc94fe7c84dba Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 23:10:33 -0500 Subject: [PATCH 06/14] formatting Signed-off-by: Jason Ray --- statman/stopwatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/statman/stopwatch.py b/statman/stopwatch.py index 094623d..c2247b4 100644 --- a/statman/stopwatch.py +++ b/statman/stopwatch.py @@ -10,7 +10,7 @@ class Stopwatch(Metric): _read_units = 'ms' _history = None - def __init__(self, name=None, autostart=False, initial_delta=None, enable_history=False, history:History=None): + def __init__(self, name=None, autostart=False, initial_delta=None, enable_history=False, history: History = None): super().__init__(name=name) self.reset() self._initial_delta = initial_delta From db1b14fe79b5171b07ee6ef53f1e24b3f1f76a28 Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 23:10:39 -0500 Subject: [PATCH 07/14] formatting Signed-off-by: Jason Ray --- statman/tests/test_statman.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/statman/tests/test_statman.py b/statman/tests/test_statman.py index 8a9e1ed..6d3752c 100644 --- a/statman/tests/test_statman.py +++ b/statman/tests/test_statman.py @@ -183,7 +183,9 @@ def test_manually_registry(self): time.sleep(1) self.assertAlmostEqual(sw.read(), 1, delta=0.1) + class TestStopwatchViaStatmanConcurrency(TestStatman): + def test_concurrent_access(self): from statman import Statman as SM @@ -205,16 +207,15 @@ def test_concurrent_access(self): sw2.stop() - - self.assertIsNot(sw1, sw2) + self.assertIsNot(sw1, sw2) print(sw1.history) print(sw2.history) - self.assertIs(sw1.history , sw2.history) - self.assertAlmostEqual(sw1.value , 1.5 , places=0) - self.assertAlmostEqual(sw2.value , 2.0 , places=0) + self.assertIs(sw1.history, sw2.history) + self.assertAlmostEqual(sw1.value, 1.5, places=0) + self.assertAlmostEqual(sw2.value, 2.0, places=0) - self.assertEqual(sw1.history.count() , 2) - self.assertEqual(sw2.history.count() , 2) + self.assertEqual(sw1.history.count(), 2) + self.assertEqual(sw2.history.count(), 2) class TestCalculationViaStatman(TestStatman): From d4fe83609cc989edf165e87031cf712ed55b1b2c Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 23:11:06 -0500 Subject: [PATCH 08/14] make method static Signed-off-by: Jason Ray --- statman/statman.py | 1 + 1 file changed, 1 insertion(+) diff --git a/statman/statman.py b/statman/statman.py index e5f83f5..99da44e 100644 --- a/statman/statman.py +++ b/statman/statman.py @@ -41,6 +41,7 @@ def stopwatch(name: str = None, autostart: bool = False, initial_delta: float = return sw + @staticmethod def _stopwatch_threadsafe(name: str = None, autostart: bool = False, initial_delta: float = None, enable_history=False): parent_sw = Statman.metric_registry().get(name) From e1a667737e24fdadcd48a316599902f3e3d91958 Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 23:12:55 -0500 Subject: [PATCH 09/14] simplify if/else Signed-off-by: Jason Ray --- statman/statman.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/statman/statman.py b/statman/statman.py index 99da44e..62e4644 100644 --- a/statman/statman.py +++ b/statman/statman.py @@ -213,11 +213,10 @@ def refresh(self): Statman.gauge(statman_key).value = value else: print(f'skipping non-numeric value {key=} {value=} {statman_key=}') + elif isinstance(value, (int, float) ): + print(f'skipping non-dictionary, numeric {result=}') else: - if isinstance(value, int) or isinstance(value, float): - print(f'skipping non-dictionary, numeric {result=}') - else: - print(f'skipping non-dictionary, non-numeric {result=}') + print(f'skipping non-dictionary, non-numeric {result=}') except Exception as e: print(f'failed to execute refresh method [{self._name}][{e}]') From ae6cbbd632264350d71ab0d1d075e8fa075d993d Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 23:13:10 -0500 Subject: [PATCH 10/14] formatting Signed-off-by: Jason Ray --- statman/statman.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/statman/statman.py b/statman/statman.py index 62e4644..0cac157 100644 --- a/statman/statman.py +++ b/statman/statman.py @@ -213,7 +213,7 @@ def refresh(self): Statman.gauge(statman_key).value = value else: print(f'skipping non-numeric value {key=} {value=} {statman_key=}') - elif isinstance(value, (int, float) ): + elif isinstance(value, (int, float)): print(f'skipping non-dictionary, numeric {result=}') else: print(f'skipping non-dictionary, non-numeric {result=}') From b30bb3c1b5dfa5497b79711c6bee45c333599ea1 Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 23:13:35 -0500 Subject: [PATCH 11/14] lint Signed-off-by: Jason Ray --- statman/statman.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/statman/statman.py b/statman/statman.py index 0cac157..30c24b9 100644 --- a/statman/statman.py +++ b/statman/statman.py @@ -1,11 +1,11 @@ import threading import uuid +from is_numeric import is_numeric from .stopwatch import Stopwatch from .gauge import Gauge from .calculation import Calculation from .rate import Rate from .metric import Metric -from is_numeric import is_numeric _registry = {} From 9a084295f25f4212789c94693a0e74c0df092d4a Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 23:14:49 -0500 Subject: [PATCH 12/14] lint Signed-off-by: Jason Ray --- statman/statman.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/statman/statman.py b/statman/statman.py index 30c24b9..5adf894 100644 --- a/statman/statman.py +++ b/statman/statman.py @@ -46,7 +46,8 @@ def _stopwatch_threadsafe(name: str = None, autostart: bool = False, initial_del parent_sw = Statman.metric_registry().get(name) if not parent_sw: - with threading.Lock(): + lock = threading.Lock() + with lock: parent_sw = Statman.metric_registry().get(name) if not parent_sw: parent_sw = Stopwatch(name=name, autostart=autostart, initial_delta=initial_delta, enable_history=enable_history) From 086511d8aebb9909004a7b13fa59385af5711b07 Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Thu, 14 Dec 2023 23:19:22 -0500 Subject: [PATCH 13/14] lint Signed-off-by: Jason Ray --- statman/statman.py | 2 +- statman/stopwatch.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/statman/statman.py b/statman/statman.py index 5adf894..76ac272 100644 --- a/statman/statman.py +++ b/statman/statman.py @@ -50,7 +50,7 @@ def _stopwatch_threadsafe(name: str = None, autostart: bool = False, initial_del with lock: parent_sw = Statman.metric_registry().get(name) if not parent_sw: - parent_sw = Stopwatch(name=name, autostart=autostart, initial_delta=initial_delta, enable_history=enable_history) + parent_sw = Stopwatch(name=name, autostart=False, enable_history=enable_history) if not name is None: Statman.register(name, parent_sw) print(f'_stopwatch_threadsafe-{name}: add to registry {parent_sw=}') diff --git a/statman/stopwatch.py b/statman/stopwatch.py index c2247b4..02764e7 100644 --- a/statman/stopwatch.py +++ b/statman/stopwatch.py @@ -1,6 +1,6 @@ import time -from .metric import Metric from statman.history import History +from .metric import Metric class Stopwatch(Metric): @@ -59,7 +59,7 @@ def restart(self): self.reset() self.start() - def read(self, units: str = 's', precision: int = None) -> float: + def read(self, precision: int = None, units: str = 's') -> float: delta = None if self._start_time: stop_time = None From 804dfe0520f3bf8432de7395a064fea75ddd6285 Mon Sep 17 00:00:00 2001 From: Jason Ray Date: Fri, 15 Dec 2023 10:50:36 -0500 Subject: [PATCH 14/14] threadsafe decorator Signed-off-by: Jason Ray --- README.md | 15 +++++++++++++++ statman/decorators.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 63e2d9c..117ceeb 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,21 @@ Statman.stopwatch('stopwatch-name').read() print(f'event took {Statman.stopwatch('stopwatch-name').read(precision=1)}s to execute') # event took 1.0s to execute ``` +### Stopwatch via Statman Registry with thread safety +Most use cases of statman are thread safe. However, the one that is not is using stopwatch via registry. If you want to use stopwatch via statman in a threaded env, small change. + +``` python +from statman import Statman + +sw1 = SM.stopwatch(name='sw', thread_safe=True) +sw1.start() +# do some expensive operation that you want to measure +sw1.read() + +print(f'event took {sw1.read(precision=1)}s to execute') # event took 1.0s to execute +``` + + ### Stopwatch: Direct Usage (no registry) ``` python from statman import Stopwatch diff --git a/statman/decorators.py b/statman/decorators.py index b2b8fcd..3813cf7 100644 --- a/statman/decorators.py +++ b/statman/decorators.py @@ -6,7 +6,7 @@ def timer(name): def timer_inner_decorator(func): def timer_wrapper(*args, **kwargs): - sw = Statman.stopwatch(name=name, enable_history=True) + sw = Statman.stopwatch(name=name, enable_history=True, thread_safe=True) sw.start() result = func(*args, **kwargs) sw.stop()