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

Commit

Permalink
Add a timed context manager to statsd.
Browse files Browse the repository at this point in the history
This enables a context manager in statsd so you can easily time
a set of code without saving the start time, etc. manually:

```python
with statsd.timed_context('user.query.time', sample_rate=0.5):
    # Do what you need to ...
    pass

start = time.time()
try:
    get_user(user_id)
finally:
    statsd.timing('user.query.time', time.time() - start)
```

Two tests are also added for this code.

Fixes DataDog#25
  • Loading branch information
clokep committed Jun 30, 2015
1 parent 416c101 commit 7be05b6
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 1 deletion.
40 changes: 39 additions & 1 deletion datadog/dogstatsd/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def timing(self, metric, value, tags=None, sample_rate=1):
def timed(self, metric, tags=None, sample_rate=1):
"""
A decorator that will measure the distribution of a function's run
time. Optionally specify a list of tag or a sample rate.
time. Optionally specify a list of tags or a sample rate.
::
@statsd.timed('user.query.time', sample_rate=0.5)
Expand All @@ -156,6 +156,44 @@ def wrapped(*args, **kwargs):
return wrapped
return wrapper

class _TimedContextManager(object):
def __init__(self, statsd, metric, tags=None, sample_rate=1):
"""
Create a context manager which will report the time elapsed by its
context.
"""
self.statsd = statsd
self.metric = metric
self.tags = tags
self.sample_rate = sample_rate

def __enter__(self):
self.start = time()

def __exit__(self, type, value, traceback):
# Report the elapsed time of the context manager.
self.statsd.timing(self.metric, time() - self.start,
self.tags, self.sample_rate)

def timed_context(self, metric, tags=None, sample_rate=1):
"""
A context manager that will measure the distribution of a context's run
time. Optionally specify a list of tags or a sample rate.
::
with statsd.timed_context('user.query.time', sample_rate=0.5):
# Do what you need to ...
pass
# Is equivalent to ...
start = time.time()
try:
get_user(user_id)
finally:
statsd.timing('user.query.time', time.time() - start)
"""
return self._TimedContextManager(self, metric, tags, sample_rate)

def set(self, metric, value, tags=None, sample_rate=1):
"""
Sample a set value.
Expand Down
34 changes: 34 additions & 0 deletions tests/unit/dogstatsd/test_statsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,40 @@ def func(a, b, c=1, d=1):
t.assert_equal('timed.test', name)
self.assert_almost_equal(0.5, float(value), 0.1)

def test_timed_context(self):
with self.statsd.timed_context('timed_context.test'):
time.sleep(0.5)

packet = self.recv()
name_value, type_ = packet.split('|')
name, value = name_value.split(':')

t.assert_equal('ms', type_)
t.assert_equal('timed_context.test', name)
self.assert_almost_equal(0.5, float(value), 0.1)

def test_timed_context_exception(self):
"""Test that an exception bubbles out of the context manager."""
class ContextException(Exception):
pass

def func(self):
with self.statsd.timed_context('timed_context.test.exception'):
time.sleep(0.5)
raise ContextException()

# Ensure the exception was raised.
t.assert_raises(ContextException, func, self)

# Ensure the timing was recorded.
packet = self.recv()
name_value, type_ = packet.split('|')
name, value = name_value.split(':')

t.assert_equal('ms', type_)
t.assert_equal('timed_context.test.exception', name)
self.assert_almost_equal(0.5, float(value), 0.1)

def test_batched(self):
self.statsd.open_buffer()
self.statsd.gauge('page.views', 123)
Expand Down

0 comments on commit 7be05b6

Please sign in to comment.