Source code for tapes.reporting.statsd

from __future__ import absolute_import
import logging

import statsd

from . import ScheduledReporter, reporting_logger
from ..local.meter import Meter
from ..local.timer import Timer
from ..local.gauge import Gauge
from ..local.counter import Counter
from ..local.histogram import Histogram


[docs]class StatsdReporter(ScheduledReporter): """Reporter for StatsD.""" def __init__(self, interval, host='localhost', port=8125, prefix=None, registry=None): """ :param interval: a timedelta, how often metrics are reported :param host: the statsd host :param port: the statsd port :param prefix: the statsd prefix to use :param registry: the registry to report on, defaults to the global one """ super(StatsdReporter, self).__init__(interval, registry) self.statsd_client = statsd.StatsClient(host, port, prefix) def _report_meter(self, name, meter): stats = meter.get_values() self.statsd_client.gauge('{}.total'.format(name), stats['count']) self.statsd_client.timing('{}.m1_rate'.format(name), stats['m1']) self.statsd_client.timing('{}.m5_rate'.format(name), stats['m5']) self.statsd_client.timing('{}.m15_rate'.format(name), stats['m15']) def _report_timer(self, name, timer): stats = timer.get_values() self.statsd_client.gauge('{}.total'.format(name), stats['count']) self.statsd_client.timing('{}.m1_rate'.format(name), stats['m1']) self.statsd_client.timing('{}.m5_rate'.format(name), stats['m5']) self.statsd_client.timing('{}.m15_rate'.format(name), stats['m15']) # statsd wants millis, this is in seconds internally self.statsd_client.timing('{}.min'.format(name), stats['min'] * 1000) self.statsd_client.timing('{}.max'.format(name), stats['max'] * 1000) self.statsd_client.timing('{}.mean'.format(name), stats['mean'] * 1000) self.statsd_client.timing('{}.stddev'.format(name), stats['stddev'] * 1000) self.statsd_client.timing('{}.q50'.format(name), stats['q50'] * 1000) self.statsd_client.timing('{}.q75'.format(name), stats['q75'] * 1000) self.statsd_client.timing('{}.q98'.format(name), stats['q98'] * 1000) self.statsd_client.timing('{}.q99'.format(name), stats['q99'] * 1000) self.statsd_client.timing('{}.q999'.format(name), stats['q999'] * 1000) def _report_gauge(self, name, gauge): stats = gauge.get_values() self.statsd_client.gauge('{}.value'.format(name), stats['value']) def _report_counter(self, name, counter): stats = counter.get_values() self.statsd_client.incr('{}.value'.format(name), stats['value']) def _report_histogram(self, name, histogram): stats = histogram.get_values() self.statsd_client.gauge('{}.total'.format(name), stats['count']) self.statsd_client.timing('{}.min'.format(name), stats['min']) self.statsd_client.timing('{}.max'.format(name), stats['max']) self.statsd_client.timing('{}.mean'.format(name), stats['mean']) self.statsd_client.timing('{}.stddev'.format(name), stats['stddev']) self.statsd_client.timing('{}.q50'.format(name), stats['q50']) self.statsd_client.timing('{}.q75'.format(name), stats['q75']) self.statsd_client.timing('{}.q98'.format(name), stats['q98']) self.statsd_client.timing('{}.q99'.format(name), stats['q99']) self.statsd_client.timing('{}.q999'.format(name), stats['q999']) def _talk_this_way(self, name, thing): if isinstance(thing, Meter): self._report_meter(name, thing) elif isinstance(thing, Timer): self._report_timer(name, thing) elif isinstance(thing, Gauge): self._report_gauge(name, thing) elif isinstance(thing, Counter): self._report_counter(name, thing) elif isinstance(thing, Histogram): self._report_histogram(name, thing) else: raise ValueError('No clue what a {} is'.format(type(thing))) def _walk_this_way(self, stats, curr_name=''): try: for k, v in stats.items(): self._walk_this_way(v, '{}.{}'.format(curr_name, k) if curr_name else k) except AttributeError: self._talk_this_way(curr_name, stats) def report(self): if reporting_logger.isEnabledFor(logging.DEBUG): reporting_logger.debug('Reporting to StatsD %s', self.registry.get_stats()) self._walk_this_way(self.registry.stats, '')