Skip to content
This repository has been archived by the owner on Dec 11, 2023. It is now read-only.

Commit

Permalink
Merge pull request #172 from librato/inherit-tags
Browse files Browse the repository at this point in the history
add ability to inherit tags
  • Loading branch information
mbeale authored Sep 18, 2017
2 parents 737c26a + 05f2a18 commit bda57b2
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 25 deletions.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,43 @@ with api.new_queue() as q:
Queues by default will collect metrics until they are told to submit. You may create a queue
that autosubmits based on metric volume.


```python
# Submit when the 400th metric is queued
q = api.new_queue(auto_submit_count=400)
```

## Tag Inheritance

Tags can be inherited from the queue or connection object if `inherit_tags=True` is passed as
an attribute. If inherit_tags is not passed, but tags are added to the measurement, the measurement
tags will be the only tags added to that measurement.

When there are tag collisions, the measurement, then the batch, then the connection is the order of
priority.

```python
api = librato.connect('email', 'token', tags={'company': 'librato', 'service': 'app'})

# tags will be {'city': 'sf'}
api.submit('temperature', 80, tags={'city': 'sf'})

# tags will be {'city': 'sf', 'company': 'librato', 'service': 'app'}
api.submit('temperature', 80, tags={'city': 'sf'}, inherit_tags=True)

q = api.new_queue(tags={'service':'api'})

# tags will be {'location': 'downstairs'}
q.add('temperature', 22.1, tags={'location': 'downstairs'})

# tags will be {'company': 'librato', 'service':'api'}
q.add('temperature', 23.1)

# tags will be {'location': 'downstairs', 'company': 'librato', 'service': 'api'}
q.add('temperature', 22.1, tags={'location': 'downstairs'}, inherit_tags=True)
q.submit()
```

## Updating Metric Attributes

You can update the information for a metric by using the `update` method,
Expand Down
27 changes: 14 additions & 13 deletions librato/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,19 +284,26 @@ def submit(self, name, value, type="gauge", **query_props):

def submit_tagged(self, name, value, **query_props):
payload = {'measurements': []}
payload['measurements'].append(self.create_tagged_payload(name, value, **query_props))
self._mexe("measurements", method="POST", query_props=payload)

if self.tags:
payload['tags'] = self.tags

def create_tagged_payload(self, name, value, **query_props):
"""Create the measurement for forwarding to Librato"""
measurement = {
'name': self.sanitize(name),
'value': value
}
if 'tags' in query_props:
inherit_tags = query_props.pop('inherit_tags', False)
if inherit_tags:
tags = query_props.pop('tags', {})
measurement['tags'] = dict(self.get_tags(), **tags)
elif self.tags:
measurement['tags'] = self.tags

for k, v in query_props.items():
measurement[k] = v

payload['measurements'].append(measurement)
self._mexe("measurements", method="POST", query_props=payload)
return measurement

def get(self, name, **query_props):
resp = self._mexe("metrics/%s" % self.sanitize(name), method="GET", query_props=query_props)
Expand Down Expand Up @@ -561,13 +568,7 @@ def delete_chart(self, chart_id, space_id, **query_props):
# Queue
#
def new_queue(self, **kwargs):
tags = self.tags
if 'tags' in kwargs:
# Supplied tag set takes precedence
tags.update(kwargs.pop('tags'))

q = Queue(self, tags=tags, **kwargs)
return q
return Queue(self, **kwargs)

#
# misc
Expand Down
21 changes: 11 additions & 10 deletions librato/queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,8 @@ def add_tags(self, d):
self.tags.update(d)

def add(self, name, value, type='gauge', **query_props):
if len(self.tags) > 0:
query_props['tags'] = self.tags

if 'tags' in query_props:
"""add measurements to the Q"""
if 'tags' in query_props or len(self.tags) > 0:
self.add_tagged(name, value, **query_props)
else:
nm = {} # new measurement
Expand All @@ -85,6 +83,13 @@ def add_tagged(self, name, value, **query_props):
nm['sum'] = value
nm['count'] = 1

# must remove the inherit_tags key for compliance with json
inherit_tags = query_props.pop('inherit_tags', False)
tags = query_props.get('tags', {})
if inherit_tags or tags == {}:
inheritted_tags = dict(self.connection.get_tags(), **self.get_tags())
query_props['tags'] = dict(inheritted_tags, **tags)

for pn, v in query_props.items():
nm[pn] = v

Expand Down Expand Up @@ -134,12 +139,8 @@ def submit(self):
self.connection._mexe("metrics", method="POST", query_props=c)
self.chunks = []

for c in self.tagged_chunks:
if 'tags' in c:
c['tags'] = dict(self.tags).update(c['tags'])
elif self.tags:
c['tags'] = dict(self.tags)
self.connection._mexe("measurements", method="POST", query_props=c)
for chunk in self.tagged_chunks:
self.connection._mexe("measurements", method="POST", query_props=chunk)
self.tagged_chunks = []

def __enter__(self):
Expand Down
16 changes: 15 additions & 1 deletion tests/test_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,20 @@ def test_add_in_gauge(self):
assert len(gauge.measurements[src]) == 2
assert gauge.measurements[src][-1]['value'] == 1

def test_md_inherit_tags(self):
self.conn.set_tags({'company': 'Librato', 'hi': 'four'})

measurement = self.conn.create_tagged_payload('user_cpu', 20.2, tags={'hi': 'five'}, inherit_tags=True)

assert measurement['tags'] == {'hi': 'five', 'company': 'Librato'}

def test_md_donot_inherit_tags(self):
self.conn.set_tags({'company': 'Librato', 'hi': 'four'})

measurement = self.conn.create_tagged_payload('user_cpu', 20.2, tags={'hi': 'five'})

assert measurement['tags'] == {'hi': 'five'}

def test_md_submit(self):
mt1 = int(time.time()) - 5

Expand All @@ -223,7 +237,7 @@ def test_merge_tags(self):

self.conn.set_tags({'company': 'Librato'})
tags = {'hostname': 'web-1'}
self.conn.submit_tagged('user_cpu', 20.2, time=mt1, tags=tags)
self.conn.submit_tagged('user_cpu', 20.2, time=mt1, tags=tags, inherit_tags=True)

# Ensure 'company' and 'hostname' tags made it through
for tags_search in ["hostname=web-1", "company=Librato"]:
Expand Down
52 changes: 51 additions & 1 deletion tests/test_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,56 @@ def test_inherited_tags(self):
assert len(measurements) == 1
assert measurements[0]['value'] == 10

def test_inherit_connection_level_tags(self):
"""test if top level tags are ignored when passing measurement level tags"""
conn = librato.connect('user_test', 'key_test', tags={'sky': 'blue'})

q = conn.new_queue()
q.add_tagged('user_cpu', 10, tags={"hi": "five"}, inherit_tags=True)

measurements = q.tagged_chunks[0]['measurements']

assert len(measurements) == 1
assert measurements[0].get('tags', {}) == {'sky': 'blue', 'hi': 'five'}

def test_ignore_connection_queue_level_tags(self):
"""test if queue level tags are ignored when passing measurement level tags"""
conn = librato.connect('user_test', 'key_test', tags={'sky': 'blue'})

q = conn.new_queue(tags={"service": "api"})
q.add_tagged('user_cpu', 10, tags={"hi": "five"})
measurements = q.tagged_chunks[0]['measurements']

assert len(measurements) == 1
assert measurements[0].get('tags', {}) == {'hi': 'five'}

q.submit()

resp = self.conn.get_tagged('user_cpu', duration=60, tags_search="sky=blue")
assert len(resp['series']) == 0

def test_inherit_queue_connection_level_tags(self):
"""test if queue level tags are ignored when passing measurement level tags"""
conn = librato.connect('user_test', 'key_test', tags={'sky': 'blue', 'company': 'Librato'})

q = conn.new_queue(tags={"service": "api", "hi": "four", "sky": "red"})
q.add_tagged('user_cpu', 100, tags={"hi": "five"}, inherit_tags=True)
measurements = q.tagged_chunks[0]['measurements']

assert len(measurements) == 1
assert measurements[0].get('tags', {}) == {'sky': 'red', 'service': 'api', 'hi': 'five', 'company': 'Librato'}

def test_inherit_queue_level_tags(self):
"""test if queue level tags are ignored when passing measurement level tags"""
conn = librato.connect('user_test', 'key_test')

q = conn.new_queue(tags={"service": "api", "hi": "four"})
q.add_tagged('user_cpu', 100, tags={"hi": "five"}, inherit_tags=True)
measurements = q.tagged_chunks[0]['measurements']

assert len(measurements) == 1
assert measurements[0].get('tags', {}) == {'service': 'api', 'hi': 'five'}

def test_constructor_tags(self):
conn = librato.connect('user_test', 'key_test', tags={'sky': 'blue'})
q = conn.new_queue(tags={'sky': 'red', 'coal': 'black'})
Expand Down Expand Up @@ -243,7 +293,7 @@ def test_md_measurement_level_tag(self):
q.set_tags({'hostname': 'web-1'})

mt1 = int(time.time()) - 5
q.add_tagged('system_cpu', 33.22, time=mt1, tags={"user": "james"})
q.add_tagged('system_cpu', 33.22, time=mt1, tags={"user": "james"}, inherit_tags=True)
q.submit()

# Ensure both tags get submitted
Expand Down

0 comments on commit bda57b2

Please sign in to comment.