diff --git a/README.md b/README.md index 5af4cc51..67220f9e 100644 --- a/README.md +++ b/README.md @@ -185,13 +185,13 @@ c.labels('get', '/').inc() c.labels('post', '/submit').inc() ``` -Labels can also be provided as a dict: +Labels can also be passed as keyword-arguments: ```python from prometheus_client import Counter c = Counter('my_requests_total', 'HTTP Failures', ['method', 'endpoint']) -c.labels({'method': 'get', 'endpoint': '/'}).inc() -c.labels({'method': 'post', 'endpoint': '/submit'}).inc() +c.labels(method='get', endpoint='/').inc() +c.labels(method='post', endpoint='/submit').inc() ``` ### Process Collector @@ -369,7 +369,7 @@ REGISTRY.register(CustomCollector()) ## Parser The Python client supports parsing the Promeheus text format. -This is intended for advanced use cases where you have servers +This is intended for advanced use cases where you have servers exposing Prometheus metrics and need to get them into some other system. @@ -379,4 +379,3 @@ for family in text_string_to_metric_families("my_gauge 1.0\n"): for sample in family.samples: print("Name: {0} Labels: {1} Value: {2}".format(*sample)) ``` - diff --git a/prometheus_client/core.py b/prometheus_client/core.py index 66198025..1752b71d 100644 --- a/prometheus_client/core.py +++ b/prometheus_client/core.py @@ -253,7 +253,7 @@ def __init__(self, wrappedClass, name, labelnames, **kwargs): if l.startswith('__'): raise ValueError('Invalid label metric name: ' + l) - def labels(self, *labelvalues): + def labels(self, *labelvalues, **labelkwargs): '''Return the child for the given labelset. All metrics can have labels, allowing grouping of related time series. @@ -276,10 +276,13 @@ def labels(self, *labelvalues): See the best practices on [naming](http://prometheus.io/docs/practices/naming/) and [labels](http://prometheus.io/docs/practices/instrumentation/#use-labels). ''' - if len(labelvalues) == 1 and type(labelvalues[0]) == dict: - if sorted(labelvalues[0].keys()) != sorted(self._labelnames): + if labelvalues and labelkwargs: + raise ValueError("Can't pass both *args and **kwargs") + + if labelkwargs: + if sorted(labelkwargs) != sorted(self._labelnames): raise ValueError('Incorrect label names') - labelvalues = tuple([unicode(labelvalues[0][l]) for l in self._labelnames]) + labelvalues = tuple([unicode(labelkwargs[l]) for l in self._labelnames]) else: if len(labelvalues) != len(self._labelnames): raise ValueError('Incorrect label count') diff --git a/tests/test_core.py b/tests/test_core.py index 83b15e86..d8d8311a 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -249,7 +249,7 @@ def test_incorrect_label_count_raises(self): def test_labels_coerced_to_string(self): self.counter.labels(None).inc() - self.counter.labels({'l': None}).inc() + self.counter.labels(l=None).inc() self.assertEqual(2, self.registry.get_sample_value('c', {'l': 'None'})) self.counter.remove(None) @@ -259,26 +259,27 @@ def test_non_string_labels_raises(self): class Test(object): __str__ = None self.assertRaises(TypeError, self.counter.labels, Test()) - self.assertRaises(TypeError, self.counter.labels, {'l': Test()}) + self.assertRaises(TypeError, self.counter.labels, l=Test()) def test_namespace_subsystem_concatenated(self): c = Counter('c', 'help', namespace='a', subsystem='b', registry=self.registry) c.inc() self.assertEqual(1, self.registry.get_sample_value('a_b_c')) - def test_labels_by_dict(self): - self.counter.labels({'l': 'x'}).inc() + def test_labels_by_kwarg(self): + self.counter.labels(l='x').inc() self.assertEqual(1, self.registry.get_sample_value('c', {'l': 'x'})) - self.assertRaises(ValueError, self.counter.labels, {'l': 'x', 'm': 'y'}) - self.assertRaises(ValueError, self.counter.labels, {'m': 'y'}) - self.assertRaises(ValueError, self.counter.labels, {}) - self.two_labels.labels({'a': 'x', 'b': 'y'}).inc() + self.assertRaises(ValueError, self.counter.labels, l='x', m='y') + self.assertRaises(ValueError, self.counter.labels, m='y') + self.assertRaises(ValueError, self.counter.labels) + self.two_labels.labels(a='x', b='y').inc() self.assertEqual(1, self.registry.get_sample_value('two', {'a': 'x', 'b': 'y'})) - self.assertRaises(ValueError, self.two_labels.labels, {'a': 'x', 'b': 'y', 'c': 'z'}) - self.assertRaises(ValueError, self.two_labels.labels, {'a': 'x', 'c': 'z'}) - self.assertRaises(ValueError, self.two_labels.labels, {'b': 'y', 'c': 'z'}) - self.assertRaises(ValueError, self.two_labels.labels, {'c': 'z'}) - self.assertRaises(ValueError, self.two_labels.labels, {}) + self.assertRaises(ValueError, self.two_labels.labels, a='x', b='y', c='z') + self.assertRaises(ValueError, self.two_labels.labels, a='x', c='z') + self.assertRaises(ValueError, self.two_labels.labels, b='y', c='z') + self.assertRaises(ValueError, self.two_labels.labels, c='z') + self.assertRaises(ValueError, self.two_labels.labels) + self.assertRaises(ValueError, self.two_labels.labels, {'a': 'x'}, b='y') def test_invalid_names_raise(self): self.assertRaises(ValueError, Counter, '', 'help')