Create the concept of a cachecounter metric; generating two counters specific to caches

This commit is contained in:
Paul "LeoNerd" Evans 2015-03-04 15:47:23 +00:00
parent 7d72e44eb9
commit ce8b5769f7
3 changed files with 73 additions and 8 deletions

View file

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from .metric import CounterMetric
from .metric import CounterMetric, CacheCounterMetric
# We'll keep all the available metrics in a single toplevel dict, one shared
@ -43,6 +43,15 @@ class Metrics(object):
return metric
def register_cachecounter(self, name, *args, **kwargs):
full_name = "%s.%s" % (self.name_prefix, name)
metric = CacheCounterMetric(full_name, *args, **kwargs)
self._register(metric)
return metric
def counted(self, func):
""" A method decorator that registers a counter, to count invocations
of this method. """

View file

@ -14,16 +14,28 @@
# limitations under the License.
class CounterMetric(object):
class BaseMetric(object):
def __init__(self, name, keys=[]):
self.name = name
self.keys = keys # OK not to clone as we never write it
def _render_key(self, values):
# TODO: some kind of value escape
return ",".join(["%s=%s" % kv for kv in zip(self.keys, values)])
class CounterMetric(BaseMetric):
"""The simplest kind of metric; one that stores a monotonically-increasing
integer that counts events."""
def __init__(self, *args, **kwargs):
super(CounterMetric, self).__init__(*args, **kwargs)
self.counts = {}
# Scalar metrics are never empty
if not len(keys):
if not len(self.keys):
self.counts[()] = 0
def inc(self, *values):
@ -42,13 +54,32 @@ class CounterMetric(object):
def fetch(self):
return dict(self.counts)
def _render_key(self, values):
# TODO: some kind of value escape
return ",".join(["%s=%s" % kv for kv in zip(self.keys, values)])
def render(self):
if not len(self.keys):
return ["%s %d" % (self.name, self.counts[()])]
return ["%s{%s} %d" % (self.name, self._render_key(k), self.counts[k])
for k in sorted(self.counts.keys())]
class CacheCounterMetric(object):
"""A combination of two CounterMetrics, one to count cache hits and one to
count misses.
This metric generates standard metric name pairs, so that monitoring rules
can easily be applied to measure hit ratio."""
def __init__(self, name, keys=[]):
self.name = name
self.hits = CounterMetric(name + ":hits", keys=keys)
self.misses = CounterMetric(name + ":misses", keys=keys)
def inc_hits(self, *values):
self.hits.inc(*values)
def inc_misses(self, *values):
self.misses.inc(*values)
def render(self):
return self.hits.render() + self.misses.render()

View file

@ -15,7 +15,7 @@
from tests import unittest
from synapse.metrics.metric import CounterMetric
from synapse.metrics.metric import CounterMetric, CacheCounterMetric
class CounterMetricTestCase(unittest.TestCase):
@ -59,3 +59,28 @@ class CounterMetricTestCase(unittest.TestCase):
"vector{method=GET} 2",
"vector{method=PUT} 1",
])
class CacheCounterMetricTestCase(unittest.TestCase):
def test_cachecounter(self):
counter = CacheCounterMetric("cache")
self.assertEquals(counter.render(), [
"cache:hits 0",
"cache:misses 0",
])
counter.inc_misses()
self.assertEquals(counter.render(), [
"cache:hits 0",
"cache:misses 1",
])
counter.inc_hits()
self.assertEquals(counter.render(), [
"cache:hits 1",
"cache:misses 1",
])