From b26a859a76f357a7f11c6c9ed9e2e301ce1ba083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Vokr=C3=A1=C4=8Dko?= Date: Thu, 23 Apr 2026 09:45:05 +0200 Subject: [PATCH 1/4] Expose measured duration on Timer context manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assigning the .time() context manager (with ... as t) now yields a Timer whose .duration attribute holds the observed value in seconds after the block exits. This lets callers reuse the measurement (logging, further metrics) without calling default_timer() a second time. Signed-off-by: Lukáš Vokráčko --- docs/content/instrumenting/gauge.md | 4 ++++ docs/content/instrumenting/histogram.md | 4 ++++ docs/content/instrumenting/summary.md | 4 ++++ prometheus_client/context_managers.py | 5 +++-- tests/test_core.py | 8 ++++++++ 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/content/instrumenting/gauge.md b/docs/content/instrumenting/gauge.md index 43168a68..901894ba 100644 --- a/docs/content/instrumenting/gauge.md +++ b/docs/content/instrumenting/gauge.md @@ -108,6 +108,10 @@ def process(): with g.time(): pass + +with g.time() as t: + pass +# t.duration holds the observed seconds ``` ### `set_function(f)` diff --git a/docs/content/instrumenting/histogram.md b/docs/content/instrumenting/histogram.md index 8975d859..8213d059 100644 --- a/docs/content/instrumenting/histogram.md +++ b/docs/content/instrumenting/histogram.md @@ -86,6 +86,10 @@ def process(): with h.time(): pass + +with h.time() as t: + pass +# t.duration holds the observed seconds ``` ## Labels diff --git a/docs/content/instrumenting/summary.md b/docs/content/instrumenting/summary.md index 55428ecb..bcb5df1d 100644 --- a/docs/content/instrumenting/summary.md +++ b/docs/content/instrumenting/summary.md @@ -68,6 +68,10 @@ def process(): with s.time(): pass + +with s.time() as t: + pass +# t.duration holds the observed seconds ``` ## Labels diff --git a/prometheus_client/context_managers.py b/prometheus_client/context_managers.py index 3988ec22..3e8d7ced 100644 --- a/prometheus_client/context_managers.py +++ b/prometheus_client/context_managers.py @@ -55,6 +55,7 @@ class Timer: def __init__(self, metric, callback_name): self._metric = metric self._callback_name = callback_name + self.duration = None def _new_timer(self): return self.__class__(self._metric, self._callback_name) @@ -65,9 +66,9 @@ def __enter__(self): def __exit__(self, typ, value, traceback): # Time can go backwards. - duration = max(default_timer() - self._start, 0) + self.duration = max(default_timer() - self._start, 0) callback = getattr(self._metric, self._callback_name) - callback(duration) + callback(self.duration) def labels(self, *args, **kw): self._metric = self._metric.labels(*args, **kw) diff --git a/tests/test_core.py b/tests/test_core.py index 66492c6f..cdf32bfa 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -378,6 +378,14 @@ def test_block_decorator_with_label(self): metric.labels('foo') self.assertEqual(1, value('s_with_labels_count', {'label1': 'foo'})) + def test_timer_duration_exposed(self): + with self.summary.time() as t: + time.sleep(0.01) + self.assertIsNotNone(t.duration) + self.assertGreater(t.duration, 0) + recorded_sum = self.registry.get_sample_value('s_sum') + self.assertEqual(t.duration, recorded_sum) + def test_timer_not_observable(self): s = Summary('test', 'help', labelnames=('label',), registry=self.registry) From b941deb297ee2856b963112f887dd347c05f1fdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Vokr=C3=A1=C4=8Dko?= Date: Fri, 24 Apr 2026 07:18:08 +0200 Subject: [PATCH 2/4] Update docs/content/instrumenting/summary.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukáš Vokráčko --- docs/content/instrumenting/summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/instrumenting/summary.md b/docs/content/instrumenting/summary.md index bcb5df1d..714dfd2f 100644 --- a/docs/content/instrumenting/summary.md +++ b/docs/content/instrumenting/summary.md @@ -71,7 +71,7 @@ with s.time(): with s.time() as t: pass -# t.duration holds the observed seconds +print(t.duration) # observed time in seconds. ``` ## Labels From 76edfd5d24058234eeb66b04fbc666137cd0de01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Vokr=C3=A1=C4=8Dko?= Date: Fri, 24 Apr 2026 07:18:15 +0200 Subject: [PATCH 3/4] Update docs/content/instrumenting/histogram.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lukáš Vokráčko --- docs/content/instrumenting/histogram.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/instrumenting/histogram.md b/docs/content/instrumenting/histogram.md index 8213d059..fa0ffe1a 100644 --- a/docs/content/instrumenting/histogram.md +++ b/docs/content/instrumenting/histogram.md @@ -89,7 +89,7 @@ with h.time(): with h.time() as t: pass -# t.duration holds the observed seconds +print(t.duration) # observed time in seconds. ``` ## Labels From 0897499c7e892f89b0ac9f4b96941ba1ae3fcf2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Vokr=C3=A1=C4=8Dko?= Date: Fri, 24 Apr 2026 07:18:25 +0200 Subject: [PATCH 4/4] Update docs/content/instrumenting/gauge.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Chris Marchbanks Signed-off-by: Lukáš Vokráčko --- docs/content/instrumenting/gauge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/instrumenting/gauge.md b/docs/content/instrumenting/gauge.md index 901894ba..62294944 100644 --- a/docs/content/instrumenting/gauge.md +++ b/docs/content/instrumenting/gauge.md @@ -111,7 +111,7 @@ with g.time(): with g.time() as t: pass -# t.duration holds the observed seconds +print(t.duration) # observed time in seconds. ``` ### `set_function(f)`