diff --git a/synapse/metrics/__init__.py b/synapse/metrics/__init__.py
index 125845eb30..d5c30bbe41 100644
--- a/synapse/metrics/__init__.py
+++ b/synapse/metrics/__init__.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. """
diff --git a/synapse/metrics/metric.py b/synapse/metrics/metric.py
index f5a98763cc..00b149f6f6 100644
--- a/synapse/metrics/metric.py
+++ b/synapse/metrics/metric.py
@@ -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()
|