Rename TimerMetric to DistributionMetric; as it could count more than just time

This commit is contained in:
Paul "LeoNerd" Evans 2015-03-10 15:21:03 +00:00
parent 642f725fd7
commit f1fbe3e09f
4 changed files with 37 additions and 33 deletions

View File

@ -19,7 +19,9 @@ from __future__ import absolute_import
import logging import logging
from resource import getrusage, getpagesize, RUSAGE_SELF from resource import getrusage, getpagesize, RUSAGE_SELF
from .metric import CounterMetric, CallbackMetric, TimerMetric, CacheMetric from .metric import (
CounterMetric, CallbackMetric, DistributionMetric, CacheMetric
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -59,8 +61,8 @@ class Metrics(object):
def register_callback(self, *args, **kwargs): def register_callback(self, *args, **kwargs):
return self._register(CallbackMetric, *args, **kwargs) return self._register(CallbackMetric, *args, **kwargs)
def register_timer(self, *args, **kwargs): def register_distribution(self, *args, **kwargs):
return self._register(TimerMetric, *args, **kwargs) return self._register(DistributionMetric, *args, **kwargs)
def register_cache(self, *args, **kwargs): def register_cache(self, *args, **kwargs):
return self._register(CacheMetric, *args, **kwargs) return self._register(CacheMetric, *args, **kwargs)

View File

@ -101,35 +101,37 @@ class CallbackMetric(BaseMetric):
for k in sorted(value.keys())] for k in sorted(value.keys())]
class TimerMetric(CounterMetric): class DistributionMetric(CounterMetric):
"""A combination of an event counter and a time accumulator, which counts """A combination of an event counter and an accumulator, which counts
both the number of events and how long each one takes. both the number of events and accumulates the total value. Typically this
could be used to keep track of method-running times, or other distributions
of values that occur in discrete occurances.
TODO(paul): Try to export some heatmap-style stats? TODO(paul): Try to export some heatmap-style stats?
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(TimerMetric, self).__init__(*args, **kwargs) super(DistributionMetric, self).__init__(*args, **kwargs)
self.times = {} self.totals = {}
# Scalar metrics are never empty # Scalar metrics are never empty
if self.is_scalar(): if self.is_scalar():
self.times[()] = 0 self.totals[()] = 0
def inc_time(self, msec, *values): def inc_by(self, inc, *values):
self.inc(*values) self.inc(*values)
if values not in self.times: if values not in self.totals:
self.times[values] = msec self.totals[values] = inc
else: else:
self.times[values] += msec self.totals[values] += inc
def render_item(self, k): def render_item(self, k):
keystr = self._render_key(k) keystr = self._render_key(k)
return ["%s:count%s %d" % (self.name, keystr, self.counts[k]), return ["%s:count%s %d" % (self.name, keystr, self.counts[k]),
"%s:msec%s %d" % (self.name, keystr, self.times[k])] "%s:total%s %d" % (self.name, keystr, self.totals[k])]
class CacheMetric(object): class CacheMetric(object):

View File

@ -38,9 +38,9 @@ transaction_logger = logging.getLogger("synapse.storage.txn")
metrics = synapse.metrics.get_metrics_for("synapse.storage") metrics = synapse.metrics.get_metrics_for("synapse.storage")
sql_query_timer = metrics.register_timer("queries", labels=["verb"]) sql_query_timer = metrics.register_distribution("queries", labels=["verb"])
sql_txn_timer = metrics.register_timer("transactions", labels=["desc"]) sql_txn_timer = metrics.register_distribution("transactions", labels=["desc"])
sql_getevents_timer = metrics.register_timer("getEvents", labels=["desc"]) sql_getevents_timer = metrics.register_distribution("getEvents", labels=["desc"])
caches_by_name = {} caches_by_name = {}
cache_counter = metrics.register_cache( cache_counter = metrics.register_cache(
@ -143,7 +143,7 @@ class LoggingTransaction(object):
finally: finally:
msecs = (time.time() * 1000) - start msecs = (time.time() * 1000) - start
sql_logger.debug("[SQL time] {%s} %f", self.name, msecs) sql_logger.debug("[SQL time] {%s} %f", self.name, msecs)
sql_query_timer.inc_time(msecs, sql.split()[0]) sql_query_timer.inc_by(msecs, sql.split()[0])
class PerformanceCounters(object): class PerformanceCounters(object):
@ -268,7 +268,7 @@ class SQLBaseStore(object):
self._current_txn_total_time += end - start self._current_txn_total_time += end - start
self._txn_perf_counters.update(desc, start, end) self._txn_perf_counters.update(desc, start, end)
sql_txn_timer.inc_time(self._current_txn_total_time, desc) sql_txn_timer.inc_by(self._current_txn_total_time, desc)
with PreserveLoggingContext(): with PreserveLoggingContext():
result = yield self._db_pool.runInteraction( result = yield self._db_pool.runInteraction(
@ -672,7 +672,7 @@ class SQLBaseStore(object):
def update_counter(desc, last_time): def update_counter(desc, last_time):
curr_time = self._get_event_counters.update(desc, last_time) curr_time = self._get_event_counters.update(desc, last_time)
sql_getevents_timer.inc_time(curr_time - last_time, desc) sql_getevents_timer.inc_by(curr_time - last_time, desc)
return curr_time return curr_time
cache = self._get_event_cache.setdefault(event_id, {}) cache = self._get_event_cache.setdefault(event_id, {})
@ -727,7 +727,7 @@ class SQLBaseStore(object):
def update_counter(desc, last_time): def update_counter(desc, last_time):
curr_time = self._get_event_counters.update(desc, last_time) curr_time = self._get_event_counters.update(desc, last_time)
sql_getevents_timer.inc_time(curr_time - last_time, desc) sql_getevents_timer.inc_by(curr_time - last_time, desc)
return curr_time return curr_time
d = json.loads(js) d = json.loads(js)

View File

@ -16,7 +16,7 @@
from tests import unittest from tests import unittest
from synapse.metrics.metric import ( from synapse.metrics.metric import (
CounterMetric, CallbackMetric, TimerMetric, CacheMetric CounterMetric, CallbackMetric, DistributionMetric, CacheMetric
) )
@ -97,37 +97,37 @@ class CallbackMetricTestCase(unittest.TestCase):
]) ])
class TimerMetricTestCase(unittest.TestCase): class DistributionMetricTestCase(unittest.TestCase):
def test_scalar(self): def test_scalar(self):
metric = TimerMetric("thing") metric = DistributionMetric("thing")
self.assertEquals(metric.render(), [ self.assertEquals(metric.render(), [
'thing:count 0', 'thing:count 0',
'thing:msec 0', 'thing:total 0',
]) ])
metric.inc_time(500) metric.inc_by(500)
self.assertEquals(metric.render(), [ self.assertEquals(metric.render(), [
'thing:count 1', 'thing:count 1',
'thing:msec 500', 'thing:total 500',
]) ])
def test_vector(self): def test_vector(self):
metric = TimerMetric("queries", labels=["verb"]) metric = DistributionMetric("queries", labels=["verb"])
self.assertEquals(metric.render(), []) self.assertEquals(metric.render(), [])
metric.inc_time(300, "SELECT") metric.inc_by(300, "SELECT")
metric.inc_time(200, "SELECT") metric.inc_by(200, "SELECT")
metric.inc_time(800, "INSERT") metric.inc_by(800, "INSERT")
self.assertEquals(metric.render(), [ self.assertEquals(metric.render(), [
'queries:count{verb="INSERT"} 1', 'queries:count{verb="INSERT"} 1',
'queries:msec{verb="INSERT"} 800', 'queries:total{verb="INSERT"} 800',
'queries:count{verb="SELECT"} 2', 'queries:count{verb="SELECT"} 2',
'queries:msec{verb="SELECT"} 500', 'queries:total{verb="SELECT"} 500',
]) ])