forked from zaclys/searxng
Merge pull request #12 from searxng/metrics-stats-page
[mod] update /stats
This commit is contained in:
commit
3cdd6a6a50
3
Makefile
3
Makefile
|
@ -199,7 +199,8 @@ PYLINT_FILES=\
|
||||||
searx/engines/yahoo_news.py \
|
searx/engines/yahoo_news.py \
|
||||||
searx/engines/apkmirror.py \
|
searx/engines/apkmirror.py \
|
||||||
searx/engines/artic.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
|
test.pylint: pyenvinstall
|
||||||
$(call cmd,pylint,$(PYLINT_FILES))
|
$(call cmd,pylint,$(PYLINT_FILES))
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
# pylint: disable=missing-module-docstring, missing-function-docstring
|
||||||
|
|
||||||
import typing
|
import typing
|
||||||
import math
|
import math
|
||||||
|
@ -63,7 +64,7 @@ def initialize(engine_names=None):
|
||||||
"""
|
"""
|
||||||
Initialize metrics
|
Initialize metrics
|
||||||
"""
|
"""
|
||||||
global counter_storage, histogram_storage
|
global counter_storage, histogram_storage # pylint: disable=global-statement
|
||||||
|
|
||||||
counter_storage = CounterStorage()
|
counter_storage = CounterStorage()
|
||||||
histogram_storage = HistogramStorage()
|
histogram_storage = HistogramStorage()
|
||||||
|
@ -96,12 +97,12 @@ def initialize(engine_names=None):
|
||||||
histogram_storage.configure(histogram_width, histogram_size, 'engine', engine_name, 'time', 'total')
|
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 = {}
|
result = {}
|
||||||
engine_names = list(errors_per_engines.keys())
|
engine_names = list(errors_per_engines.keys())
|
||||||
engine_names.sort()
|
engine_names.sort()
|
||||||
for engine_name in engine_names:
|
for engine_name in engine_names:
|
||||||
if engine_name not in engline_list:
|
if engine_name not in engline_name_list:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
error_stats = errors_per_engines[engine_name]
|
error_stats = errors_per_engines[engine_name]
|
||||||
|
@ -125,82 +126,88 @@ def get_engine_errors(engline_list):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def to_percentage(stats, maxvalue):
|
def get_reliabilities(engline_name_list, checker_results):
|
||||||
for engine_stat in stats:
|
reliabilities = {}
|
||||||
if maxvalue:
|
|
||||||
engine_stat['percentage'] = int(engine_stat['avg'] / maxvalue * 100)
|
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:
|
else:
|
||||||
engine_stat['percentage'] = 0
|
reliablity = 100 - sum([error['percentage'] for error in errors if not error.get('secondary')])
|
||||||
return stats
|
|
||||||
|
reliabilities[engine_name] = {
|
||||||
|
'reliablity': reliablity,
|
||||||
|
'errors': errors,
|
||||||
|
'checker': checker_results.get(engine_name, {}).get('errors', {}).keys(),
|
||||||
|
}
|
||||||
|
return reliabilities
|
||||||
|
|
||||||
|
|
||||||
def get_engines_stats(engine_list):
|
def round_or_none(number, digits):
|
||||||
global counter_storage, histogram_storage
|
return round(number, digits) if number else number
|
||||||
|
|
||||||
|
|
||||||
|
def get_engines_stats(engine_name_list):
|
||||||
assert counter_storage is not None
|
assert counter_storage is not None
|
||||||
assert histogram_storage is not None
|
assert histogram_storage is not None
|
||||||
|
|
||||||
list_time = []
|
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
|
max_time_total = max_result_count = None # noqa
|
||||||
for engine_name in engine_list:
|
for engine_name in engine_name_list:
|
||||||
error_count = counter('engine', engine_name, 'search', 'count', 'error')
|
sent_count = counter('engine', engine_name, 'search', 'count', 'sent')
|
||||||
|
if sent_count == 0:
|
||||||
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:
|
|
||||||
continue
|
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_total = histogram('engine', engine_name, 'time', 'total').percentage(50)
|
||||||
time_http = histogram('engine', engine_name, 'time', 'http').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 = counter('engine', engine_name, 'score') # noqa
|
||||||
score_per_result = score / float(result_count_sum)
|
score_per_result = score / float(result_count_sum)
|
||||||
else:
|
else:
|
||||||
score = score_per_result = 0.0
|
score = score_per_result = 0.0
|
||||||
|
|
||||||
max_time_total = max(time_total, max_time_total or 0)
|
max_time_total = max(time_total or 0, max_time_total or 0)
|
||||||
max_http_time = max(time_http, max_http_time or 0)
|
max_result_count = max(result_count or 0, max_result_count 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)
|
|
||||||
|
|
||||||
|
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 {
|
return {
|
||||||
'time': list_time,
|
'time': list_time,
|
||||||
'max_time': math.ceil(max_time_total or 0),
|
'max_time': math.ceil(max_time_total or 0),
|
||||||
'time_total': list_time_total,
|
'max_result_count': math.ceil(max_result_count or 0),
|
||||||
'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,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -998,3 +998,21 @@ th:hover .engine-tooltip,
|
||||||
padding: 0.4rem 0;
|
padding: 0.4rem 0;
|
||||||
width: 1px;
|
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;
|
||||||
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -971,6 +971,24 @@ th:hover .engine-tooltip,
|
||||||
padding: 0.4rem 0;
|
padding: 0.4rem 0;
|
||||||
width: 1px;
|
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*/
|
/*Global*/
|
||||||
body {
|
body {
|
||||||
background: #1d1f21 none !important;
|
background: #1d1f21 none !important;
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -682,6 +682,7 @@ input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
margin: 0rem 0 0 2rem;
|
margin: 0rem 0 0 2rem;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
|
box-shadow: 2px 2px 2px 0px rgba(0, 0, 0, 0.1);
|
||||||
background: white;
|
background: white;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
@ -756,3 +757,21 @@ td:hover .engine-tooltip,
|
||||||
padding: 0.4rem 0;
|
padding: 0.4rem 0;
|
||||||
width: 1px;
|
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;
|
||||||
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -89,3 +89,17 @@ td:hover .engine-tooltip, th:hover .engine-tooltip, .engine-tooltip:hover {
|
||||||
padding: 0.4rem 0;
|
padding: 0.4rem 0;
|
||||||
width: 1px;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
margin: 0rem 0 0 2rem;
|
margin: 0rem 0 0 2rem;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
|
box-shadow: 2px 2px 2px 0px rgba(0,0,0,0.1);
|
||||||
background: white;
|
background: white;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
@ -77,3 +78,17 @@ th:hover .engine-tooltip, td:hover .engine-tooltip, .engine-tooltip:hover {
|
||||||
width: 1px;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*! searx | 21-04-2021 | */
|
/*! searx | 23-04-2021 | */
|
||||||
/*
|
/*
|
||||||
* searx, A privacy-respecting, hackable metasearch engine
|
* searx, A privacy-respecting, hackable metasearch engine
|
||||||
*
|
*
|
||||||
|
@ -1153,6 +1153,25 @@ select:focus {
|
||||||
transform: rotate(360deg);
|
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 -- */
|
||||||
.stacked-bar-chart {
|
.stacked-bar-chart {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -1216,6 +1235,24 @@ select:focus {
|
||||||
padding: 0.4rem 0;
|
padding: 0.4rem 0;
|
||||||
width: 1px;
|
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.js v2.6.3 | license MIT | (c) 2017, Baptiste Donaux | http://autocomplete-js.com */
|
||||||
.autocomplete {
|
.autocomplete {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -1494,23 +1531,6 @@ select:focus {
|
||||||
#main_preferences div.selectable_url pre {
|
#main_preferences div.selectable_url pre {
|
||||||
width: 100%;
|
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) {
|
@media screen and (max-width: 75em) {
|
||||||
.preferences_back {
|
.preferences_back {
|
||||||
clear: both;
|
clear: both;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,4 @@
|
||||||
/*! searx | 21-04-2021 | */
|
/*! searx | 23-04-2021 | */
|
||||||
/*
|
/*
|
||||||
* searx, A privacy-respecting, hackable metasearch engine
|
* searx, A privacy-respecting, hackable metasearch engine
|
||||||
*
|
*
|
||||||
|
@ -1153,6 +1153,25 @@ select:focus {
|
||||||
transform: rotate(360deg);
|
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 -- */
|
||||||
.stacked-bar-chart {
|
.stacked-bar-chart {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -1216,6 +1235,24 @@ select:focus {
|
||||||
padding: 0.4rem 0;
|
padding: 0.4rem 0;
|
||||||
width: 1px;
|
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.js v2.6.3 | license MIT | (c) 2017, Baptiste Donaux | http://autocomplete-js.com */
|
||||||
.autocomplete {
|
.autocomplete {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -1494,23 +1531,6 @@ select:focus {
|
||||||
#main_preferences div.selectable_url pre {
|
#main_preferences div.selectable_url pre {
|
||||||
width: 100%;
|
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) {
|
@media screen and (max-width: 75em) {
|
||||||
.preferences_back {
|
.preferences_back {
|
||||||
clear: both;
|
clear: both;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,4 @@
|
||||||
/*! simple/searx.min.js | 21-04-2021 | */
|
/*! simple/searx.min.js | 23-04-2021 | */
|
||||||
|
|
||||||
(function(t,e){"use strict";var a=e.currentScript||function(){var t=e.getElementsByTagName("script");return t[t.length-1]}();t.searx={touch:"ontouchstart"in t||t.DocumentTouch&&document instanceof DocumentTouch||false,method:a.getAttribute("data-method"),autocompleter:a.getAttribute("data-autocompleter")==="true",search_on_category_select:a.getAttribute("data-search-on-category-select")==="true",infinite_scroll:a.getAttribute("data-infinite-scroll")==="true",static_path:a.getAttribute("data-static-path"),translations:JSON.parse(a.getAttribute("data-translations"))};e.getElementsByTagName("html")[0].className=t.searx.touch?"js touch":"js"})(window,document);
|
(function(t,e){"use strict";var a=e.currentScript||function(){var t=e.getElementsByTagName("script");return t[t.length-1]}();t.searx={touch:"ontouchstart"in t||t.DocumentTouch&&document instanceof DocumentTouch||false,method:a.getAttribute("data-method"),autocompleter:a.getAttribute("data-autocompleter")==="true",search_on_category_select:a.getAttribute("data-search-on-category-select")==="true",infinite_scroll:a.getAttribute("data-infinite-scroll")==="true",static_path:a.getAttribute("data-static-path"),translations:JSON.parse(a.getAttribute("data-translations"))};e.getElementsByTagName("html")[0].className=t.searx.touch?"js touch":"js"})(window,document);
|
||||||
//# sourceMappingURL=searx.head.min.js.map
|
//# sourceMappingURL=searx.head.min.js.map
|
|
@ -1,4 +1,4 @@
|
||||||
/*! simple/searx.min.js | 21-04-2021 | */
|
/*! simple/searx.min.js | 23-04-2021 | */
|
||||||
|
|
||||||
window.searx=function(t,a){"use strict";if(t.Element){(function(e){e.matches=e.matches||e.matchesSelector||e.webkitMatchesSelector||e.msMatchesSelector||function(e){var t=this,n=(t.parentNode||t.document).querySelectorAll(e),i=-1;while(n[++i]&&n[i]!=t);return!!n[i]}})(Element.prototype)}function o(e,t,n){try{e.call(t,n)}catch(e){console.log(e)}}var s=window.searx||{};s.on=function(i,e,r,t){t=t||false;if(typeof i!=="string"){i.addEventListener(e,r,t)}else{a.addEventListener(e,function(e){var t=e.target||e.srcElement,n=false;while(t&&t.matches&&t!==a&&!(n=t.matches(i)))t=t.parentElement;if(n)o(r,t,e)},t)}};s.ready=function(e){if(document.readyState!="loading"){e.call(t)}else{t.addEventListener("DOMContentLoaded",e.bind(t))}};s.http=function(e,t,n){var i=new XMLHttpRequest,r=function(){},a=function(){},o={then:function(e){r=e;return o},catch:function(e){a=e;return o}};try{i.open(e,t,true);i.onload=function(){if(i.status==200){r(i.response,i.responseType)}else{a(Error(i.statusText))}};i.onerror=function(){a(Error("Network Error"))};i.onabort=function(){a(Error("Transaction is aborted"))};i.send()}catch(e){a(e)}return o};s.loadStyle=function(e){var t=s.static_path+e,n="style_"+e.replace(".","_"),i=a.getElementById(n);if(i===null){i=a.createElement("link");i.setAttribute("id",n);i.setAttribute("rel","stylesheet");i.setAttribute("type","text/css");i.setAttribute("href",t);a.body.appendChild(i)}};s.loadScript=function(e,t){var n=s.static_path+e,i="script_"+e.replace(".","_"),r=a.getElementById(i);if(r===null){r=a.createElement("script");r.setAttribute("id",i);r.setAttribute("src",n);r.onload=t;r.onerror=function(){r.setAttribute("error","1")};a.body.appendChild(r)}else if(!r.hasAttribute("error")){try{t.apply(r,[])}catch(e){console.log(e)}}else{console.log("callback not executed : script '"+n+"' not loaded.")}};s.insertBefore=function(e,t){element.parentNode.insertBefore(e,t)};s.insertAfter=function(e,t){t.parentNode.insertBefore(e,t.nextSibling)};s.on(".close","click",function(e){var t=e.target||e.srcElement;this.parentNode.classList.add("invisible")});return s}(window,document);(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.AutoComplete=e()}})(function(){var e,t,n;return function a(o,s,l){function u(n,e){if(!s[n]){if(!o[n]){var t=typeof require=="function"&&require;if(!e&&t)return t(n,!0);if(c)return c(n,!0);var i=new Error("Cannot find module '"+n+"'");throw i.code="MODULE_NOT_FOUND",i}var r=s[n]={exports:{}};o[n][0].call(r.exports,function(e){var t=o[n][1][e];return u(t?t:e)},r,r.exports,a,o,s,l)}return s[n].exports}var c=typeof require=="function"&&require;for(var e=0;e<l.length;e++)u(l[e]);return u}({1:[function(e,t,n){
|
window.searx=function(t,a){"use strict";if(t.Element){(function(e){e.matches=e.matches||e.matchesSelector||e.webkitMatchesSelector||e.msMatchesSelector||function(e){var t=this,n=(t.parentNode||t.document).querySelectorAll(e),i=-1;while(n[++i]&&n[i]!=t);return!!n[i]}})(Element.prototype)}function o(e,t,n){try{e.call(t,n)}catch(e){console.log(e)}}var s=window.searx||{};s.on=function(i,e,r,t){t=t||false;if(typeof i!=="string"){i.addEventListener(e,r,t)}else{a.addEventListener(e,function(e){var t=e.target||e.srcElement,n=false;while(t&&t.matches&&t!==a&&!(n=t.matches(i)))t=t.parentElement;if(n)o(r,t,e)},t)}};s.ready=function(e){if(document.readyState!="loading"){e.call(t)}else{t.addEventListener("DOMContentLoaded",e.bind(t))}};s.http=function(e,t,n){var i=new XMLHttpRequest,r=function(){},a=function(){},o={then:function(e){r=e;return o},catch:function(e){a=e;return o}};try{i.open(e,t,true);i.onload=function(){if(i.status==200){r(i.response,i.responseType)}else{a(Error(i.statusText))}};i.onerror=function(){a(Error("Network Error"))};i.onabort=function(){a(Error("Transaction is aborted"))};i.send()}catch(e){a(e)}return o};s.loadStyle=function(e){var t=s.static_path+e,n="style_"+e.replace(".","_"),i=a.getElementById(n);if(i===null){i=a.createElement("link");i.setAttribute("id",n);i.setAttribute("rel","stylesheet");i.setAttribute("type","text/css");i.setAttribute("href",t);a.body.appendChild(i)}};s.loadScript=function(e,t){var n=s.static_path+e,i="script_"+e.replace(".","_"),r=a.getElementById(i);if(r===null){r=a.createElement("script");r.setAttribute("id",i);r.setAttribute("src",n);r.onload=t;r.onerror=function(){r.setAttribute("error","1")};a.body.appendChild(r)}else if(!r.hasAttribute("error")){try{t.apply(r,[])}catch(e){console.log(e)}}else{console.log("callback not executed : script '"+n+"' not loaded.")}};s.insertBefore=function(e,t){element.parentNode.insertBefore(e,t)};s.insertAfter=function(e,t){t.parentNode.insertBefore(e,t.nextSibling)};s.on(".close","click",function(e){var t=e.target||e.srcElement;this.parentNode.classList.add("invisible")});return s}(window,document);(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.AutoComplete=e()}})(function(){var e,t,n;return function a(o,s,l){function u(n,e){if(!s[n]){if(!o[n]){var t=typeof require=="function"&&require;if(!e&&t)return t(n,!0);if(c)return c(n,!0);var i=new Error("Cannot find module '"+n+"'");throw i.code="MODULE_NOT_FOUND",i}var r=s[n]={exports:{}};o[n][0].call(r.exports,function(e){var t=o[n][1][e];return u(t?t:e)},r,r.exports,a,o,s,l)}return s[n].exports}var c=typeof require=="function"&&require;for(var e=0;e<l.length;e++)u(l[e]);return u}({1:[function(e,t,n){
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -94,24 +94,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 75em) {
|
@media screen and (max-width: 75em) {
|
||||||
|
|
|
@ -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 -- */
|
||||||
.stacked-bar-chart {
|
.stacked-bar-chart {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -532,3 +551,17 @@ select {
|
||||||
padding: 0.4rem 0;
|
padding: 0.4rem 0;
|
||||||
width: 1px;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,45 +1,97 @@
|
||||||
{% extends "oscar/base.html" %}
|
{% extends "oscar/base.html" %}
|
||||||
{% block styles %}
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/charts.min.css') }}" type="text/css" />
|
|
||||||
<style>
|
|
||||||
#engine-times {
|
|
||||||
--labels-size: 20rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#engine-times th {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
|
||||||
{% block title %}{{ _('stats') }} - {% endblock %}
|
{% block title %}{{ _('stats') }} - {% endblock %}
|
||||||
|
|
||||||
|
{%- macro th_sort(column_order, column_name) -%}
|
||||||
|
{% if column_order==sort_order %}
|
||||||
|
{{ column_name }} {{ icon('chevron-down') }}
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ url_for('stats', sort=column_order) }}">{{ column_name }}
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro -%}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<h1>{{ _('Engine stats') }}</h1>
|
<h1>{{ _('Engine stats') }}</h1>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% for stat_name,stat_category in stats %}
|
<div class="col-xs-12 col-sm-12 col-md-12">
|
||||||
<div class="col-xs-12 col-sm-12 col-md-6">
|
<div class="table-responsive">
|
||||||
<h3>{{ stat_name }}</h3>
|
{% if not engine_stats.get('time') %}
|
||||||
<div class="container-fluid">
|
<div class="col-sm-12 col-md-12">
|
||||||
{% for engine in stat_category %}
|
{% include 'oscar/messages/no_data_available.html' %}
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-4 col-md-4">{{ engine.name }}</div>
|
|
||||||
<div class="col-sm-8 col-md-8">
|
|
||||||
<div class="progress">
|
|
||||||
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="{{ '%i'|format(engine.avg) }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ engine.percentage }}%;">
|
|
||||||
{{ '%.02f'|format(engine.avg) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% else %}
|
||||||
{% endfor %}
|
<table class="table table-hover table-condensed table-striped">
|
||||||
{% if not stat_category %}
|
<tr>
|
||||||
<div class="col-sm-12 col-md-12">
|
<th scope="col" style="width:20rem;">{{ th_sort('name', _("Engine name")) }}</th>
|
||||||
{% include 'oscar/messages/no_data_available.html' %}
|
<th scope="col" style="width:7rem; text-align: right;">{{ th_sort('score', _('Scores')) }}</th>
|
||||||
</div>
|
<th scope="col">{{ th_sort('result_count', _('Result count')) }}</th>
|
||||||
|
<th scope="col">{{ th_sort('time', _('Response time')) }}</th>
|
||||||
|
<th scope="col" style="text-align: right;">{{ th_sort('reliability', _('Reliability')) }}</th>
|
||||||
|
</tr>
|
||||||
|
{% for engine_stat in engine_stats.get('time', []) %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ engine_stat.name }}</td>
|
||||||
|
<td style="text-align: right;">
|
||||||
|
{% if engine_stat.score %}
|
||||||
|
<span aria-labelledby="{{engine_stat.name}}_score" >{{ engine_stat.score|round(1) }}</span>
|
||||||
|
<div class="engine-tooltip text-left" role="tooltip" id="{{engine_stat.name}}_score">{{- "" -}}
|
||||||
|
<p>{{ _('Scores per result') }}: {{ engine_stat.score_per_result | round(3) }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{%- if engine_stat.result_count -%}
|
||||||
|
<span class="stacked-bar-chart-value">{{- engine_stat.result_count | int -}}</span>{{- "" -}}
|
||||||
|
<span class="stacked-bar-chart" aria-hidden="true">{{- "" -}}
|
||||||
|
<span style="width: calc(max(2px, 100%*{{ (engine_stat.result_count / engine_stats.max_result_count )|round(3) }}))" class="stacked-bar-chart-serie1"></span>{{- "" -}}
|
||||||
|
</span>
|
||||||
|
{%- endif -%}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{%- if engine_stat.total -%}
|
||||||
|
<span class="stacked-bar-chart-value">{{- engine_stat.total | round(1) -}}</span>{{- "" -}}
|
||||||
|
<span class="stacked-bar-chart" aria-labelledby="{{engine_stat.name}}_time" aria-hidden="true">{{- "" -}}
|
||||||
|
<span style="width: calc(max(2px, 100%*{{ (engine_stat.http / engine_stats.max_time )|round(3) }}))" class="stacked-bar-chart-serie1"></span>{{- "" -}}
|
||||||
|
<span style="width: calc(100%*{{ engine_stat.processing / engine_stats.max_time |round(3) }})" class="stacked-bar-chart-serie2"></span>{{- "" -}}
|
||||||
|
</span>{{- "" -}}
|
||||||
|
<div class="engine-tooltip text-left" role="tooltip" id="{{engine_stat.name}}_time">{{- "" -}}
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tr>
|
||||||
|
<th scope="col"></th>
|
||||||
|
<th scope="col">{{ _('Total') }}</th>
|
||||||
|
<th scope="col">{{ _('HTTP') }}</th>
|
||||||
|
<th scope="col">{{ _('Processing') }}</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{{ _('Median') }}</th>
|
||||||
|
<td>{{ engine_stat.total }}</td>
|
||||||
|
<td>{{ engine_stat.http }}</td>
|
||||||
|
<td>{{ engine_stat.processing }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{{ _('P80') }}</th>
|
||||||
|
<td>{{ engine_stat.total_p80 }}</td>
|
||||||
|
<td>{{ engine_stat.http_p80 }}</td>
|
||||||
|
<td>{{ engine_stat.processing_p80 }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{{ _('P95') }}</th>
|
||||||
|
<td>{{ engine_stat.total_p95 }}</td>
|
||||||
|
<td>{{ engine_stat.http_p95 }}</td>
|
||||||
|
<td>{{ engine_stat.processing_p95 }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
</td>
|
||||||
|
<td style="text-align: right;"> {{ engine_reliabilities.get(engine_stat.name, {}).get('reliablity') }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,4 +1,15 @@
|
||||||
|
{% from 'simple/macros.html' import icon %}
|
||||||
|
|
||||||
{% extends "simple/base.html" %}
|
{% extends "simple/base.html" %}
|
||||||
|
|
||||||
|
{%- macro th_sort(column_order, column_name) -%}
|
||||||
|
{% if column_order==sort_order %}
|
||||||
|
{{ column_name }} {{ icon('arrow-dropdown') }}
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ url_for('stats', sort=column_order) }}">{{ column_name }}
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro -%}
|
||||||
|
|
||||||
{% block head %} {% endblock %}
|
{% block head %} {% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
@ -6,20 +17,77 @@
|
||||||
|
|
||||||
<h2>{{ _('Engine stats') }}</h2>
|
<h2>{{ _('Engine stats') }}</h2>
|
||||||
|
|
||||||
{% for stat_name,stat_category in stats %}
|
{% if not engine_stats.get('time') %}
|
||||||
<div class="left">
|
{{ _('There is currently no data available. ') }}
|
||||||
<table>
|
{% else %}
|
||||||
<tr colspan="3">
|
<table style="max-width: 1280px; margin: 0 auto;">
|
||||||
<th>{{ stat_name }}</th>
|
<tr>
|
||||||
</tr>
|
<th scope="col" style="width:20rem;">{{ th_sort('name', _("Engine name")) }}</th>
|
||||||
{% for engine in stat_category %}
|
<th scope="col" style="width:7rem; text-align: right;">{{ th_sort('score', _('Scores')) }}</th>
|
||||||
<tr>
|
<th scope="col">{{ th_sort('result_count', _('Result count')) }}</th>
|
||||||
<td>{{ engine.name }}</td>
|
<th scope="col">{{ th_sort('time', _('Response time')) }}</th>
|
||||||
<td>{{ '%.02f'|format(engine.avg) }}</td>
|
<th scope="col" style="text-align: right;">{{ th_sort('reliability', _('Reliability')) }}</th>
|
||||||
<td class="percentage"><div style="width: {{ engine.percentage }}%"> </div></td>
|
</tr>
|
||||||
</tr>
|
{% for engine_stat in engine_stats.get('time', []) %}
|
||||||
{% endfor %}
|
<tr>
|
||||||
</table>
|
<td>{{ engine_stat.name }}</td>
|
||||||
</div>
|
<td style="text-align: right;">
|
||||||
{% endfor %}
|
{% if engine_stat.score %}
|
||||||
|
<span aria-labelledby="{{engine_stat.name}}_score" >{{ engine_stat.score|round(1) }}</span>
|
||||||
|
<div class="engine-tooltip" role="tooltip" id="{{engine_stat.name}}_score">{{- "" -}}
|
||||||
|
<p>{{ _('Scores per result') }}: {{ engine_stat.score_per_result | round(3) }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{%- if engine_stat.result_count -%}
|
||||||
|
<span class="stacked-bar-chart-value">{{- engine_stat.result_count | int -}}</span>{{- "" -}}
|
||||||
|
<span class="stacked-bar-chart" aria-hidden="true">{{- "" -}}
|
||||||
|
<span style="width: calc(max(2px, 100%*{{ (engine_stat.result_count / engine_stats.max_result_count )|round(3) }}))" class="stacked-bar-chart-serie1"></span>{{- "" -}}
|
||||||
|
</span>
|
||||||
|
{%- endif -%}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{%- if engine_stat.total -%}
|
||||||
|
<span class="stacked-bar-chart-value">{{- engine_stat.total | round(1) -}}</span>{{- "" -}}
|
||||||
|
<span class="stacked-bar-chart" aria-labelledby="{{engine_stat.name}}_time" aria-hidden="true">{{- "" -}}
|
||||||
|
<span style="width: calc(max(2px, 100%*{{ (engine_stat.http / engine_stats.max_time )|round(3) }}))" class="stacked-bar-chart-serie1"></span>{{- "" -}}
|
||||||
|
<span style="width: calc(100%*{{ engine_stat.processing / engine_stats.max_time |round(3) }})" class="stacked-bar-chart-serie2"></span>{{- "" -}}
|
||||||
|
</span>{{- "" -}}
|
||||||
|
<div class="engine-tooltip" role="tooltip" id="{{engine_stat.name}}_time">{{- "" -}}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th scope="col"></th>
|
||||||
|
<th scope="col">{{ _('Total') }}</th>
|
||||||
|
<th scope="col">{{ _('HTTP') }}</th>
|
||||||
|
<th scope="col">{{ _('Processing') }}</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{{ _('Median') }}</th>
|
||||||
|
<td>{{ engine_stat.total }}</td>
|
||||||
|
<td>{{ engine_stat.http }}</td>
|
||||||
|
<td>{{ engine_stat.processing }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{{ _('P80') }}</th>
|
||||||
|
<td>{{ engine_stat.total_p80 }}</td>
|
||||||
|
<td>{{ engine_stat.http_p80 }}</td>
|
||||||
|
<td>{{ engine_stat.processing_p80 }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{{ _('P95') }}</th>
|
||||||
|
<td>{{ engine_stat.total_p95 }}</td>
|
||||||
|
<td>{{ engine_stat.http_p95 }}</td>
|
||||||
|
<td>{{ engine_stat.processing_p95 }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
</td>
|
||||||
|
<td style="text-align: right;"> {{ engine_reliabilities.get(engine_stat.name, {}).get('reliablity') }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -93,7 +93,7 @@ from searx.preferences import Preferences, ValidationException, LANGUAGE_CODES
|
||||||
from searx.answerers import answerers
|
from searx.answerers import answerers
|
||||||
from searx.network import stream as http_stream
|
from searx.network import stream as http_stream
|
||||||
from searx.answerers import ask
|
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
|
# serve pages with HTTP/1.1
|
||||||
from werkzeug.serving import WSGIRequestHandler
|
from werkzeug.serving import WSGIRequestHandler
|
||||||
|
@ -1073,16 +1073,47 @@ def image_proxy():
|
||||||
@app.route('/stats', methods=['GET'])
|
@app.route('/stats', methods=['GET'])
|
||||||
def stats():
|
def stats():
|
||||||
"""Render engine statistics page."""
|
"""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()))
|
filtered_engines = dict(filter(lambda kv: (kv[0], request.preferences.validate_token(kv[1])), engines.items()))
|
||||||
engine_stats = get_engines_stats(filtered_engines)
|
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(
|
return render(
|
||||||
'stats.html',
|
'stats.html',
|
||||||
stats=[(gettext('Engine time (sec)'), engine_stats['time_total']),
|
sort_order=sort_order,
|
||||||
(gettext('Page loads (sec)'), engine_stats['time_http']),
|
engine_stats=engine_stats,
|
||||||
(gettext('Number of results'), engine_stats['result_count']),
|
engine_reliabilities=engine_reliabilities,
|
||||||
(gettext('Scores'), engine_stats['scores']),
|
|
||||||
(gettext('Scores per result'), engine_stats['scores_per_result']),
|
|
||||||
(gettext('Errors'), engine_stats['error_count'])]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue