Skip to content

Commit

Permalink
Add tags support to GraphiteBridge
Browse files Browse the repository at this point in the history
Graphite has support for tagged metrics with a syntax very similar to
the non-tagged format.  Update GraphiteBridge to support it.

Signed-off-by: Matt Wilder <me@partcyb.org>
  • Loading branch information
partcyborg committed Feb 3, 2021
1 parent fdd741c commit 1041d23
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 6 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,13 +440,24 @@ Metrics are pushed over TCP in the Graphite plaintext format.
```python
from prometheus_client.bridge.graphite import GraphiteBridge

gb = GraphiteBridge(('graphite.your.org', 2003))
gb = GraphiteBridge('graphite.your.org', 2003)
# Push once.
gb.push()
# Push every 10 seconds in a daemon thread.
gb.start(10.0)
```

Graphite [tags](https://grafana.com/blog/2018/01/11/graphite-1.1-teaching-an-old-dog-new-tricks/) are also supported.

```python
from prometheus_client.bridge.graphite import GraphiteBridge

gb = GraphiteBridge('graphite.your.org', 2003, tags=True)
c = Counter('my_requests_total', 'HTTP Failures', ['method', 'endpoint'])
c.labels('get', '/').inc()
gb.push()
```

## Custom Collectors

Sometimes it is not possible to directly instrument code, as it is not
Expand Down
13 changes: 10 additions & 3 deletions prometheus_client/bridge/graphite.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ def run(self):


class GraphiteBridge(object):
def __init__(self, address, registry=REGISTRY, timeout_seconds=30, _timer=time.time):
def __init__(self, address, registry=REGISTRY, tags=False, timeout_seconds=30, _timer=time.time):
self._address = address
self._registry = registry
self._tags = tags
self._timeout = timeout_seconds
self._timer = _timer

Expand All @@ -63,8 +64,14 @@ def push(self, prefix=''):
for metric in self._registry.collect():
for s in metric.samples:
if s.labels:
labelstr = '.' + '.'.join(
['{0}.{1}'.format(
if self._tags:
sep = ';'
fmt = '{0}={1}'
else:
sep = '.'
fmt = '{0}.{1}'
labelstr = sep + sep.join(
[fmt.format(
_sanitize(k), _sanitize(v))
for k, v in sorted(s.labels.items())])
else:
Expand Down
37 changes: 35 additions & 2 deletions tests/test_graphite_bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ def run(self):
self.t.start()

# Explicitly use localhost as the target host, since connecting to 0.0.0.0 fails on Windows
address = ('localhost', server.server_address[1])
self.gb = GraphiteBridge(address, self.registry, _timer=fake_timer)
self.address = ('localhost', server.server_address[1])
self.gb = GraphiteBridge(self.address, self.registry, _timer=fake_timer)

def _use_tags(self):
self.gb = GraphiteBridge(self.address, self.registry, tags=True, _timer=fake_timer)

def test_nolabels(self):
gauge = Gauge('g', 'help', registry=self.registry)
Expand All @@ -56,6 +59,16 @@ def test_labels(self):

self.assertEqual(b'labels.a.c.b.d 1.0 1434898897\n', self.data)

def test_labels_tags(self):
self._use_tags()
labels = Gauge('labels', 'help', ['a', 'b'], registry=self.registry)
labels.labels('c', 'd').inc()

self.gb.push()
self.t.join()

self.assertEqual(b'labels;a=c;b=d 1.0 1434898897\n', self.data)

def test_prefix(self):
labels = Gauge('labels', 'help', ['a', 'b'], registry=self.registry)
labels.labels('c', 'd').inc()
Expand All @@ -65,6 +78,16 @@ def test_prefix(self):

self.assertEqual(b'pre.fix.labels.a.c.b.d 1.0 1434898897\n', self.data)

def test_prefix_tags(self):
self._use_tags()
labels = Gauge('labels', 'help', ['a', 'b'], registry=self.registry)
labels.labels('c', 'd').inc()

self.gb.push(prefix='pre.fix')
self.t.join()

self.assertEqual(b'pre.fix.labels;a=c;b=d 1.0 1434898897\n', self.data)

def test_sanitizing(self):
labels = Gauge('labels', 'help', ['a'], registry=self.registry)
labels.labels('c.:8').inc()
Expand All @@ -73,3 +96,13 @@ def test_sanitizing(self):
self.t.join()

self.assertEqual(b'labels.a.c__8 1.0 1434898897\n', self.data)

def test_sanitizing_tags(self):
self._use_tags()
labels = Gauge('labels', 'help', ['a'], registry=self.registry)
labels.labels('c.:8').inc()

self.gb.push()
self.t.join()

self.assertEqual(b'labels;a=c__8 1.0 1434898897\n', self.data)

0 comments on commit 1041d23

Please sign in to comment.