diff --git a/README.md b/README.md index ad40e400..d9721a58 100644 --- a/README.md +++ b/README.md @@ -252,6 +252,13 @@ h = Histogram('request_latency_seconds', 'Description of histogram') h.observe(4.7, {'trace_id': 'abc123'}) ``` +### Disabling `_created` metrics + +By default counters, histograms, and summaries export an additional series +suffixed with `_created` and a value of the unix timestamp for when the metric +was created. If this information is not helpful, it can be disabled by setting +the environment variable `PROMETHEUS_DISABLE_CREATED_SERIES=True`. + ### Process Collector The Python client automatically exports metrics about process CPU usage, RAM, diff --git a/prometheus_client/metrics.py b/prometheus_client/metrics.py index 38e34161..41bec517 100644 --- a/prometheus_client/metrics.py +++ b/prometheus_client/metrics.py @@ -1,3 +1,4 @@ +import os from threading import Lock import time import types @@ -62,6 +63,13 @@ def _validate_exemplar(exemplar): raise ValueError('Exemplar labels have %d UTF-8 characters, exceeding the limit of 128') +def _get_use_created() -> bool: + return os.environ.get("PROMETHEUS_DISABLE_CREATED_SERIES", 'False').lower() not in ('true', '1', 't') + + +_use_created = _get_use_created() + + class MetricWrapperBase(Collector): _type: Optional[str] = None _reserved_labelnames: Sequence[str] = () @@ -291,10 +299,13 @@ def count_exceptions(self, exception: Type[BaseException] = Exception) -> Except return ExceptionCounter(self, exception) def _child_samples(self) -> Iterable[Sample]: - return ( - Sample('_total', {}, self._value.get(), None, self._value.get_exemplar()), - Sample('_created', {}, self._created, None, None), - ) + sample = Sample('_total', {}, self._value.get(), None, self._value.get_exemplar()) + if _use_created: + return ( + sample, + Sample('_created', {}, self._created, None, None) + ) + return (sample,) class Gauge(MetricWrapperBase): @@ -484,11 +495,13 @@ def time(self) -> Timer: return Timer(self, 'observe') def _child_samples(self) -> Iterable[Sample]: - return ( + samples = [ Sample('_count', {}, self._count.get(), None, None), Sample('_sum', {}, self._sum.get(), None, None), - Sample('_created', {}, self._created, None, None), - ) + ] + if _use_created: + samples.append(Sample('_created', {}, self._created, None, None)) + return tuple(samples) class Histogram(MetricWrapperBase): @@ -616,7 +629,8 @@ def _child_samples(self) -> Iterable[Sample]: samples.append(Sample('_count', {}, acc, None, None)) if self._upper_bounds[0] >= 0: samples.append(Sample('_sum', {}, self._sum.get(), None, None)) - samples.append(Sample('_created', {}, self._created, None, None)) + if _use_created: + samples.append(Sample('_created', {}, self._created, None, None)) return tuple(samples) diff --git a/tests/test_core.py b/tests/test_core.py index 36d521cc..6f7c9d1c 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1,9 +1,11 @@ from concurrent.futures import ThreadPoolExecutor +import os import time import unittest import pytest +from prometheus_client import metrics from prometheus_client.core import ( CollectorRegistry, Counter, CounterMetricFamily, Enum, Gauge, GaugeHistogramMetricFamily, GaugeMetricFamily, Histogram, @@ -11,6 +13,7 @@ StateSetMetricFamily, Summary, SummaryMetricFamily, UntypedMetricFamily, ) from prometheus_client.decorator import getargspec +from prometheus_client.metrics import _get_use_created def assert_not_observable(fn, *args, **kwargs): @@ -115,6 +118,32 @@ def test_exemplar_too_long(self): }) +class TestDisableCreated(unittest.TestCase): + def setUp(self): + self.registry = CollectorRegistry() + os.environ['PROMETHEUS_DISABLE_CREATED_SERIES'] = 'True' + metrics._use_created = _get_use_created() + + def tearDown(self): + os.environ.pop('PROMETHEUS_DISABLE_CREATED_SERIES', None) + metrics._use_created = _get_use_created() + + def test_counter(self): + counter = Counter('c_total', 'help', registry=self.registry) + counter.inc() + self.assertEqual(None, self.registry.get_sample_value('c_created')) + + def test_histogram(self): + histogram = Histogram('h', 'help', registry=self.registry) + histogram.observe(3.2) + self.assertEqual(None, self.registry.get_sample_value('h_created')) + + def test_summary(self): + summary = Summary('s', 'help', registry=self.registry) + summary.observe(8.2) + self.assertEqual(None, self.registry.get_sample_value('s_created')) + + class TestGauge(unittest.TestCase): def setUp(self): self.registry = CollectorRegistry()