diff --git a/prometheus_client/metrics.py b/prometheus_client/metrics.py index dfa158b9..01b07e58 100644 --- a/prometheus_client/metrics.py +++ b/prometheus_client/metrics.py @@ -761,6 +761,7 @@ class Enum(MetricWrapperBase): e.state('running') The first listed state will be the default. + The full metric name, including namespace and subsystem, is reserved as a label name. Enum metrics do not work in multiprocess mode. """ _type = 'stateset' @@ -776,7 +777,7 @@ def __init__(self, _labelvalues: Optional[Sequence[str]] = None, states: Optional[Sequence[str]] = None, ): - if name in labelnames: + if name in labelnames or _build_full_name(self._type, name, namespace, subsystem, unit) in labelnames: raise ValueError(f'Overlapping labels for Enum metric: {name}') if not states: raise ValueError(f'No states provided for Enum metric: {name}') diff --git a/tests/test_core.py b/tests/test_core.py index 2c29f79a..8f0174da 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -609,6 +609,23 @@ def test_failed_init_does_not_pollute_registry(self): Enum('task_state', 'help', states=['a', 'b'], registry=registry) self.assertEqual(1, registry.get_sample_value('task_state', {'task_state': 'a'})) + def test_prefixed_name_does_not_overlap_labels(self): + for namespace, subsystem in [('app', ''), ('', 'worker'), ('app', 'worker')]: + with self.subTest(namespace=namespace, subsystem=subsystem): + registry = CollectorRegistry() + name = '_'.join(part for part in (namespace, subsystem, 'state') if part) + with self.assertRaisesRegex(ValueError, 'Overlapping labels'): + Enum('state', 'help', namespace=namespace, subsystem=subsystem, + labelnames=[name], states=['a', 'b'], registry=registry) + self.assertEqual([], list(registry.collect())) + + metric = Enum('state', 'help', namespace=namespace, subsystem=subsystem, + labelnames=['tenant'], states=['a', 'b'], registry=registry) + metric.labels('one').state('a') + metric.labels('two').state('b') + self.assertEqual(1, registry.get_sample_value(name, {'tenant': 'one', name: 'a'})) + self.assertEqual(1, registry.get_sample_value(name, {'tenant': 'two', name: 'b'})) + class TestMetricWrapper(unittest.TestCase): def setUp(self):