Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit cf11919

Browse files
authored
Fix cache metrics not being updated when not using the legacy exposition module. (#13717)
1 parent 526f84b commit cf11919

File tree

4 files changed

+81
-21
lines changed

4 files changed

+81
-21
lines changed

changelog.d/13717.misc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add experimental configuration option to allow disabling legacy Prometheus metric names.

synapse/metrics/_legacy_exposition.py

-7
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@
3434
from twisted.web.resource import Resource
3535
from twisted.web.server import Request
3636

37-
from synapse.util import caches
38-
3937
CONTENT_TYPE_LATEST = "text/plain; version=0.0.4; charset=utf-8"
4038

4139

@@ -107,11 +105,6 @@ def generate_latest(registry: CollectorRegistry, emit_help: bool = False) -> byt
107105
by prometheus-client.
108106
"""
109107

110-
# Trigger the cache metrics to be rescraped, which updates the common
111-
# metrics but do not produce metrics themselves
112-
for collector in caches.collectors_by_name.values():
113-
collector.collect()
114-
115108
output = []
116109

117110
for metric in registry.collect():

synapse/util/caches/__init__.py

+48-12
Original file line numberDiff line numberDiff line change
@@ -20,37 +20,74 @@
2020
from typing import Any, Callable, Dict, List, Optional, Sized, TypeVar
2121

2222
import attr
23+
from prometheus_client import REGISTRY
2324
from prometheus_client.core import Gauge
2425

2526
from synapse.config.cache import add_resizable_cache
27+
from synapse.util.metrics import DynamicCollectorRegistry
2628

2729
logger = logging.getLogger(__name__)
2830

2931

3032
# Whether to track estimated memory usage of the LruCaches.
3133
TRACK_MEMORY_USAGE = False
3234

35+
# We track cache metrics in a special registry that lets us update the metrics
36+
# just before they are returned from the scrape endpoint.
37+
CACHE_METRIC_REGISTRY = DynamicCollectorRegistry()
3338

3439
caches_by_name: Dict[str, Sized] = {}
35-
collectors_by_name: Dict[str, "CacheMetric"] = {}
3640

37-
cache_size = Gauge("synapse_util_caches_cache_size", "", ["name"])
38-
cache_hits = Gauge("synapse_util_caches_cache_hits", "", ["name"])
39-
cache_evicted = Gauge("synapse_util_caches_cache_evicted_size", "", ["name", "reason"])
40-
cache_total = Gauge("synapse_util_caches_cache", "", ["name"])
41-
cache_max_size = Gauge("synapse_util_caches_cache_max_size", "", ["name"])
41+
cache_size = Gauge(
42+
"synapse_util_caches_cache_size", "", ["name"], registry=CACHE_METRIC_REGISTRY
43+
)
44+
cache_hits = Gauge(
45+
"synapse_util_caches_cache_hits", "", ["name"], registry=CACHE_METRIC_REGISTRY
46+
)
47+
cache_evicted = Gauge(
48+
"synapse_util_caches_cache_evicted_size",
49+
"",
50+
["name", "reason"],
51+
registry=CACHE_METRIC_REGISTRY,
52+
)
53+
cache_total = Gauge(
54+
"synapse_util_caches_cache", "", ["name"], registry=CACHE_METRIC_REGISTRY
55+
)
56+
cache_max_size = Gauge(
57+
"synapse_util_caches_cache_max_size", "", ["name"], registry=CACHE_METRIC_REGISTRY
58+
)
4259
cache_memory_usage = Gauge(
4360
"synapse_util_caches_cache_size_bytes",
4461
"Estimated memory usage of the caches",
4562
["name"],
63+
registry=CACHE_METRIC_REGISTRY,
4664
)
4765

48-
response_cache_size = Gauge("synapse_util_caches_response_cache_size", "", ["name"])
49-
response_cache_hits = Gauge("synapse_util_caches_response_cache_hits", "", ["name"])
66+
response_cache_size = Gauge(
67+
"synapse_util_caches_response_cache_size",
68+
"",
69+
["name"],
70+
registry=CACHE_METRIC_REGISTRY,
71+
)
72+
response_cache_hits = Gauge(
73+
"synapse_util_caches_response_cache_hits",
74+
"",
75+
["name"],
76+
registry=CACHE_METRIC_REGISTRY,
77+
)
5078
response_cache_evicted = Gauge(
51-
"synapse_util_caches_response_cache_evicted_size", "", ["name", "reason"]
79+
"synapse_util_caches_response_cache_evicted_size",
80+
"",
81+
["name", "reason"],
82+
registry=CACHE_METRIC_REGISTRY,
5283
)
53-
response_cache_total = Gauge("synapse_util_caches_response_cache", "", ["name"])
84+
response_cache_total = Gauge(
85+
"synapse_util_caches_response_cache", "", ["name"], registry=CACHE_METRIC_REGISTRY
86+
)
87+
88+
89+
# Register our custom cache metrics registry with the global registry
90+
REGISTRY.register(CACHE_METRIC_REGISTRY)
5491

5592

5693
class EvictionReason(Enum):
@@ -168,9 +205,8 @@ def register_cache(
168205
add_resizable_cache(cache_name, resize_callback)
169206

170207
metric = CacheMetric(cache, cache_type, cache_name, collect_callback)
171-
metric_name = "cache_%s_%s" % (cache_type, cache_name)
172208
caches_by_name[cache_name] = cache
173-
collectors_by_name[metric_name] = metric
209+
CACHE_METRIC_REGISTRY.register_hook(metric.collect)
174210
return metric
175211

176212

synapse/util/metrics.py

+32-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
import logging
1616
from functools import wraps
1717
from types import TracebackType
18-
from typing import Awaitable, Callable, Optional, Type, TypeVar
18+
from typing import Awaitable, Callable, Generator, List, Optional, Type, TypeVar
1919

20-
from prometheus_client import Counter
20+
from prometheus_client import CollectorRegistry, Counter, Metric
2121
from typing_extensions import Concatenate, ParamSpec, Protocol
2222

2323
from synapse.logging.context import (
@@ -208,3 +208,33 @@ def _update_in_flight(self, metrics: _InFlightMetric) -> None:
208208
metrics.real_time_sum += duration
209209

210210
# TODO: Add other in flight metrics.
211+
212+
213+
class DynamicCollectorRegistry(CollectorRegistry):
214+
"""
215+
Custom Prometheus Collector registry that calls a hook first, allowing you
216+
to update metrics on-demand.
217+
218+
Don't forget to register this registry with the main registry!
219+
"""
220+
221+
def __init__(self) -> None:
222+
super().__init__()
223+
self._pre_update_hooks: List[Callable[[], None]] = []
224+
225+
def collect(self) -> Generator[Metric, None, None]:
226+
"""
227+
Collects metrics, calling pre-update hooks first.
228+
"""
229+
230+
for pre_update_hook in self._pre_update_hooks:
231+
pre_update_hook()
232+
233+
yield from super().collect()
234+
235+
def register_hook(self, hook: Callable[[], None]) -> None:
236+
"""
237+
Registers a hook that is called before metric collection.
238+
"""
239+
240+
self._pre_update_hooks.append(hook)

0 commit comments

Comments
 (0)