diff --git a/Makefile b/Makefile index 166fb65e4..7149437be 100644 --- a/Makefile +++ b/Makefile @@ -199,7 +199,8 @@ PYLINT_FILES=\ searx/engines/yahoo_news.py \ searx/engines/apkmirror.py \ searx/engines/artic.py \ - searx_extra/update/update_external_bangs.py + searx_extra/update/update_external_bangs.py \ + searx/metrics/__init__.py test.pylint: pyenvinstall $(call cmd,pylint,$(PYLINT_FILES)) diff --git a/searx/metrics/__init__.py b/searx/metrics/__init__.py index bae62c915..5665ca63c 100644 --- a/searx/metrics/__init__.py +++ b/searx/metrics/__init__.py @@ -1,4 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later +# pylint: disable=missing-module-docstring, missing-function-docstring import typing import math @@ -63,7 +64,7 @@ def initialize(engine_names=None): """ Initialize metrics """ - global counter_storage, histogram_storage + global counter_storage, histogram_storage # pylint: disable=global-statement counter_storage = CounterStorage() histogram_storage = HistogramStorage() @@ -96,12 +97,12 @@ def initialize(engine_names=None): histogram_storage.configure(histogram_width, histogram_size, 'engine', engine_name, 'time', 'total') -def get_engine_errors(engline_list): +def get_engine_errors(engline_name_list): result = {} engine_names = list(errors_per_engines.keys()) engine_names.sort() for engine_name in engine_names: - if engine_name not in engline_list: + if engine_name not in engline_name_list: continue error_stats = errors_per_engines[engine_name] @@ -125,82 +126,88 @@ def get_engine_errors(engline_list): return result -def to_percentage(stats, maxvalue): - for engine_stat in stats: - if maxvalue: - engine_stat['percentage'] = int(engine_stat['avg'] / maxvalue * 100) +def get_reliabilities(engline_name_list, checker_results): + reliabilities = {} + + engine_errors = get_engine_errors(engline_name_list) + + for engine_name in engline_name_list: + checker_result = checker_results.get(engine_name, {}) + checker_success = checker_result.get('success', True) + errors = engine_errors.get(engine_name) or [] + if counter('engine', engine_name, 'search', 'count', 'sent') == 0: + # no request + reliablity = None + elif checker_success and not errors: + reliablity = 100 + elif 'simple' in checker_result.get('errors', {}): + # the basic (simple) test doesn't work: the engine is broken accoding to the checker + # even if there is no exception + reliablity = 0 else: - engine_stat['percentage'] = 0 - return stats + reliablity = 100 - sum([error['percentage'] for error in errors if not error.get('secondary')]) + + reliabilities[engine_name] = { + 'reliablity': reliablity, + 'errors': errors, + 'checker': checker_results.get(engine_name, {}).get('errors', {}).keys(), + } + return reliabilities -def get_engines_stats(engine_list): - global counter_storage, histogram_storage +def round_or_none(number, digits): + return round(number, digits) if number else number + +def get_engines_stats(engine_name_list): assert counter_storage is not None assert histogram_storage is not None list_time = [] - list_time_http = [] - list_time_total = [] - list_result_count = [] - list_error_count = [] - list_scores = [] - list_scores_per_result = [] - max_error_count = max_http_time = max_time_total = max_result_count = max_score = None # noqa - for engine_name in engine_list: - error_count = counter('engine', engine_name, 'search', 'count', 'error') - - if counter('engine', engine_name, 'search', 'count', 'sent') > 0: - list_error_count.append({'avg': error_count, 'name': engine_name}) - max_error_count = max(error_count, max_error_count or 0) - - successful_count = counter('engine', engine_name, 'search', 'count', 'successful') - if successful_count == 0: + max_time_total = max_result_count = None # noqa + for engine_name in engine_name_list: + sent_count = counter('engine', engine_name, 'search', 'count', 'sent') + if sent_count == 0: continue - result_count_sum = histogram('engine', engine_name, 'result', 'count').sum + successful_count = counter('engine', engine_name, 'search', 'count', 'successful') + time_total = histogram('engine', engine_name, 'time', 'total').percentage(50) time_http = histogram('engine', engine_name, 'time', 'http').percentage(50) - result_count = result_count_sum / float(successful_count) + time_total_p80 = histogram('engine', engine_name, 'time', 'total').percentage(80) + time_http_p80 = histogram('engine', engine_name, 'time', 'http').percentage(80) + time_total_p95 = histogram('engine', engine_name, 'time', 'total').percentage(95) + time_http_p95 = histogram('engine', engine_name, 'time', 'http').percentage(95) - if result_count: + result_count = histogram('engine', engine_name, 'result', 'count').percentage(50) + result_count_sum = histogram('engine', engine_name, 'result', 'count').sum + if successful_count and result_count_sum: score = counter('engine', engine_name, 'score') # noqa score_per_result = score / float(result_count_sum) else: score = score_per_result = 0.0 - max_time_total = max(time_total, max_time_total or 0) - max_http_time = max(time_http, max_http_time or 0) - max_result_count = max(result_count, max_result_count or 0) - max_score = max(score, max_score or 0) - - list_time.append({'total': round(time_total, 1), - 'http': round(time_http, 1), - 'name': engine_name, - 'processing': round(time_total - time_http, 1)}) - list_time_total.append({'avg': time_total, 'name': engine_name}) - list_time_http.append({'avg': time_http, 'name': engine_name}) - list_result_count.append({'avg': result_count, 'name': engine_name}) - list_scores.append({'avg': score, 'name': engine_name}) - list_scores_per_result.append({'avg': score_per_result, 'name': engine_name}) - - list_time = sorted(list_time, key=itemgetter('total')) - list_time_total = sorted(to_percentage(list_time_total, max_time_total), key=itemgetter('avg')) - list_time_http = sorted(to_percentage(list_time_http, max_http_time), key=itemgetter('avg')) - list_result_count = sorted(to_percentage(list_result_count, max_result_count), key=itemgetter('avg'), reverse=True) - list_scores = sorted(list_scores, key=itemgetter('avg'), reverse=True) - list_scores_per_result = sorted(list_scores_per_result, key=itemgetter('avg'), reverse=True) - list_error_count = sorted(to_percentage(list_error_count, max_error_count), key=itemgetter('avg'), reverse=True) + max_time_total = max(time_total or 0, max_time_total or 0) + max_result_count = max(result_count or 0, max_result_count or 0) + list_time.append({ + 'name': engine_name, + 'total': round_or_none(time_total, 1), + 'total_p80': round_or_none(time_total_p80, 1), + 'total_p95': round_or_none(time_total_p95, 1), + 'http': round_or_none(time_http, 1), + 'http_p80': round_or_none(time_http_p80, 1), + 'http_p95': round_or_none(time_http_p95, 1), + 'processing': round(time_total - time_http, 1) if time_total else None, + 'processing_p80': round(time_total_p80 - time_http_p80, 1) if time_total else None, + 'processing_p95': round(time_total_p95 - time_http_p95, 1) if time_total else None, + 'score': score, + 'score_per_result': score_per_result, + 'result_count': result_count, + }) return { 'time': list_time, 'max_time': math.ceil(max_time_total or 0), - 'time_total': list_time_total, - 'time_http': list_time_http, - 'result_count': list_result_count, - 'scores': list_scores, - 'scores_per_result': list_scores_per_result, - 'error_count': list_error_count, + 'max_result_count': math.ceil(max_result_count or 0), } diff --git a/searx/static/themes/oscar/css/logicodev-dark.css b/searx/static/themes/oscar/css/logicodev-dark.css index 618de9327..f9cdc41f6 100644 --- a/searx/static/themes/oscar/css/logicodev-dark.css +++ b/searx/static/themes/oscar/css/logicodev-dark.css @@ -998,3 +998,21 @@ th:hover .engine-tooltip, padding: 0.4rem 0; width: 1px; } +.stacked-bar-chart-serie1 { + display: flex; + flex-shrink: 0; + flex-grow: 0; + flex-basis: unset; + background: #5bc0de; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + padding: 0.4rem 0; +} +.stacked-bar-chart-serie2 { + display: flex; + flex-shrink: 0; + flex-grow: 0; + flex-basis: unset; + background: #deb15b; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + padding: 0.4rem 0; +} diff --git a/searx/static/themes/oscar/css/logicodev-dark.min.css b/searx/static/themes/oscar/css/logicodev-dark.min.css index 09aed0298..e34b34480 100644 Binary files a/searx/static/themes/oscar/css/logicodev-dark.min.css and b/searx/static/themes/oscar/css/logicodev-dark.min.css differ diff --git a/searx/static/themes/oscar/css/logicodev-dark.min.css.map b/searx/static/themes/oscar/css/logicodev-dark.min.css.map index 71062db2e..fdaf8d8f4 100644 Binary files a/searx/static/themes/oscar/css/logicodev-dark.min.css.map and b/searx/static/themes/oscar/css/logicodev-dark.min.css.map differ diff --git a/searx/static/themes/oscar/css/logicodev.css b/searx/static/themes/oscar/css/logicodev.css index 4f6b36b11..40256101a 100644 --- a/searx/static/themes/oscar/css/logicodev.css +++ b/searx/static/themes/oscar/css/logicodev.css @@ -971,6 +971,24 @@ th:hover .engine-tooltip, padding: 0.4rem 0; width: 1px; } +.stacked-bar-chart-serie1 { + display: flex; + flex-shrink: 0; + flex-grow: 0; + flex-basis: unset; + background: #5bc0de; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + padding: 0.4rem 0; +} +.stacked-bar-chart-serie2 { + display: flex; + flex-shrink: 0; + flex-grow: 0; + flex-basis: unset; + background: #deb15b; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + padding: 0.4rem 0; +} /*Global*/ body { background: #1d1f21 none !important; diff --git a/searx/static/themes/oscar/css/logicodev.min.css b/searx/static/themes/oscar/css/logicodev.min.css index db035aa75..3daa9595d 100644 Binary files a/searx/static/themes/oscar/css/logicodev.min.css and b/searx/static/themes/oscar/css/logicodev.min.css differ diff --git a/searx/static/themes/oscar/css/logicodev.min.css.map b/searx/static/themes/oscar/css/logicodev.min.css.map index 50598d2ef..bc97c8bc8 100644 Binary files a/searx/static/themes/oscar/css/logicodev.min.css.map and b/searx/static/themes/oscar/css/logicodev.min.css.map differ diff --git a/searx/static/themes/oscar/css/pointhi.css b/searx/static/themes/oscar/css/pointhi.css index 64f612d79..99ed7b576 100644 --- a/searx/static/themes/oscar/css/pointhi.css +++ b/searx/static/themes/oscar/css/pointhi.css @@ -682,6 +682,7 @@ input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not padding: 0.5rem 1rem; margin: 0rem 0 0 2rem; border: 1px solid #ddd; + box-shadow: 2px 2px 2px 0px rgba(0, 0, 0, 0.1); background: white; font-size: 14px; font-weight: normal; @@ -756,3 +757,21 @@ td:hover .engine-tooltip, padding: 0.4rem 0; width: 1px; } +.stacked-bar-chart-serie1 { + display: flex; + flex-shrink: 0; + flex-grow: 0; + flex-basis: unset; + background: #5bc0de; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + padding: 0.4rem 0; +} +.stacked-bar-chart-serie2 { + display: flex; + flex-shrink: 0; + flex-grow: 0; + flex-basis: unset; + background: #deb15b; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + padding: 0.4rem 0; +} diff --git a/searx/static/themes/oscar/css/pointhi.min.css b/searx/static/themes/oscar/css/pointhi.min.css index 4332e4767..80027ff8e 100644 Binary files a/searx/static/themes/oscar/css/pointhi.min.css and b/searx/static/themes/oscar/css/pointhi.min.css differ diff --git a/searx/static/themes/oscar/css/pointhi.min.css.map b/searx/static/themes/oscar/css/pointhi.min.css.map index abb30817f..708e2f63a 100644 Binary files a/searx/static/themes/oscar/css/pointhi.min.css.map and b/searx/static/themes/oscar/css/pointhi.min.css.map differ diff --git a/searx/static/themes/oscar/js/searx.min.js b/searx/static/themes/oscar/js/searx.min.js index b31aad6f0..ad36c8e06 100644 Binary files a/searx/static/themes/oscar/js/searx.min.js and b/searx/static/themes/oscar/js/searx.min.js differ diff --git a/searx/static/themes/oscar/src/less/logicodev/preferences.less b/searx/static/themes/oscar/src/less/logicodev/preferences.less index 32e230413..790ed10b7 100644 --- a/searx/static/themes/oscar/src/less/logicodev/preferences.less +++ b/searx/static/themes/oscar/src/less/logicodev/preferences.less @@ -89,3 +89,17 @@ td:hover .engine-tooltip, th:hover .engine-tooltip, .engine-tooltip:hover { padding: 0.4rem 0; width: 1px; } + +.stacked-bar-chart-serie1 { + .stacked-bar-chart-base(); + background: #5bc0de; + box-shadow: inset 0 -1px 0 rgba(0,0,0,.15); + padding: 0.4rem 0; +} + +.stacked-bar-chart-serie2 { + .stacked-bar-chart-base(); + background: #deb15b; + box-shadow: inset 0 -1px 0 rgba(0,0,0,.15); + padding: 0.4rem 0; +} diff --git a/searx/static/themes/oscar/src/less/pointhi/preferences.less b/searx/static/themes/oscar/src/less/pointhi/preferences.less index cb63674ed..352aed513 100644 --- a/searx/static/themes/oscar/src/less/pointhi/preferences.less +++ b/searx/static/themes/oscar/src/less/pointhi/preferences.less @@ -8,6 +8,7 @@ padding: 0.5rem 1rem; margin: 0rem 0 0 2rem; border: 1px solid #ddd; + box-shadow: 2px 2px 2px 0px rgba(0,0,0,0.1); background: white; font-size: 14px; font-weight: normal; @@ -77,3 +78,17 @@ th:hover .engine-tooltip, td:hover .engine-tooltip, .engine-tooltip:hover { width: 1px; } +.stacked-bar-chart-serie1 { + .stacked-bar-chart-base(); + background: #5bc0de; + box-shadow: inset 0 -1px 0 rgba(0,0,0,.15); + padding: 0.4rem 0; +} + +.stacked-bar-chart-serie2 { + .stacked-bar-chart-base(); + background: #deb15b; + box-shadow: inset 0 -1px 0 rgba(0,0,0,.15); + padding: 0.4rem 0; +} + diff --git a/searx/static/themes/simple/css/searx-rtl.css b/searx/static/themes/simple/css/searx-rtl.css index 0da2850c5..8823fa8b6 100644 --- a/searx/static/themes/simple/css/searx-rtl.css +++ b/searx/static/themes/simple/css/searx-rtl.css @@ -1,4 +1,4 @@ -/*! searx | 21-04-2021 | */ +/*! searx | 23-04-2021 | */ /* * searx, A privacy-respecting, hackable metasearch engine * @@ -1153,6 +1153,25 @@ select:focus { transform: rotate(360deg); } } +/* -- engine-tooltip -- */ +.engine-tooltip { + display: none; + position: absolute; + padding: 0.5rem 1rem; + margin: 0rem 0 0 2rem; + border: 1px solid #ddd; + box-shadow: 2px 2px 2px 0px rgba(0, 0, 0, 0.1); + background: white; + font-size: 14px; + font-weight: normal; + z-index: 1000000; + text-align: left; +} +th:hover .engine-tooltip, +td:hover .engine-tooltip, +.engine-tooltip:hover { + display: inline-block; +} /* -- stacked bar chart -- */ .stacked-bar-chart { margin: 0; @@ -1216,6 +1235,24 @@ select:focus { padding: 0.4rem 0; width: 1px; } +.stacked-bar-chart-serie1 { + display: flex; + flex-shrink: 0; + flex-grow: 0; + flex-basis: unset; + background: #5bc0de; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + padding: 0.4rem 0; +} +.stacked-bar-chart-serie2 { + display: flex; + flex-shrink: 0; + flex-grow: 0; + flex-basis: unset; + background: #deb15b; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + padding: 0.4rem 0; +} /*! Autocomplete.js v2.6.3 | license MIT | (c) 2017, Baptiste Donaux | http://autocomplete-js.com */ .autocomplete { position: absolute; @@ -1494,23 +1531,6 @@ select:focus { #main_preferences div.selectable_url pre { width: 100%; } -#main_preferences .engine-tooltip { - display: none; - position: absolute; - padding: 0.5rem 1rem; - margin: 0rem 0 0 2rem; - border: 1px solid #ddd; - background: white; - font-size: 14px; - font-weight: normal; - z-index: 1000000; - text-align: left; -} -#main_preferences th:hover .engine-tooltip, -#main_preferences td:hover .engine-tooltip, -#main_preferences .engine-tooltip:hover { - display: inline-block; -} @media screen and (max-width: 75em) { .preferences_back { clear: both; diff --git a/searx/static/themes/simple/css/searx-rtl.min.css b/searx/static/themes/simple/css/searx-rtl.min.css index 615b88ec5..68b25fa60 100644 Binary files a/searx/static/themes/simple/css/searx-rtl.min.css and b/searx/static/themes/simple/css/searx-rtl.min.css differ diff --git a/searx/static/themes/simple/css/searx.css b/searx/static/themes/simple/css/searx.css index 15b9f0853..b8c95e19e 100644 --- a/searx/static/themes/simple/css/searx.css +++ b/searx/static/themes/simple/css/searx.css @@ -1,4 +1,4 @@ -/*! searx | 21-04-2021 | */ +/*! searx | 23-04-2021 | */ /* * searx, A privacy-respecting, hackable metasearch engine * @@ -1153,6 +1153,25 @@ select:focus { transform: rotate(360deg); } } +/* -- engine-tooltip -- */ +.engine-tooltip { + display: none; + position: absolute; + padding: 0.5rem 1rem; + margin: 0rem 0 0 2rem; + border: 1px solid #ddd; + box-shadow: 2px 2px 2px 0px rgba(0, 0, 0, 0.1); + background: white; + font-size: 14px; + font-weight: normal; + z-index: 1000000; + text-align: left; +} +th:hover .engine-tooltip, +td:hover .engine-tooltip, +.engine-tooltip:hover { + display: inline-block; +} /* -- stacked bar chart -- */ .stacked-bar-chart { margin: 0; @@ -1216,6 +1235,24 @@ select:focus { padding: 0.4rem 0; width: 1px; } +.stacked-bar-chart-serie1 { + display: flex; + flex-shrink: 0; + flex-grow: 0; + flex-basis: unset; + background: #5bc0de; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + padding: 0.4rem 0; +} +.stacked-bar-chart-serie2 { + display: flex; + flex-shrink: 0; + flex-grow: 0; + flex-basis: unset; + background: #deb15b; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + padding: 0.4rem 0; +} /*! Autocomplete.js v2.6.3 | license MIT | (c) 2017, Baptiste Donaux | http://autocomplete-js.com */ .autocomplete { position: absolute; @@ -1494,23 +1531,6 @@ select:focus { #main_preferences div.selectable_url pre { width: 100%; } -#main_preferences .engine-tooltip { - display: none; - position: absolute; - padding: 0.5rem 1rem; - margin: 0rem 0 0 2rem; - border: 1px solid #ddd; - background: white; - font-size: 14px; - font-weight: normal; - z-index: 1000000; - text-align: left; -} -#main_preferences th:hover .engine-tooltip, -#main_preferences td:hover .engine-tooltip, -#main_preferences .engine-tooltip:hover { - display: inline-block; -} @media screen and (max-width: 75em) { .preferences_back { clear: both; diff --git a/searx/static/themes/simple/css/searx.min.css b/searx/static/themes/simple/css/searx.min.css index 52ad98ecd..54e4e73ef 100644 Binary files a/searx/static/themes/simple/css/searx.min.css and b/searx/static/themes/simple/css/searx.min.css differ diff --git a/searx/static/themes/simple/js/searx.head.min.js b/searx/static/themes/simple/js/searx.head.min.js index 043f25515..cc57bdea9 100644 Binary files a/searx/static/themes/simple/js/searx.head.min.js and b/searx/static/themes/simple/js/searx.head.min.js differ diff --git a/searx/static/themes/simple/js/searx.min.js b/searx/static/themes/simple/js/searx.min.js index 8ae15bede..36b8c3870 100644 Binary files a/searx/static/themes/simple/js/searx.min.js and b/searx/static/themes/simple/js/searx.min.js differ diff --git a/searx/static/themes/simple/less/preferences.less b/searx/static/themes/simple/less/preferences.less index 93bdaad27..e1e88b51f 100644 --- a/searx/static/themes/simple/less/preferences.less +++ b/searx/static/themes/simple/less/preferences.less @@ -93,24 +93,6 @@ width: 100%; } } - - - .engine-tooltip { - display: none; - position: absolute; - padding: 0.5rem 1rem; - margin: 0rem 0 0 2rem; - border: 1px solid #ddd; - background: white; - font-size: 14px; - font-weight: normal; - z-index: 1000000; - text-align: left; - } - - th:hover .engine-tooltip, td:hover .engine-tooltip, .engine-tooltip:hover { - display: inline-block; - } } diff --git a/searx/static/themes/simple/less/toolkit.less b/searx/static/themes/simple/less/toolkit.less index b3dba9ea9..3e9274fc8 100644 --- a/searx/static/themes/simple/less/toolkit.less +++ b/searx/static/themes/simple/less/toolkit.less @@ -475,6 +475,25 @@ select { } } +/* -- engine-tooltip -- */ +.engine-tooltip { + display: none; + position: absolute; + padding: 0.5rem 1rem; + margin: 0rem 0 0 2rem; + border: 1px solid #ddd; + box-shadow: 2px 2px 2px 0px rgba(0,0,0,0.1); + background: white; + font-size: 14px; + font-weight: normal; + z-index: 1000000; + text-align: left; +} + +th:hover .engine-tooltip, td:hover .engine-tooltip, .engine-tooltip:hover { + display: inline-block; +} + /* -- stacked bar chart -- */ .stacked-bar-chart { margin: 0; @@ -532,3 +551,17 @@ select { padding: 0.4rem 0; width: 1px; } + +.stacked-bar-chart-serie1 { + .stacked-bar-chart-base(); + background: #5bc0de; + box-shadow: inset 0 -1px 0 rgba(0,0,0,.15); + padding: 0.4rem 0; +} + +.stacked-bar-chart-serie2 { + .stacked-bar-chart-base(); + background: #deb15b; + box-shadow: inset 0 -1px 0 rgba(0,0,0,.15); + padding: 0.4rem 0; +} diff --git a/searx/templates/oscar/stats.html b/searx/templates/oscar/stats.html index 0573bf65f..b83714020 100644 --- a/searx/templates/oscar/stats.html +++ b/searx/templates/oscar/stats.html @@ -1,45 +1,97 @@ {% extends "oscar/base.html" %} -{% block styles %} - - -{% endblock %} {% block title %}{{ _('stats') }} - {% endblock %} + +{%- macro th_sort(column_order, column_name) -%} + {% if column_order==sort_order %} + {{ column_name }} {{ icon('chevron-down') }} + {% else %} + {{ column_name }} + {% endif %} +{%- endmacro -%} + {% block content %}

{{ _('Engine stats') }}

- {% for stat_name,stat_category in stats %} -
-

{{ stat_name }}

-
- {% for engine in stat_category %} -
-
{{ engine.name }}
-
-
-
- {{ '%.02f'|format(engine.avg) }} -
-
+
+
+ {% if not engine_stats.get('time') %} +
+ {% include 'oscar/messages/no_data_available.html' %}
-
- {% endfor %} - {% if not stat_category %} -
- {% include 'oscar/messages/no_data_available.html' %} -
+ {% else %} + + + + + + + + + {% for engine_stat in engine_stats.get('time', []) %} + + + + + + + + {% endfor %} +
{{ th_sort('name', _("Engine name")) }}{{ th_sort('score', _('Scores')) }}{{ th_sort('result_count', _('Result count')) }}{{ th_sort('time', _('Response time')) }}{{ th_sort('reliability', _('Reliability')) }}
{{ engine_stat.name }} + {% if engine_stat.score %} + {{ engine_stat.score|round(1) }} + + {% endif %} + + {%- if engine_stat.result_count -%} + {{- engine_stat.result_count | int -}}{{- "" -}} + + {%- endif -%} + + {%- if engine_stat.total -%} + {{- engine_stat.total | round(1) -}}{{- "" -}} + {{- "" -}} + + {%- endif -%} + {{ engine_reliabilities.get(engine_stat.name, {}).get('reliablity') }}
{% endif %}
- {% endfor %}
{% endblock %} diff --git a/searx/templates/simple/stats.html b/searx/templates/simple/stats.html index 462ab4aa9..eecd88903 100644 --- a/searx/templates/simple/stats.html +++ b/searx/templates/simple/stats.html @@ -1,4 +1,15 @@ +{% from 'simple/macros.html' import icon %} + {% extends "simple/base.html" %} + +{%- macro th_sort(column_order, column_name) -%} + {% if column_order==sort_order %} + {{ column_name }} {{ icon('arrow-dropdown') }} + {% else %} +
{{ column_name }} + {% endif %} +{%- endmacro -%} + {% block head %} {% endblock %} {% block content %} @@ -6,20 +17,77 @@

{{ _('Engine stats') }}

-{% for stat_name,stat_category in stats %} -
- - - - - {% for engine in stat_category %} - - - - - - {% endfor %} -
{{ stat_name }}
{{ engine.name }}{{ '%.02f'|format(engine.avg) }}
 
-
-{% endfor %} +{% if not engine_stats.get('time') %} +{{ _('There is currently no data available. ') }} +{% else %} + + + + + + + + + {% for engine_stat in engine_stats.get('time', []) %} + + + + + + + + {% endfor %} +
{{ th_sort('name', _("Engine name")) }}{{ th_sort('score', _('Scores')) }}{{ th_sort('result_count', _('Result count')) }}{{ th_sort('time', _('Response time')) }}{{ th_sort('reliability', _('Reliability')) }}
{{ engine_stat.name }} + {% if engine_stat.score %} + {{ engine_stat.score|round(1) }} + + {% endif %} + + {%- if engine_stat.result_count -%} + {{- engine_stat.result_count | int -}}{{- "" -}} + + {%- endif -%} + + {%- if engine_stat.total -%} + {{- engine_stat.total | round(1) -}}{{- "" -}} + {{- "" -}} + + {%- endif -%} + {{ engine_reliabilities.get(engine_stat.name, {}).get('reliablity') }}
+{% endif %} + {% endblock %} diff --git a/searx/webapp.py b/searx/webapp.py index d02e142fc..d917c16d4 100755 --- a/searx/webapp.py +++ b/searx/webapp.py @@ -93,7 +93,7 @@ from searx.preferences import Preferences, ValidationException, LANGUAGE_CODES from searx.answerers import answerers from searx.network import stream as http_stream from searx.answerers import ask -from searx.metrics import get_engines_stats, get_engine_errors, histogram, counter +from searx.metrics import get_engines_stats, get_engine_errors, get_reliabilities, histogram, counter # serve pages with HTTP/1.1 from werkzeug.serving import WSGIRequestHandler @@ -1073,16 +1073,47 @@ def image_proxy(): @app.route('/stats', methods=['GET']) def stats(): """Render engine statistics page.""" + checker_results = checker_get_result() + checker_results = checker_results['engines'] \ + if checker_results['status'] == 'ok' and 'engines' in checker_results else {} + filtered_engines = dict(filter(lambda kv: (kv[0], request.preferences.validate_token(kv[1])), engines.items())) engine_stats = get_engines_stats(filtered_engines) + engine_reliabilities = get_reliabilities(filtered_engines, checker_results) + + sort_order = request.args.get('sort', default='name', type=str) + + SORT_PARAMETERS = { + 'name': (False, 'name', ''), + 'score': (True, 'score', 0), + 'result_count': (True, 'result_count', 0), + 'time': (False, 'total', 0), + 'reliability': (False, 'reliability', 100), + } + + if sort_order not in SORT_PARAMETERS: + sort_order = 'name' + + reverse, key_name, default_value = SORT_PARAMETERS[sort_order] + + def get_key(engine_stat): + reliability = engine_reliabilities.get(engine_stat['name']).get('reliablity', 0) + reliability_order = 0 if reliability else 1 + if key_name == 'reliability': + key = reliability + reliability_order = 0 + else: + key = engine_stat.get(key_name) or default_value + if reverse: + reliability_order = 1 - reliability_order + return (reliability_order, key, engine_stat['name']) + + engine_stats['time'] = sorted(engine_stats['time'], reverse=reverse, key=get_key) return render( 'stats.html', - stats=[(gettext('Engine time (sec)'), engine_stats['time_total']), - (gettext('Page loads (sec)'), engine_stats['time_http']), - (gettext('Number of results'), engine_stats['result_count']), - (gettext('Scores'), engine_stats['scores']), - (gettext('Scores per result'), engine_stats['scores_per_result']), - (gettext('Errors'), engine_stats['error_count'])] + sort_order=sort_order, + engine_stats=engine_stats, + engine_reliabilities=engine_reliabilities, )