Implement counters in StatsdMixin.

This commit is contained in:
Dave Shawley 2016-01-19 10:43:02 -05:00
parent 8b0085effc
commit 6c903f4f40
4 changed files with 69 additions and 8 deletions

View file

@ -10,10 +10,16 @@ implements the same interface:
Key in ``self.application.settings`` that contains this particular
mix-in's configuration data.
.. method:: record_timing(path, milliseconds)
.. method:: record_timing(milliseconds, *path)
:noindex:
:param str path: timing path to record
:param float milliseconds: number of milliseconds to record
:param path: timing path to record
.. method:: increase_counter(*path, amount=1)
:param path: counter path to increment
:keyword int amount: value to increase the counter by
Statsd Implementation

View file

@ -20,6 +20,12 @@ class SimpleHandler(metrics.StatsdMixin, web.RequestHandler):
self.set_status(204)
self.finish()
def post(self):
"""Example of increasing a counter."""
self.increase_counter('request', 'path')
self.set_status(204)
def _sig_handler(*args_):
iol = ioloop.IOLoop.instance()
iol.add_callback_from_signal(iol.stop)

View file

@ -57,12 +57,24 @@ class StatsdMixin(object):
more than replacing periods with dashes.
"""
settings = self.settings[self.SETTINGS_KEY]
normalized = '.'.join(str(p).replace('.', '-') for p in path)
msg = '{0}.{1}:{2}|ms'.format(settings['namespace'], normalized,
milliseconds)
settings['socket'].sendto(msg.encode('ascii'),
(settings['host'], int(settings['port'])))
self._send(self._build_path(path), milliseconds, 'ms')
def increase_counter(self, *path, **kwargs):
"""
Increase a counter.
:param path: elements of the metric path to incr
:keyword int amount: amount to increase the counter by. If
omitted, the counter is increased by one.
This method increases a counter within the application's
namespace. Each element of `path` is converted to a string
and normalized before joining the elements by periods. The
normalization process is little more than replacing periods
with dashes.
"""
self._send(self._build_path(path), kwargs.get('amount', '1'), 'c')
def on_finish(self):
"""
@ -80,3 +92,15 @@ class StatsdMixin(object):
self.record_timing(self.request.request_time() * 1000,
self.__class__.__name__, self.request.method,
self.__status_code)
def _build_path(self, path):
"""Return a normalized path."""
return '{}.{}'.format(self.settings[self.SETTINGS_KEY]['namespace'],
'.'.join(str(p).replace('.', '-') for p in path))
def _send(self, path, value, stat_type):
"""Send a metric to Statsd."""
settings = self.settings[self.SETTINGS_KEY]
msg = '{0}:{1}|{2}'.format(path, value, stat_type)
settings['socket'].sendto(msg.encode('ascii'),
(settings['host'], int(settings['port'])))

View file

@ -7,11 +7,20 @@ from sprockets.mixins.metrics.testing import FakeStatsdServer
import examples.statsd
class CounterBumper(metrics.StatsdMixin, web.RequestHandler):
def post(self, counter, amount):
path = counter.split('.')
self.increase_counter(*path, amount=int(amount))
self.set_status(204)
class StatsdMethodTimingTests(testing.AsyncHTTPTestCase):
def get_app(self):
self.application = web.Application([
web.url('/', examples.statsd.SimpleHandler),
web.url('/counters/(\w*)/(\d*)', CounterBumper),
])
return self.application
@ -54,3 +63,19 @@ class StatsdMethodTimingTests(testing.AsyncHTTPTestCase):
self.assertEqual(
self.settings['namespace'],
'applications.' + examples.statsd.SimpleHandler.__module__)
def test_that_counter_increment_defaults_to_one(self):
response = self.fetch('/', method='POST', body='')
self.assertEqual(response.code, 204)
prefix = 'testing.request.path'
for path, value, stat_type in self.statsd.find_metrics(prefix, 'c'):
self.assertEqual(int(value), 1)
def test_that_counter_accepts_increment_value(self):
response = self.fetch('/counters/path/5', method='POST', body='')
self.assertEqual(response.code, 204)
prefix = 'testing.path'
for path, value, stat_type in self.statsd.find_metrics(prefix, 'c'):
self.assertEqual(int(value), 5)