Skip to content

Commit

Permalink
Registry a no-op metrics service by default
Browse files Browse the repository at this point in the history
  • Loading branch information
leplatrem committed Oct 24, 2024
1 parent 276a285 commit 7e20482
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 14 deletions.
8 changes: 3 additions & 5 deletions kinto/core/initialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,9 @@ def on_new_response(event):
def setup_metrics(config):
settings = config.get_settings()

# Register a no-op metrics service by default.
config.registry.registerUtility(metrics.NoOpMetricsService(), metrics.IMetricsService)

# This does not fully respect the Pyramid/ZCA patterns, but the rest of Kinto uses
# `registry.storage`, `registry.cache`, etc. Consistency seems more important.
config.registry.__class__.metrics = property(
Expand All @@ -449,9 +452,6 @@ def deprecated_registry(self):
def on_app_created(event):
config = event.app
metrics_service = config.registry.metrics
if not metrics_service:
logger.warning("No metrics service registered.")
return

metrics.watch_execution_time(metrics_service, config.registry.cache, prefix="backend")
metrics.watch_execution_time(metrics_service, config.registry.storage, prefix="backend")
Expand All @@ -471,8 +471,6 @@ def on_app_created(event):
def on_new_response(event):
request = event.request
metrics_service = config.registry.metrics
if not metrics_service:
return

# Count unique users.
user_id = request.prefixed_userid
Expand Down
28 changes: 27 additions & 1 deletion kinto/core/metrics.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import types

from zope.interface import Interface
from zope.interface import Interface, implementer

from kinto.core import utils

Expand All @@ -23,6 +23,30 @@ def count(key, count=1, unique=None):
"""


class NoOpTimer:
def __call__(self, f):
@utils.safe_wraps(f)
def _wrapped(*args, **kwargs):
return f(*args, **kwargs)

return _wrapped

def __enter__(self):
pass

def __exit__(self, *args, **kwargs):
pass


@implementer(IMetricsService)
class NoOpMetricsService:
def timer(self, key):
return NoOpTimer()

def count(self, key, count=1, unique=None):
pass


def watch_execution_time(metrics_service, obj, prefix="", classname=None):
"""
Decorate all methods of an object in order to watch their execution time.
Expand All @@ -49,6 +73,8 @@ def listener_with_timer(config, key, func):
def wrapped(*args, **kwargs):
metrics_service = config.registry.metrics
if not metrics_service:
# This only happens if `kinto.core.initialization.setup_metrics` is
# not listed in the `initialization_sequence` setting.
return func(*args, **kwargs)
# If metrics are enabled, monitor execution time of listeners.
with metrics_service.timer(key):
Expand Down
8 changes: 8 additions & 0 deletions kinto/core/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import collections.abc as collections_abc
import functools
import hashlib
import hmac
import os
Expand Down Expand Up @@ -541,3 +542,10 @@ def apply_json_patch(obj, ops):
raise ValueError(e)

return result


def safe_wraps(wrapper, *args, **kwargs):
"""Safely wraps partial functions."""
while isinstance(wrapper, functools.partial):
wrapper = wrapper.func
return functools.wraps(wrapper, *args, **kwargs)
9 changes: 1 addition & 8 deletions kinto/plugins/prometheus.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import functools
from time import perf_counter as time_now

from pyramid.exceptions import ConfigurationError
from pyramid.response import Response
from zope.interface import implementer

from kinto.core import metrics
from kinto.core.utils import safe_wraps


try:
Expand All @@ -30,13 +30,6 @@ def _fix_metric_name(s):
return s.replace("-", "_").replace(".", "_")


def safe_wraps(wrapper, *args, **kwargs):
"""Safely wraps partial functions."""
while isinstance(wrapper, functools.partial):
wrapper = wrapper.func
return functools.wraps(wrapper, *args, **kwargs)


class Timer:
def __init__(self, summary):
self.summary = summary
Expand Down

0 comments on commit 7e20482

Please sign in to comment.