[enh] settings.yml: implement general.enable_metrics

* allow not to record metrics (response time, etc...)
* this commit doesn't change the UI. If the metrics are disabled
  /stats and /stats/errors will return empty response.
  in /preferences, the columns response time and reliability will be empty.
This commit is contained in:
Alexandre Flament 2021-12-26 22:44:46 +01:00
parent a7199bc085
commit 2134703b4b
8 changed files with 35 additions and 11 deletions

View file

@ -81,6 +81,9 @@ Global Settings
``contact_url``: ``contact_url``:
Contact ``mailto:`` address or WEB form. Contact ``mailto:`` address or WEB form.
``enable_metrics``:
Enabled by default. Record various anonymous metrics availabled at ``/stats``,
``/stats/errors`` and ``/preferences``.
.. _settings global server: .. _settings global server:

View file

@ -9,7 +9,7 @@ from timeit import default_timer
from operator import itemgetter from operator import itemgetter
from searx.engines import engines from searx.engines import engines
from .models import HistogramStorage, CounterStorage from .models import HistogramStorage, CounterStorage, VoidHistogram, VoidCounterStorage
from .error_recorder import count_error, count_exception, errors_per_engines from .error_recorder import count_error, count_exception, errors_per_engines
__all__ = [ __all__ = [
@ -69,14 +69,18 @@ def counter(*args):
return counter_storage.get(*args) return counter_storage.get(*args)
def initialize(engine_names=None): def initialize(engine_names=None, enabled=True):
""" """
Initialize metrics Initialize metrics
""" """
global counter_storage, histogram_storage # pylint: disable=global-statement global counter_storage, histogram_storage # pylint: disable=global-statement
if enabled:
counter_storage = CounterStorage() counter_storage = CounterStorage()
histogram_storage = HistogramStorage() histogram_storage = HistogramStorage()
else:
counter_storage = VoidCounterStorage()
histogram_storage = HistogramStorage(histogram_class=VoidHistogram)
# max_timeout = max of all the engine.timeout # max_timeout = max of all the engine.timeout
max_timeout = 2 max_timeout = 2

View file

@ -9,7 +9,7 @@ from searx.exceptions import (
SearxEngineAPIException, SearxEngineAPIException,
SearxEngineAccessDeniedException, SearxEngineAccessDeniedException,
) )
from searx import searx_parent_dir from searx import searx_parent_dir, settings
from searx.engines import engines from searx.engines import engines
@ -165,6 +165,8 @@ def get_error_context(framerecords, exception_classname, log_message, log_parame
def count_exception(engine_name: str, exc: Exception, secondary: bool = False) -> None: def count_exception(engine_name: str, exc: Exception, secondary: bool = False) -> None:
if not settings['general']['enable_metrics']:
return
framerecords = inspect.trace() framerecords = inspect.trace()
try: try:
exception_classname = get_exception_classname(exc) exception_classname = get_exception_classname(exc)
@ -178,6 +180,8 @@ def count_exception(engine_name: str, exc: Exception, secondary: bool = False) -
def count_error( def count_error(
engine_name: str, log_message: str, log_parameters: typing.Optional[typing.Tuple] = None, secondary: bool = False engine_name: str, log_message: str, log_parameters: typing.Optional[typing.Tuple] = None, secondary: bool = False
) -> None: ) -> None:
if not settings['general']['enable_metrics']:
return
framerecords = list(reversed(inspect.stack()[1:])) framerecords = list(reversed(inspect.stack()[1:]))
try: try:
error_context = get_error_context(framerecords, None, log_message, log_parameters or (), secondary) error_context = get_error_context(framerecords, None, log_message, log_parameters or (), secondary)

View file

@ -102,16 +102,17 @@ class Histogram:
class HistogramStorage: class HistogramStorage:
__slots__ = 'measures' __slots__ = 'measures', 'histogram_class'
def __init__(self): def __init__(self, histogram_class=Histogram):
self.clear() self.clear()
self.histogram_class = histogram_class
def clear(self): def clear(self):
self.measures = {} self.measures = {}
def configure(self, width, size, *args): def configure(self, width, size, *args):
measure = Histogram(width, size) measure = self.histogram_class(width, size)
self.measures[args] = measure self.measures[args] = measure
return measure return measure
@ -154,3 +155,13 @@ class CounterStorage:
logger.debug("Counters:") logger.debug("Counters:")
for k in ks: for k in ks:
logger.debug("- %-60s %s", '|'.join(k), self.counters[k]) logger.debug("- %-60s %s", '|'.join(k), self.counters[k])
class VoidHistogram(Histogram):
def observe(self, value):
pass
class VoidCounterStorage(CounterStorage):
def add(self, value, *args):
pass

View file

@ -24,13 +24,13 @@ from searx.search.checker import initialize as initialize_checker
logger = logger.getChild('search') logger = logger.getChild('search')
def initialize(settings_engines=None, enable_checker=False, check_network=False): def initialize(settings_engines=None, enable_checker=False, check_network=False, enable_metrics=True):
settings_engines = settings_engines or settings['engines'] settings_engines = settings_engines or settings['engines']
load_engines(settings_engines) load_engines(settings_engines)
initialize_network(settings_engines, settings['outgoing']) initialize_network(settings_engines, settings['outgoing'])
if check_network: if check_network:
check_network_configuration() check_network_configuration()
initialize_metrics([engine['name'] for engine in settings_engines]) initialize_metrics([engine['name'] for engine in settings_engines], enable_metrics)
initialize_processors(settings_engines) initialize_processors(settings_engines)
if enable_checker: if enable_checker:
initialize_checker() initialize_checker()

View file

@ -2,6 +2,7 @@ general:
debug: false # Debug mode, only for development debug: false # Debug mode, only for development
instance_name: "SearXNG" # displayed name instance_name: "SearXNG" # displayed name
contact_url: false # mailto:contact@example.com contact_url: false # mailto:contact@example.com
enable_metrics: true # record stats
brand: brand:
new_issue_url: https://github.com/searxng/searxng/issues/new new_issue_url: https://github.com/searxng/searxng/issues/new

View file

@ -142,6 +142,7 @@ SCHEMA = {
'debug': SettingsValue(bool, False, 'SEARXNG_DEBUG'), 'debug': SettingsValue(bool, False, 'SEARXNG_DEBUG'),
'instance_name': SettingsValue(str, 'SearXNG'), 'instance_name': SettingsValue(str, 'SearXNG'),
'contact_url': SettingsValue((None, False, str), None), 'contact_url': SettingsValue((None, False, str), None),
'enable_metrics': SettingsValue(bool, True),
}, },
'brand': { 'brand': {
'issue_url': SettingsValue(str, 'https://github.com/searxng/searxng/issues'), 'issue_url': SettingsValue(str, 'https://github.com/searxng/searxng/issues'),

View file

@ -1333,7 +1333,7 @@ werkzeug_reloader = flask_run_development or (searx_debug and __name__ == "__mai
# initialize the engines except on the first run of the werkzeug server. # initialize the engines except on the first run of the werkzeug server.
if not werkzeug_reloader or (werkzeug_reloader and os.environ.get("WERKZEUG_RUN_MAIN") == "true"): if not werkzeug_reloader or (werkzeug_reloader and os.environ.get("WERKZEUG_RUN_MAIN") == "true"):
plugin_initialize(app) plugin_initialize(app)
search_initialize(enable_checker=True, check_network=True) search_initialize(enable_checker=True, check_network=True, enable_metrics=settings['general']['enable_metrics'])
def run(): def run():