diff --git a/prometheus_client/metrics.py b/prometheus_client/metrics.py index 8878fb86..45125b42 100644 --- a/prometheus_client/metrics.py +++ b/prometheus_client/metrics.py @@ -275,7 +275,7 @@ def f(): def _metric_init(self) -> None: self._value = values.ValueClass(self._type, self._name, self._name + '_total', self._labelnames, - self._labelvalues) + self._labelvalues, self._documentation) self._created = time.time() def inc(self, amount: float = 1, exemplar: Optional[Dict[str, str]] = None) -> None: @@ -377,7 +377,7 @@ def __init__(self, def _metric_init(self) -> None: self._value = values.ValueClass( self._type, self._name, self._name, self._labelnames, self._labelvalues, - multiprocess_mode=self._multiprocess_mode + self._documentation, multiprocess_mode=self._multiprocess_mode ) def inc(self, amount: float = 1) -> None: @@ -469,8 +469,8 @@ def create_response(request): def _metric_init(self) -> None: self._count = values.ValueClass(self._type, self._name, self._name + '_count', self._labelnames, - self._labelvalues) - self._sum = values.ValueClass(self._type, self._name, self._name + '_sum', self._labelnames, self._labelvalues) + self._labelvalues, self._documentation) + self._sum = values.ValueClass(self._type, self._name, self._name + '_sum', self._labelnames, self._labelvalues, self._documentation) self._created = time.time() def observe(self, amount: float) -> None: @@ -583,14 +583,15 @@ def _metric_init(self) -> None: self._buckets: List[values.ValueClass] = [] self._created = time.time() bucket_labelnames = self._labelnames + ('le',) - self._sum = values.ValueClass(self._type, self._name, self._name + '_sum', self._labelnames, self._labelvalues) + self._sum = values.ValueClass(self._type, self._name, self._name + '_sum', self._labelnames, self._labelvalues, self._documentation) for b in self._upper_bounds: self._buckets.append(values.ValueClass( self._type, self._name, self._name + '_bucket', bucket_labelnames, - self._labelvalues + (floatToGoString(b),)) + self._labelvalues + (floatToGoString(b),), + self._documentation) ) def observe(self, amount: float, exemplar: Optional[Dict[str, str]] = None) -> None: diff --git a/prometheus_client/mmap_dict.py b/prometheus_client/mmap_dict.py index 5c8e0fbd..c3de38fa 100644 --- a/prometheus_client/mmap_dict.py +++ b/prometheus_client/mmap_dict.py @@ -2,6 +2,7 @@ import mmap import os import struct +from typing import List _INITIAL_MMAP_SIZE = 1 << 16 _pack_integer_func = struct.Struct(b'i').pack @@ -137,8 +138,8 @@ def close(self): self._f = None -def mmap_key(metric_name, name, labelnames, labelvalues): +def mmap_key(metric_name: str, name: str, labelnames: List[str], labelvalues: List[str], help_text: str) -> str: """Format a key for use in the mmap file.""" # ensure labels are in consistent order for identity labels = dict(zip(labelnames, labelvalues)) - return json.dumps([metric_name, name, labels], sort_keys=True) + return json.dumps([metric_name, name, labels, help_text], sort_keys=True) diff --git a/prometheus_client/multiprocess.py b/prometheus_client/multiprocess.py index 5a23c482..dd343913 100644 --- a/prometheus_client/multiprocess.py +++ b/prometheus_client/multiprocess.py @@ -15,8 +15,6 @@ except NameError: # Python >= 2.5 FileNotFoundError = IOError -MP_METRIC_HELP = 'Multiprocess metric' - class MultiProcessCollector: """Collector for files for multi-process mode.""" @@ -53,9 +51,9 @@ def _read_metrics(files): def _parse_key(key): val = key_cache.get(key) if not val: - metric_name, name, labels = json.loads(key) + metric_name, name, labels, help_text = json.loads(key) labels_key = tuple(sorted(labels.items())) - val = key_cache[key] = (metric_name, name, labels, labels_key) + val = key_cache[key] = (metric_name, name, labels, labels_key, help_text) return val for f in files: @@ -71,11 +69,11 @@ def _parse_key(key): continue raise for key, value, _ in file_values: - metric_name, name, labels, labels_key = _parse_key(key) + metric_name, name, labels, labels_key, help_text = _parse_key(key) metric = metrics.get(metric_name) if metric is None: - metric = Metric(metric_name, MP_METRIC_HELP, typ) + metric = Metric(metric_name, help_text, typ) metrics[metric_name] = metric if typ == 'gauge': diff --git a/prometheus_client/values.py b/prometheus_client/values.py index 03b203be..3373379b 100644 --- a/prometheus_client/values.py +++ b/prometheus_client/values.py @@ -10,7 +10,7 @@ class MutexValue: _multiprocess = False - def __init__(self, typ, metric_name, name, labelnames, labelvalues, **kwargs): + def __init__(self, typ, metric_name, name, labelnames, labelvalues, help_text, **kwargs): self._value = 0.0 self._exemplar = None self._lock = Lock() @@ -57,8 +57,8 @@ class MmapedValue: _multiprocess = True - def __init__(self, typ, metric_name, name, labelnames, labelvalues, multiprocess_mode='', **kwargs): - self._params = typ, metric_name, name, labelnames, labelvalues, multiprocess_mode + def __init__(self, typ, metric_name, name, labelnames, labelvalues, help_text, multiprocess_mode='', **kwargs): + self._params = typ, metric_name, name, labelnames, labelvalues, help_text, multiprocess_mode # This deprecation warning can go away in a few releases when removing the compatibility if 'prometheus_multiproc_dir' in os.environ and 'PROMETHEUS_MULTIPROC_DIR' not in os.environ: os.environ['PROMETHEUS_MULTIPROC_DIR'] = os.environ['prometheus_multiproc_dir'] @@ -69,7 +69,7 @@ def __init__(self, typ, metric_name, name, labelnames, labelvalues, multiprocess values.append(self) def __reset(self): - typ, metric_name, name, labelnames, labelvalues, multiprocess_mode = self._params + typ, metric_name, name, labelnames, labelvalues, help_text, multiprocess_mode = self._params if typ == 'gauge': file_prefix = typ + '_' + multiprocess_mode else: @@ -81,7 +81,7 @@ def __reset(self): files[file_prefix] = MmapedDict(filename) self._file = files[file_prefix] - self._key = mmap_key(metric_name, name, labelnames, labelvalues) + self._key = mmap_key(metric_name, name, labelnames, labelvalues, help_text) self._value = self._file.read_value(self._key) def __check_for_pid_change(self): diff --git a/tests/test_multiprocess.py b/tests/test_multiprocess.py index a41903a1..10990ad3 100644 --- a/tests/test_multiprocess.py +++ b/tests/test_multiprocess.py @@ -281,6 +281,31 @@ def add_label(key, value): self.assertEqual(metrics['h'].samples, expected_histogram) + def test_collect_preserves_help(self): + pid = 0 + values.ValueClass = MultiProcessValue(lambda: pid) + labels = {i: i for i in 'abcd'} + + c = Counter('c', 'c help', labelnames=labels.keys(), registry=None) + g = Gauge('g', 'g help', labelnames=labels.keys(), registry=None) + h = Histogram('h', 'h help', labelnames=labels.keys(), registry=None) + + c.labels(**labels).inc(1) + g.labels(**labels).set(1) + h.labels(**labels).observe(1) + + pid = 1 + + c.labels(**labels).inc(1) + g.labels(**labels).set(1) + h.labels(**labels).observe(5) + + metrics = {m.name: m for m in self.collector.collect()} + + self.assertEqual(metrics['c'].documentation, 'c help') + self.assertEqual(metrics['g'].documentation, 'g help') + self.assertEqual(metrics['h'].documentation, 'h help') + def test_merge_no_accumulate(self): pid = 0 values.ValueClass = MultiProcessValue(lambda: pid)