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

pull/4/merge
Paul "LeoNerd" Evans 10 years ago
parent 7d72e44eb9
commit ce8b5769f7
  1. 11
      synapse/metrics/__init__.py
  2. 43
      synapse/metrics/metric.py
  3. 27
      tests/metrics/test_metric.py

@ -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. """

@ -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()

@ -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",
])

Loading…
Cancel
Save