Skip to content

Commit

Permalink
Merge pull request #90 from jofusa/jdennison/add-constant-tags-to-thr…
Browse files Browse the repository at this point in the history
…ead-statsd

[statsd][threadstats] `constant_tags` support
  • Loading branch information
yannmh committed Oct 19, 2015
2 parents 27e1e54 + c1a2432 commit f41c264
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 3 deletions.
8 changes: 8 additions & 0 deletions datadog/dogstatsd/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,14 @@ def event(self, title, text, alert_type=None, aggregation_key=None,
"""
title = self._escape_event_content(title)
text = self._escape_event_content(text)

# Append all client level tags to every event
if self.constant_tags:
if tags:
tags += self.constant_tags
else:
tags = self.constant_tags

string = u'_e{%d,%d}:%s|%s' % (len(title), len(text), title, text)
if date_happened:
string = '%s|d:%d' % (string, date_happened)
Expand Down
24 changes: 22 additions & 2 deletions datadog/threadstats/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,16 @@

class ThreadStats(object):

def __init__(self):
""" Initialize a dogstats object. """
def __init__(self, constant_tags=None):
"""
Initialize a dogstats object.
:param constant_tags: Tags to attach to every metric reported by this client
:type constant_tags: list of strings
"""
# Don't collect until start is called.
self._disabled = True
self.constant_tags = constant_tags

def start(self, flush_interval=10, roll_up_interval=10, device=None,
flush_in_thread=True, flush_in_greenlet=False, disabled=False):
Expand Down Expand Up @@ -116,6 +122,13 @@ def event(self, title, text, alert_type=None, aggregation_key=None,
'The web server is up again', alert_type='success')
"""
if not self._disabled:
# Append all client level tags to every event
if self.constant_tags:
if tags:
tags += self.constant_tags
else:
tags = self.constant_tags

self._event_aggregator.add_event(
title=title, text=text, alert_type=alert_type, aggregation_key=aggregation_key,
source_type_name=source_type_name, date_happened=date_happened, priority=priority,
Expand Down Expand Up @@ -292,6 +305,13 @@ def _get_aggregate_metrics(self, flush_time=None):
# FIXME: emit a dictionary from the aggregator
metrics = []
for timestamp, value, name, tags, host in rolled_up_metrics:
# Append all client level tags to every metric
if self.constant_tags:
if tags:
tags += self.constant_tags
else:
tags = self.constant_tags

metric = {
'metric': name,
'points': [[timestamp, value]],
Expand Down
9 changes: 9 additions & 0 deletions tests/unit/dogstatsd/test_statsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ def test_event(self):
aggregation_key='key', tags=['t1', 't2:v2'])
t.assert_equal(u'_e{5,19}:Title|♬ †øU †øU ¥ºu T0µ ♪|k:key|#t1,t2:v2', self.recv())

def test_event_constant_tags(self):
self.statsd.constant_tags = ['bar:baz', 'foo']
self.statsd.event('Title', u'L1\nL2', priority='low', date_happened=1375296969)
t.assert_equal(u'_e{5,6}:Title|L1\\nL2|d:1375296969|p:low|#bar:baz,foo', self.recv())

self.statsd.event('Title', u'♬ †øU †øU ¥ºu T0µ ♪',
aggregation_key='key', tags=['t1', 't2:v2'])
t.assert_equal(u'_e{5,19}:Title|♬ †øU †øU ¥ºu T0µ ♪|k:key|#t1,t2:v2,bar:baz,foo', self.recv())

def test_service_check(self):
now = int(time.time())
self.statsd.service_check(
Expand Down
82 changes: 81 additions & 1 deletion tests/unit/threadstats/test_threadstats.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,9 @@ def test_event(self):
reporter.events = []
event1_priority = "low"
event1_date_happened = 1375296969
event1_tag = "Event 2 tag"
dog.event(event1_title, event1_text, priority=event1_priority,
date_happened=event1_date_happened)
date_happened=event1_date_happened, tags=[event1_tag])

# Flush and test
dog.flush()
Expand All @@ -113,6 +114,49 @@ def test_event(self):
nt.assert_equal(event['text'], event1_text)
nt.assert_equal(event['priority'], event1_priority)
nt.assert_equal(event['date_happened'], event1_date_happened)
nt.assert_equal(event['tags'], [event1_tag])

def test_event_constant_tags(self):
constant_tag = 'type:constant'
dog = ThreadStats(constant_tags=[constant_tag])
dog.start(roll_up_interval=10, flush_in_thread=False)
reporter = dog.reporter = MemoryReporter()

# Add two events
event1_title = "Event 1 title"
event2_title = "Event 1 title"
event1_text = "Event 1 text"
event2_text = "Event 2 text"
dog.event(event1_title, event1_text)
dog.event(event2_title, event2_text)

# Flush and test
dog.flush()
event1, event2 = reporter.events
nt.assert_equal(event1['title'], event1_title)
nt.assert_equal(event1['text'], event1_text)
nt.assert_equal(event1['tags'], [constant_tag])
nt.assert_equal(event2['title'], event2_title)
nt.assert_equal(event2['text'], event2_text)
nt.assert_equal(event2['text'], event2_text)
nt.assert_equal(event2['tags'], [constant_tag])

# Test more parameters
reporter.events = []
event1_priority = "low"
event1_date_happened = 1375296969
event1_tag = "Event 2 tag"
dog.event(event1_title, event1_text, priority=event1_priority,
date_happened=event1_date_happened, tags=[event1_tag])

# Flush and test
dog.flush()
event, = reporter.events
nt.assert_equal(event['title'], event1_title)
nt.assert_equal(event['text'], event1_text)
nt.assert_equal(event['priority'], event1_priority)
nt.assert_equal(event['date_happened'], event1_date_happened)
nt.assert_equal(event['tags'], [event1_tag, constant_tag])

def test_histogram(self):
dog = ThreadStats()
Expand Down Expand Up @@ -345,6 +389,42 @@ def test_tags(self):
nt.assert_equal(g3['tags'], ['env:staging'])
nt.assert_equal(g3['points'][0][1], 20)

def test_constant_tags(self):
dog = ThreadStats(constant_tags=['type:constant'])
dog.start(roll_up_interval=10, flush_in_thread=False)
reporter = dog.reporter = MemoryReporter()

# Post the same metric with different tags.
dog.gauge('gauge', 10, timestamp=100.0)
dog.gauge('gauge', 15, timestamp=100.0, tags=['env:production', 'db'])
dog.gauge('gauge', 20, timestamp=100.0, tags=['env:staging'])

dog.increment('counter', timestamp=100.0)
dog.increment('counter', timestamp=100.0, tags=['env:production', 'db'])
dog.increment('counter', timestamp=100.0, tags=['env:staging'])

dog.flush(200.0)

metrics = self.sort_metrics(reporter.metrics)
nt.assert_equal(len(metrics), 6)

[c1, c2, c3, g1, g2, g3] = metrics
(nt.assert_equal(c['metric'], 'counter') for c in [c1, c2, c3])
nt.assert_equal(c1['tags'], ['env:production', 'db', 'type:constant'])
nt.assert_equal(c1['points'][0][1], 1)
nt.assert_equal(c2['tags'], ['env:staging', 'type:constant'])
nt.assert_equal(c2['points'][0][1], 1)
nt.assert_equal(c3['tags'], ['type:constant'])
nt.assert_equal(c3['points'][0][1], 1)

(nt.assert_equal(c['metric'], 'gauge') for c in [g1, g2, g3])
nt.assert_equal(g1['tags'], ['env:production', 'db', 'type:constant'])
nt.assert_equal(g1['points'][0][1], 15)
nt.assert_equal(g2['tags'], ['env:staging', 'type:constant'])
nt.assert_equal(g2['points'][0][1], 20)
nt.assert_equal(g3['tags'], ['type:constant'])
nt.assert_equal(g3['points'][0][1], 10)

# Ensure histograms work as well.
@dog.timed('timed', tags=['version:1'])
def test():
Expand Down

0 comments on commit f41c264

Please sign in to comment.