summaryrefslogtreecommitdiff
path: root/searx
diff options
context:
space:
mode:
authorAlexandre Flament <alex@al-f.net>2021-04-23 21:08:48 +0200
committerAlexandre Flament <alex@al-f.net>2021-04-25 14:28:06 +0200
commitdf41b7712150adf384bc08e38215a7cc9970c100 (patch)
treee03332896d7941c9d3432164fd8fa541d4f8ece5 /searx
parent0603b043ceadbc833410464bbf576fda8c11dc97 (diff)
[mod] /stats : detail per engine
allow to submit a github issue including the technical details (exceptions, errors, warning, checker result)
Diffstat (limited to 'searx')
-rw-r--r--searx/__init__.py4
-rw-r--r--searx/metrics/__init__.py2
-rw-r--r--searx/settings.yml1
-rw-r--r--searx/templates/__common__/new_issue.html74
-rw-r--r--searx/templates/oscar/stats.html82
-rw-r--r--searx/templates/simple/stats.html70
-rwxr-xr-xsearx/webapp.py14
7 files changed, 227 insertions, 20 deletions
diff --git a/searx/__init__.py b/searx/__init__.py
index 11adbba7..71e00a49 100644
--- a/searx/__init__.py
+++ b/searx/__init__.py
@@ -89,6 +89,10 @@ class _brand_namespace:
return self.get_val('brand', 'issue_url')
@property
+ def NEW_ISSUE_URL(self):
+ return self.get_val('brand', 'new_issue_url')
+
+ @property
def DOCS_URL(self):
return self.get_val('brand', 'docs_url')
diff --git a/searx/metrics/__init__.py b/searx/metrics/__init__.py
index adcb47ae..6ed57811 100644
--- a/searx/metrics/__init__.py
+++ b/searx/metrics/__init__.py
@@ -150,7 +150,7 @@ def get_reliabilities(engline_name_list, checker_results):
reliabilities[engine_name] = {
'reliablity': reliablity,
'errors': errors,
- 'checker': checker_results.get(engine_name, {}).get('errors', {}).keys(),
+ 'checker': checker_results.get(engine_name, {}).get('errors', {}),
}
return reliabilities
diff --git a/searx/settings.yml b/searx/settings.yml
index 6e106a46..13163c7e 100644
--- a/searx/settings.yml
+++ b/searx/settings.yml
@@ -7,6 +7,7 @@ brand:
git_url: https://github.com/searxng/searxng
git_branch: master
issue_url: https://github.com/searxng/searxng/issues
+ new_issue_url: https://github.com/searxng/searxng/issues/new
docs_url: https://searxng.github.io/searxng
public_instances: https://searx.space
wiki_url: https://github.com/searxng/searxng/wiki
diff --git a/searx/templates/__common__/new_issue.html b/searx/templates/__common__/new_issue.html
new file mode 100644
index 00000000..2a111a52
--- /dev/null
+++ b/searx/templates/__common__/new_issue.html
@@ -0,0 +1,74 @@
+{% macro new_issue(new_issue_url, engine_name, engine_reliability) %}
+<form action="{{ new_issue_url }}" method="GET">
+ <input name="title" type="hidden" value="Bug: {{ engine_name }} engine">
+ <input name="labels" type="hidden" value="bug">
+ <input name="template" type="hidden" value="bug-report.md">
+ <textarea name="body" style="display: none;">{{- '' -}}
+
+**Version of SearXNG, commit number if you are using on master branch and stipulate if you forked SearXNG**
+<!-- If you are running on master branch using git execute this command
+in order to fetch the latest commit ID:
+```
+git log -1
+```
+If you are using searx-docker then look at the bottom of the SearXNG page
+and check for the version after "Powered by SearXNG"
+
+Please also stipulate if you are using a forked version of SearxNG and
+include a link to the fork source code.
+-->
+**How did you install SearXNG?**
+<!-- Did you install SearXNG using the official wiki or using searx-docker
+or manually by executing the searx/webapp.py file? -->
+**What happened?**
+<!-- A clear and concise description of what the bug is. -->
+
+**How To Reproduce**
+<!-- How can we reproduce this issue? (as minimally and as precisely as possible) -->
+
+**Expected behavior**
+<!-- A clear and concise description of what you expected to happen. -->
+
+**Screenshots & Logs**
+<!-- If applicable, add screenshots, logs to help explain your problem. -->
+
+**Additional context**
+<!-- Add any other context about the problem here. -->
+
+**Technical report**
+
+{% for error in engine_reliability.errors %}
+{% if secondary %}Warning{% else %}Error{% endif %}
+{{'\n '}}* Error: {{ error.exception_classname or error.log_message }}
+{{' '}}* Percentage: {{ error.percentage }}
+{{' '}}* Parameters: `{{ error.log_parameters }}`
+{{' '}}* File name: `{{ error.filename }}:{{ error.line_no }}`
+{{' '}}* Function: `{{ error.function }}`
+{{' '}}* Code: `{{ error.code }}`
+{{'\n'-}}
+{%- endfor -%}
+{%- for test_name, results in engine_reliability.checker.items() -%}
+{%- if loop.first %}Checker{% endif -%}
+{{-'\n '}}* {{ test_name }}: {% for result in results%}`{{ result }}`,{% endfor -%}
+{%- endfor -%}
+ </textarea>
+ <style>
+ .github-issue-button {
+ display: block;
+ padding: 8px 16px;
+ font-family: sans-serif;
+ font-size: 16px;
+ color: white;
+ background-color: rgb(35, 134, 54);
+ border: rgb(46, 160, 67);
+ border-radius: 10px !important;
+ box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;
+ }
+
+ .github-issue-button:hover {
+ background-color: rgb(46, 160, 67);
+ }
+ </style>
+ <button type="submit" class="github-issue-button" title="{{ new_issue_url }}">{{ _('Submit a new issue on Github including the above information') }}</button>
+</form>
+{% endmacro %}
diff --git a/searx/templates/oscar/stats.html b/searx/templates/oscar/stats.html
index b8371402..49c776ea 100644
--- a/searx/templates/oscar/stats.html
+++ b/searx/templates/oscar/stats.html
@@ -1,18 +1,21 @@
-{% extends "oscar/base.html" %}
+{% extends 'oscar/base.html' %}
+{% from '__common__/new_issue.html' import new_issue %}
-{% block title %}{{ _('stats') }} - {% endblock %}
+{% block title %}{{ _('stats') }} - {% if selected_engine_name %} {{ selected_engine_name }} - {% endif %}{% 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 %}
+ {%- if selected_engine_name -%}
+ {{ column_name }}
+ {%- elif column_order==sort_order -%}
+ {{ column_name }} {{ icon('arrow-dropdown') }}
+ {%- else -%}
+ <a href="{{ url_for('stats', sort=column_order) }}">{{ column_name }}</a>
+ {%- endif -%}
{%- endmacro -%}
{% block content %}
<div class="container-fluid">
- <h1>{{ _('Engine stats') }}</h1>
+ <h1>{{ _('Engine stats') }}{% if selected_engine_name %} - {{ selected_engine_name }}{% endif %}</h1>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="table-responsive">
@@ -31,14 +34,14 @@
</tr>
{% for engine_stat in engine_stats.get('time', []) %}
<tr>
- <td>{{ engine_stat.name }}</td>
+ <td><a href="{{ url_for('stats', engine=engine_stat.name|e) }}">{{ engine_stat.name }}</a></td>
<td style="text-align: right;">
- {% if engine_stat.score %}
+ {%- 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 %}
+ {%- endif -%}
</td>
<td>
{%- if engine_stat.result_count -%}
@@ -92,6 +95,63 @@
{% endif %}
</div>
</div>
+ <div class="col-xs-12 col-sm-12 col-md-12">
+ {% if selected_engine_name %}
+ {% for secondary in [False, True] %}
+ {% set ns = namespace(first=true) %}
+ {% for error in engine_reliabilities[selected_engine_name].errors %}
+ {% if secondary == error.secondary %}
+ {% if ns.first %}
+ {% set ns.first = false %}
+ <h3>{% if secondary %}{{ _('Warnings') }}{% else %}{{ _('Errors and exceptions') }}{% endif %}</h3>
+ {% endif %}
+ <table class="table table-striped table-bordered">
+ <tbody style="padding-top: 1rem;">
+ <tr>
+ {%- if error.exception_classname -%}
+ <th scope="row" style="width: 10rem">{{ _('Exception') }}</th><td>{{ error.exception_classname }}</td>
+ {%- elif error.log_message -%}
+ <th scope="row" style="width: 10rem">{{ _('Message') }}</th><td>{{ error.log_message }}</td>
+ {%- endif -%}
+ <th scope="row" style="width: 10rem">{{ _('Percentage') }}</th><td style="width: 10rem">{{ error.percentage }}</td>
+ </tr>
+ {% if error.log_parameters and error.log_parameters != (None, None, None) %}<tr><th scope="row">{{ _('Parameter') }}</th>{{- '' -}}
+ <td colspan="3">
+ {%- for param in error.log_parameters -%}
+ <span style="border-right: 1px solid gray; padding: 0 1rem 0 0; margin: 0 0 0 0.5rem;">{{ param }}</span>
+ {%- endfor -%}
+ </td>
+ </tr>
+ {% endif %}
+ <tr><th scope="row">{{ _('Filename') }}</th><td colspan="3">{{ error.filename }}:{{ error.line_no }}</td></tr>
+ <tr><th scope="row">{{ _('Function') }}</th><td colspan="3">{{ error.function }}</td></tr>
+ <tr><th scope="row">{{ _('Code') }}</th><td colspan="3">{{ error.code }}</td></tr>
+ </tbody>
+ </table>
+ {% endif %}
+ {% endfor %}
+ {% endfor %}
+ {% if engine_reliabilities[selected_engine_name].checker %}
+ <h3>{{ _('Checker') }}</h3>
+ <table class="table table-striped table-bordered">
+ <tr>
+ <th scope="col" style="width: 10rem">{{ _('Failed test') }}</th>
+ <th scope="col">{{ _('Comment(s)') }}</th>
+ </tr>
+ {% for test_name, results in engine_reliabilities[selected_engine_name].checker.items() %}
+ <tr>
+ <td>{{ test_name }}</td>
+ <td>
+ {% for r in results %}<p>{{ r }}</p>{% endfor %}
+ </td>
+ </tr>
+ {% endfor %}
+ </table>
+ {% endif %}
+ {{ new_issue(brand.NEW_ISSUE_URL, selected_engine_name, engine_reliabilities[selected_engine_name]) }}
+ {% endif %}
+ </div>
</div>
</div>
+
{% endblock %}
diff --git a/searx/templates/simple/stats.html b/searx/templates/simple/stats.html
index eecd8890..098a5406 100644
--- a/searx/templates/simple/stats.html
+++ b/searx/templates/simple/stats.html
@@ -1,12 +1,15 @@
{% from 'simple/macros.html' import icon %}
+{% from '__common__/new_issue.html' import new_issue %}
{% extends "simple/base.html" %}
{%- macro th_sort(column_order, column_name) -%}
- {% if column_order==sort_order %}
+ {% if selected_engine_name %}
+ {{ column_name }}
+ {% elif column_order==sort_order %}
{{ column_name }} {{ icon('arrow-dropdown') }}
{% else %}
- <a href="{{ url_for('stats', sort=column_order) }}">{{ column_name }}
+ <a href="{{ url_for('stats', sort=column_order) }}">{{ column_name }}</a>
{% endif %}
{%- endmacro -%}
@@ -15,12 +18,12 @@
<a href="{{ url_for('index') }}"><h1><span>searx</span></h1></a>
-<h2>{{ _('Engine stats') }}</h2>
+<h2>{{ _('Engine stats') }}{% if selected_engine_name %} - {{ selected_engine_name }}{% endif %}</h2>
{% if not engine_stats.get('time') %}
{{ _('There is currently no data available. ') }}
{% else %}
-<table style="max-width: 1280px; margin: 0 auto;">
+<table style="max-width: 1280px; margin: 0 auto 0 0;">
<tr>
<th scope="col" style="width:20rem;">{{ th_sort('name', _("Engine name")) }}</th>
<th scope="col" style="width:7rem; text-align: right;">{{ th_sort('score', _('Scores')) }}</th>
@@ -30,7 +33,7 @@
</tr>
{% for engine_stat in engine_stats.get('time', []) %}
<tr>
- <td>{{ engine_stat.name }}</td>
+ <td><a href="{{ url_for('stats', engine=engine_stat.name|e) }}">{{ engine_stat.name }}</a></td>
<td style="text-align: right;">
{% if engine_stat.score %}
<span aria-labelledby="{{engine_stat.name}}_score" >{{ engine_stat.score|round(1) }}</span>
@@ -90,4 +93,61 @@
</table>
{% endif %}
+<div>
+ {% if selected_engine_name %}
+ {% for secondary in [False, True] %}
+ {% set ns = namespace(first=true) %}
+ {% for error in engine_reliabilities[selected_engine_name].errors %}
+ {% if secondary == error.secondary %}
+ {% if ns.first %}
+ {% set ns.first = false %}
+ <h3>{% if secondary %}{{ _('Warnings') }}{% else %}{{ _('Errors and exceptions') }}{% endif %}</h3>
+ {% endif %}
+ <table style="max-width: 1280px; margin: 1rem; border: 1px solid gray;">
+ <tbody style="padding-top: 1rem;">
+ <tr>
+ {%- if error.exception_classname -%}
+ <th scope="row" style="width: 10rem">{{ _('Exception') }}</th><td>{{ error.exception_classname }}</td>
+ {%- elif error.log_message -%}
+ <th scope="row" style="width: 10rem">{{ _('Message') }}</th><td>{{ error.log_message }}</td>
+ {%- endif -%}
+ <th scope="row" style="width: 10rem">{{ _('Percentage') }}</th><td style="width: 10rem">{{ error.percentage }}</td>
+ </tr>
+ {% if error.log_parameters and error.log_parameters != (None, None, None) %}<tr><th scope="row">{{ _('Parameter') }}</th>{{- '' -}}
+ <td colspan="3">
+ {%- for param in error.log_parameters -%}
+ <span style="border-right: 1px solid gray; padding: 0 1rem 0 0; margin: 0 0 0 0.5rem;">{{ param }}</span>
+ {%- endfor -%}
+ </td>
+ </tr>
+ {% endif %}
+ <tr><th scope="row">{{ _('Filename') }}</th><td colspan="3">{{ error.filename }}:{{ error.line_no }}</td></tr>
+ <tr><th scope="row">{{ _('Function') }}</th><td colspan="3">{{ error.function }}</td></tr>
+ <tr><th scope="row">{{ _('Code') }}</th><td colspan="3">{{ error.code }}</td></tr>
+ </tbody>
+ </table>
+ {% endif %}
+ {% endfor %}
+ {% endfor %}
+ {% if engine_reliabilities[selected_engine_name].checker %}
+ <h3>{{ _('Checker') }}</h3>
+ <table>
+ <tr>
+ <th scope="col" style="width: 10rem">{{ _('Failed test') }}</th>
+ <th scope="col">{{ _('Comment(s)') }}</th>
+ </tr>
+ {% for test_name, results in engine_reliabilities[selected_engine_name].checker.items() %}
+ <tr>
+ <td>{{ test_name }}</td>
+ <td>
+ {% for r in results %}<p>{{ r }}</p>{% endfor %}
+ </td>
+ </tr>
+ {% endfor %}
+ </table>
+ {% endif %}
+ {{ new_issue(brand.NEW_ISSUE_URL, selected_engine_name, engine_reliabilities[selected_engine_name]) }}
+ {% endif %}
+</div>
+
{% endblock %}
diff --git a/searx/webapp.py b/searx/webapp.py
index d917c16d..69ec915a 100755
--- a/searx/webapp.py
+++ b/searx/webapp.py
@@ -1073,16 +1073,23 @@ def image_proxy():
@app.route('/stats', methods=['GET'])
def stats():
"""Render engine statistics page."""
+ sort_order = request.args.get('sort', default='name', type=str)
+ selected_engine_name = request.args.get('engine', default=None, type=str)
+
+ filtered_engines = dict(filter(lambda kv: (kv[0], request.preferences.validate_token(kv[1])), engines.items()))
+ if selected_engine_name:
+ if selected_engine_name not in filtered_engines:
+ selected_engine_name = None
+ else:
+ filtered_engines = [selected_engine_name]
+
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),
@@ -1114,6 +1121,7 @@ def stats():
sort_order=sort_order,
engine_stats=engine_stats,
engine_reliabilities=engine_reliabilities,
+ selected_engine_name=selected_engine_name,
)