Skip to content

Commit

Permalink
Merge pull request #804 from butlerx/multi-process-help
Browse files Browse the repository at this point in the history
Support metric help text in multiprocess mode
  • Loading branch information
csmarchbanks committed Dec 22, 2022
2 parents d6e08e3 + 9a2c50f commit 781e3e1
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 19 deletions.
13 changes: 7 additions & 6 deletions prometheus_client/metrics.py
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
5 changes: 3 additions & 2 deletions prometheus_client/mmap_dict.py
Expand Up @@ -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
Expand Down Expand Up @@ -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)
10 changes: 4 additions & 6 deletions prometheus_client/multiprocess.py
Expand Up @@ -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."""
Expand Down Expand Up @@ -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:
Expand All @@ -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':
Expand Down
10 changes: 5 additions & 5 deletions prometheus_client/values.py
Expand Up @@ -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()
Expand Down Expand Up @@ -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']
Expand All @@ -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:
Expand All @@ -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):
Expand Down
25 changes: 25 additions & 0 deletions tests/test_multiprocess.py
Expand Up @@ -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)
Expand Down

0 comments on commit 781e3e1

Please sign in to comment.