document as well as refactor so that CacheMetric is not nested

anoa/temp_working_cache_config
Amber H. Brown 2020-01-22 00:00:10 +11:00
parent a96b5d9ca7
commit 2f4dbfa3e1
1 changed files with 64 additions and 53 deletions

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright 2015, 2016 OpenMarket Ltd # Copyright 2015, 2016 OpenMarket Ltd
# Copyright 2019 The Matrix.org Foundation C.I.C. # Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -15,11 +15,12 @@
# limitations under the License. # limitations under the License.
import logging import logging
from typing import Dict from typing import Callable, Dict, Optional
import six import six
from six.moves import intern from six.moves import intern
import attr
from prometheus_client.core import Gauge from prometheus_client.core import Gauge
from synapse.config.cache import add_resizable_cache from synapse.config.cache import add_resizable_cache
@ -43,22 +44,71 @@ response_cache_evicted = Gauge(
response_cache_total = Gauge("synapse_util_caches_response_cache:total", "", ["name"]) response_cache_total = Gauge("synapse_util_caches_response_cache:total", "", ["name"])
@attr.s
class CacheMetric(object):
_cache = attr.ib()
_cache_type = attr.ib(type=str)
_cache_name = attr.ib(type=str)
_collect_callback = attr.ib(type=Optional[Callable])
hits = attr.ib(default=0)
misses = attr.ib(default=0)
evicted_size = attr.ib(default=0)
def inc_hits(self):
self.hits += 1
def inc_misses(self):
self.misses += 1
def inc_evictions(self, size=1):
self.evicted_size += size
def describe(self):
return []
def collect(self):
try:
if self._cache_type == "response_cache":
response_cache_size.labels(self._cache_name).set(len(self._cache))
response_cache_hits.labels(self._cache_name).set(self.hits)
response_cache_evicted.labels(self._cache_name).set(self.evicted_size)
response_cache_total.labels(self._cache_name).set(
self.hits + self.misses
)
else:
cache_size.labels(self._cache_name).set(len(self._cache))
cache_hits.labels(self._cache_name).set(self.hits)
cache_evicted.labels(self._cache_name).set(self.evicted_size)
cache_total.labels(self._cache_name).set(self.hits + self.misses)
if getattr(self._cache, "max_size", None):
cache_max_size.labels(self._cache_name).set(self._cache.max_size)
if self._collect_callback:
self._collect_callback()
except Exception as e:
logger.warning("Error calculating metrics for %s: %s", self._cache_name, e)
raise
def register_cache( def register_cache(
cache_type, cache_type: str,
cache_name, cache_name: str,
cache, cache,
collect_callback=None, collect_callback: Optional[Callable] = None,
resizable=True, resizable: bool = True,
resize_callback=None, resize_callback: Optional[Callable] = None,
): ) -> CacheMetric:
"""Register a cache object for metric collection and resizing. """Register a cache object for metric collection and resizing.
Args: Args:
cache_type (str): cache_type
cache_name (str): name of the cache cache_name: name of the cache
cache (object): cache itself cache: cache itself
collect_callback (callable|None): if not None, a function which is called during collect_callback: If given, a function which is called during metric
metric collection to update additional metrics. collection to update additional metrics.
resizable: Whether this cache supports being resized.
resize_callback: A function which can be called to resize the cache.
Returns: Returns:
CacheMetric: an object which provides inc_{hits,misses,evictions} methods CacheMetric: an object which provides inc_{hits,misses,evictions} methods
@ -71,47 +121,8 @@ def register_cache(
# Check if the metric is already registered. Unregister it, if so. # Check if the metric is already registered. Unregister it, if so.
# This usually happens during tests, as at runtime these caches are # This usually happens during tests, as at runtime these caches are
# effectively singletons. # effectively singletons.
metric = CacheMetric(cache, cache_type, cache_name, collect_callback)
metric_name = "cache_%s_%s" % (cache_type, cache_name) metric_name = "cache_%s_%s" % (cache_type, cache_name)
class CacheMetric(object):
hits = 0
misses = 0
evicted_size = 0
def inc_hits(self):
self.hits += 1
def inc_misses(self):
self.misses += 1
def inc_evictions(self, size=1):
self.evicted_size += size
def describe(self):
return []
def collect(self):
try:
if cache_type == "response_cache":
response_cache_size.labels(cache_name).set(len(cache))
response_cache_hits.labels(cache_name).set(self.hits)
response_cache_evicted.labels(cache_name).set(self.evicted_size)
response_cache_total.labels(cache_name).set(self.hits + self.misses)
else:
cache_size.labels(cache_name).set(len(cache))
cache_hits.labels(cache_name).set(self.hits)
cache_evicted.labels(cache_name).set(self.evicted_size)
cache_total.labels(cache_name).set(self.hits + self.misses)
if getattr(cache, "max_size", None):
cache_max_size.labels(cache_name).set(cache.max_size)
if collect_callback:
collect_callback()
except Exception as e:
logger.warning("Error calculating metrics for %s: %s", cache_name, e)
raise
metric = CacheMetric()
caches_by_name[cache_name] = cache caches_by_name[cache_name] = cache
collectors_by_name[metric_name] = metric collectors_by_name[metric_name] = metric
return metric return metric