diff options
| -rw-r--r-- | asset-sources/theme.scss | 35 | ||||
| -rw-r--r-- | fietsboek/__init__.py | 3 | ||||
| -rw-r--r-- | fietsboek/locale/de/LC_MESSAGES/messages.mo | bin | 21619 -> 21673 bytes | |||
| -rw-r--r-- | fietsboek/locale/de/LC_MESSAGES/messages.po | 22 | ||||
| -rw-r--r-- | fietsboek/locale/en/LC_MESSAGES/messages.mo | bin | 20345 -> 20386 bytes | |||
| -rw-r--r-- | fietsboek/locale/en/LC_MESSAGES/messages.po | 22 | ||||
| -rw-r--r-- | fietsboek/locale/fietslog.pot | 18 | ||||
| -rw-r--r-- | fietsboek/log.py | 48 | ||||
| -rw-r--r-- | fietsboek/routes.py | 1 | ||||
| -rw-r--r-- | fietsboek/static/theme.css | 34 | ||||
| -rw-r--r-- | fietsboek/static/theme.css.map | 2 | ||||
| -rw-r--r-- | fietsboek/templates/admin.jinja2 | 1 | ||||
| -rw-r--r-- | fietsboek/templates/admin_logs.jinja2 | 46 | ||||
| -rw-r--r-- | fietsboek/views/admin.py | 10 |
14 files changed, 213 insertions, 29 deletions
diff --git a/asset-sources/theme.scss b/asset-sources/theme.scss index e8ed1a5..fbb836e 100644 --- a/asset-sources/theme.scss +++ b/asset-sources/theme.scss @@ -420,7 +420,10 @@ strong { #adminContainer { display: grid; grid-template-areas: "sidebar main"; - grid-template-columns: 1fr 5fr; + /* Use minmax() to force fr to be an actual size, and not just split the + * "remaining size". + */ + grid-template-columns: minmax(0px, 1fr) minmax(0px, 5fr); gap: 1rem; } @@ -436,6 +439,36 @@ strong { font-size: 120%; } +.logview { + background-color: white; + border-radius: 0.375rem; + padding: 0.375rem; +} + +.logline { + font-family: monospace; + + td { + padding-right: 1em; + } +} + +.logline-debug { + color: #444; +} + +.logline-info { + color: #00c; +} + +.logline-warning { + color: #990; +} + +.logline-error { + color: #c00; +} + .list-group.list-group-root { padding: 0; overflow: hidden; diff --git a/fietsboek/__init__.py b/fietsboek/__init__.py index b2af484..519cdce 100644 --- a/fietsboek/__init__.py +++ b/fietsboek/__init__.py @@ -33,6 +33,7 @@ from pyramid.session import SignedCookieSessionFactory from . import config as mod_config from . import fstrans from . import jinja2 as mod_jinja2 +from . import log as mod_log from . import transformers from .data import DataManager from .pages import Pages @@ -164,6 +165,8 @@ def main(global_config, **settings): from .osm import OverpassApi from .views.tileproxy import TileRequester + mod_log.install() + # In tests this isn't passed, so guard against it if "__file__" in global_config: check_update_state(global_config["__file__"]) diff --git a/fietsboek/locale/de/LC_MESSAGES/messages.mo b/fietsboek/locale/de/LC_MESSAGES/messages.mo Binary files differindex 2cd5007..4376c91 100644 --- a/fietsboek/locale/de/LC_MESSAGES/messages.mo +++ b/fietsboek/locale/de/LC_MESSAGES/messages.mo diff --git a/fietsboek/locale/de/LC_MESSAGES/messages.po b/fietsboek/locale/de/LC_MESSAGES/messages.po index 552880f..27e798b 100644 --- a/fietsboek/locale/de/LC_MESSAGES/messages.po +++ b/fietsboek/locale/de/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-10-01 13:36+0200\n" +"POT-Creation-Date: 2026-10-15 00:03+0200\n" "PO-Revision-Date: 2022-07-02 17:35+0200\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language: de\n" @@ -18,11 +18,11 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.18.0\n" -#: fietsboek/actions.py:269 +#: fietsboek/actions.py:271 msgid "email.verify_mail.subject" msgstr "Fietsboek Konto Bestätigung" -#: fietsboek/actions.py:272 +#: fietsboek/actions.py:274 msgid "email.verify.text" msgstr "" "Um Dein Fietsboek-Konto zu bestätigen, nutze diesen Link: {}\n" @@ -145,6 +145,10 @@ msgstr "Übersicht" msgid "page.admin.nav.badges" msgstr "Wappen" +#: fietsboek/templates/admin.jinja2:12 +msgid "page.admin.nav.logs" +msgstr "Ereignisprotokoll" + #: fietsboek/templates/admin_badges.jinja2:5 msgid "page.admin.badges" msgstr "Wappen" @@ -551,8 +555,8 @@ msgstr "Schlagwörter" #: fietsboek/templates/details.jinja2:111 msgid "page.details.background_tasks_in_progress" msgstr "" -"Hintergrundaufgaben für diese Strecke sind noch nicht abgeschlossen. " -"Die angezeigten Informationen sind noch unvollständig." +"Hintergrundaufgaben für diese Strecke sind noch nicht abgeschlossen. Die " +"angezeigten Informationen sind noch unvollständig." #: fietsboek/templates/details.jinja2:121 fietsboek/templates/edit.jinja2:10 #: fietsboek/templates/finish_upload.jinja2:10 @@ -1250,15 +1254,15 @@ msgstr "Ungültige E-Mail-Adresse" msgid "flash.a_confirmation_link_has_been_sent" msgstr "Ein Bestätigungslink wurde versandt" -#: fietsboek/views/admin.py:189 +#: fietsboek/views/admin.py:197 msgid "flash.badge_added" msgstr "Wappen hinzugefügt" -#: fietsboek/views/admin.py:213 +#: fietsboek/views/admin.py:221 msgid "flash.badge_modified" msgstr "Wappen bearbeitet" -#: fietsboek/views/admin.py:233 +#: fietsboek/views/admin.py:241 msgid "flash.badge_deleted" msgstr "Wappen gelöscht" @@ -1338,7 +1342,7 @@ msgstr "Keine Datei ausgewählt" msgid "flash.upload_success" msgstr "Hochladen erfolgreich" -#: fietsboek/views/upload.py:202 +#: fietsboek/views/upload.py:203 msgid "flash.upload_cancelled" msgstr "Hochladen abgebrochen" diff --git a/fietsboek/locale/en/LC_MESSAGES/messages.mo b/fietsboek/locale/en/LC_MESSAGES/messages.mo Binary files differindex 19b3c28..6ea8566 100644 --- a/fietsboek/locale/en/LC_MESSAGES/messages.mo +++ b/fietsboek/locale/en/LC_MESSAGES/messages.mo diff --git a/fietsboek/locale/en/LC_MESSAGES/messages.po b/fietsboek/locale/en/LC_MESSAGES/messages.po index 1feb09a..0269f88 100644 --- a/fietsboek/locale/en/LC_MESSAGES/messages.po +++ b/fietsboek/locale/en/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-10-01 13:36+0200\n" +"POT-Creation-Date: 2026-10-15 00:03+0200\n" "PO-Revision-Date: 2023-04-03 20:42+0200\n" "Last-Translator: \n" "Language: en\n" @@ -18,11 +18,11 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.18.0\n" -#: fietsboek/actions.py:269 +#: fietsboek/actions.py:271 msgid "email.verify_mail.subject" msgstr "Fietsboek Account Verification" -#: fietsboek/actions.py:272 +#: fietsboek/actions.py:274 msgid "email.verify.text" msgstr "" "To verify your Fietsboek account, please use this link: {}\n" @@ -145,6 +145,10 @@ msgstr "Overview" msgid "page.admin.nav.badges" msgstr "Badges" +#: fietsboek/templates/admin.jinja2:12 +msgid "page.admin.nav.logs" +msgstr "Logs" + #: fietsboek/templates/admin_badges.jinja2:5 msgid "page.admin.badges" msgstr "Badges" @@ -549,8 +553,8 @@ msgstr "Tagged as" #: fietsboek/templates/details.jinja2:111 msgid "page.details.background_tasks_in_progress" msgstr "" -"Background tasks for this track are still running. " -"The information displayed is still incomplete." +"Background tasks for this track are still running. The information " +"displayed is still incomplete." #: fietsboek/templates/details.jinja2:121 fietsboek/templates/edit.jinja2:10 #: fietsboek/templates/finish_upload.jinja2:10 @@ -1240,15 +1244,15 @@ msgstr "Invalid email" msgid "flash.a_confirmation_link_has_been_sent" msgstr "A confirmation link has been sent" -#: fietsboek/views/admin.py:189 +#: fietsboek/views/admin.py:197 msgid "flash.badge_added" msgstr "Badge has been added" -#: fietsboek/views/admin.py:213 +#: fietsboek/views/admin.py:221 msgid "flash.badge_modified" msgstr "Badge has been modified" -#: fietsboek/views/admin.py:233 +#: fietsboek/views/admin.py:241 msgid "flash.badge_deleted" msgstr "Badge has been deleted" @@ -1327,7 +1331,7 @@ msgstr "No file selected" msgid "flash.upload_success" msgstr "Upload successful" -#: fietsboek/views/upload.py:202 +#: fietsboek/views/upload.py:203 msgid "flash.upload_cancelled" msgstr "Upload cancelled" diff --git a/fietsboek/locale/fietslog.pot b/fietsboek/locale/fietslog.pot index 4a9e203..26b222b 100644 --- a/fietsboek/locale/fietslog.pot +++ b/fietsboek/locale/fietslog.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-10-01 13:36+0200\n" +"POT-Creation-Date: 2026-10-15 00:03+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,11 +17,11 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.18.0\n" -#: fietsboek/actions.py:269 +#: fietsboek/actions.py:271 msgid "email.verify_mail.subject" msgstr "" -#: fietsboek/actions.py:272 +#: fietsboek/actions.py:274 msgid "email.verify.text" msgstr "" @@ -139,6 +139,10 @@ msgstr "" msgid "page.admin.nav.badges" msgstr "" +#: fietsboek/templates/admin.jinja2:12 +msgid "page.admin.nav.logs" +msgstr "" + #: fietsboek/templates/admin_badges.jinja2:5 msgid "page.admin.badges" msgstr "" @@ -1224,15 +1228,15 @@ msgstr "" msgid "flash.a_confirmation_link_has_been_sent" msgstr "" -#: fietsboek/views/admin.py:189 +#: fietsboek/views/admin.py:197 msgid "flash.badge_added" msgstr "" -#: fietsboek/views/admin.py:213 +#: fietsboek/views/admin.py:221 msgid "flash.badge_modified" msgstr "" -#: fietsboek/views/admin.py:233 +#: fietsboek/views/admin.py:241 msgid "flash.badge_deleted" msgstr "" @@ -1308,7 +1312,7 @@ msgstr "" msgid "flash.upload_success" msgstr "" -#: fietsboek/views/upload.py:202 +#: fietsboek/views/upload.py:203 msgid "flash.upload_cancelled" msgstr "" diff --git a/fietsboek/log.py b/fietsboek/log.py new file mode 100644 index 0000000..5e48e85 --- /dev/null +++ b/fietsboek/log.py @@ -0,0 +1,48 @@ +"""Logging-related utilities.""" +import collections +import datetime +import logging +from dataclasses import asdict, dataclass + +@dataclass(slots=True) +class LogLine: + time: str + name: str + level: int + level_name: str + message: str + thread: str + lineno: int + + def as_dict(self) -> dict: + return asdict(self) + + +class RingBuffer(logging.Handler): + """Stores messages in a ring-buffer. + + When the buffer is full, a new message will replace the oldest one. + """ + + def __init__(self, maxlen): + super().__init__() + self.buffer = collections.deque(maxlen=maxlen) + + def emit(self, record): + line = LogLine( + time=record.asctime, + name=record.name, + level=record.levelno, + level_name=record.levelname, + message=record.getMessage(), + thread=record.threadName, + lineno=record.lineno, + ) + self.buffer.append(line) + + +HANDLER = RingBuffer(5000) + + +def install(): + logging.getLogger().addHandler(HANDLER) diff --git a/fietsboek/routes.py b/fietsboek/routes.py index 2e1a171..da9ed04 100644 --- a/fietsboek/routes.py +++ b/fietsboek/routes.py @@ -101,6 +101,7 @@ def includeme(config): config.add_route("badge", "/badge/{badge_id}", factory="fietsboek.models.Badge.factory") config.add_route("admin", "/admin/") + config.add_route("admin-logs", "/admin/logs") config.add_route("admin-badge", "/admin/badges/") config.add_route("admin-badge-add", "/admin/badges/add") config.add_route("admin-badge-edit", "/admin/badges/edit") diff --git a/fietsboek/static/theme.css b/fietsboek/static/theme.css index b295203..6b9e1c2 100644 --- a/fietsboek/static/theme.css +++ b/fietsboek/static/theme.css @@ -404,7 +404,10 @@ strong { #adminContainer { display: grid; grid-template-areas: "sidebar main"; - grid-template-columns: 1fr 5fr; + /* Use minmax() to force fr to be an actual size, and not just split the + * "remaining size". + */ + grid-template-columns: minmax(0px, 1fr) minmax(0px, 5fr); gap: 1rem; } @@ -420,6 +423,35 @@ strong { font-size: 120%; } +.logview { + background-color: white; + border-radius: 0.375rem; + padding: 0.375rem; +} + +.logline { + font-family: monospace; +} +.logline td { + padding-right: 1em; +} + +.logline-debug { + color: #444; +} + +.logline-info { + color: #00c; +} + +.logline-warning { + color: #990; +} + +.logline-error { + color: #c00; +} + .list-group.list-group-root { padding: 0; overflow: hidden; diff --git a/fietsboek/static/theme.css.map b/fietsboek/static/theme.css.map index b91d750..30b9235 100644 --- a/fietsboek/static/theme.css.map +++ b/fietsboek/static/theme.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["../../asset-sources/theme.scss"],"names":[],"mappings":"AAAA;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;AAEA;EACE;EACA;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAIA;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAlCJ;EAqCE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACI;;;AAGJ;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;;;AAIJ;EACE;;;AAGF;EACE;;;AAGF;AACA;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAIA;EACE;;;AAGJ;AAEA;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAEF;EACE;EACA;;;AAEF;EACE;;AAEA;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;;AAIJ;EACE;;AAEF;EACE;;AACA;EACE;;AAGJ;EACE;;AACA;EACE;;AAGJ;EACE;;AACA;EACE;;AAGJ;EACE;;AACA;EACE;;AAGJ;EACE;EACA;;AACA;EACE;;AAIJ;EACE;EACA;;;AAKF;EACE;EACA;EAEA;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAGF;EACE;;;AAGF;AACA;EACE;;;AAGF;EACE;EACA;;AAEA;EAJF;IAKI,eACE;;;AAIJ;EACE;;AAGF;EACE;;AAEA;EAHF;IAII;;;AAGF;EACE;EACA;;AAIJ;EACE;EACA;;;AAIJ;EACE;;;AAGF;AACA;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE","file":"theme.css"}
\ No newline at end of file +{"version":3,"sourceRoot":"","sources":["../../asset-sources/theme.scss"],"names":[],"mappings":"AAAA;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;AAEA;EACE;EACA;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAIA;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAlCJ;EAqCE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACI;;;AAGJ;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;;;AAIJ;EACE;;;AAGF;EACE;;;AAGF;AACA;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAIA;EACE;;;AAGJ;AAEA;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAEF;EACE;EACA;;;AAEF;EACE;;AAEA;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;;AAIJ;EACE;;AAEF;EACE;;AACA;EACE;;AAGJ;EACE;;AACA;EACE;;AAGJ;EACE;;AACA;EACE;;AAGJ;EACE;;AACA;EACE;;AAGJ;EACE;EACA;;AACA;EACE;;AAIJ;EACE;EACA;;;AAKF;EACE;EACA;EAEA;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAGF;EACE;;;AAGF;AACA;EACE;;;AAGF;EACE;EACA;;AAEA;EAJF;IAKI,eACE;;;AAIJ;EACE;;AAGF;EACE;;AAEA;EAHF;IAII;;;AAGF;EACE;EACA;;AAIJ;EACE;EACA;;;AAIJ;EACE;;;AAGF;AACA;EACE;EACA;AACA;AAAA;AAAA;EAGA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;AAEA;EACE;;;AAIJ;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE","file":"theme.css"}
\ No newline at end of file diff --git a/fietsboek/templates/admin.jinja2 b/fietsboek/templates/admin.jinja2 index e05e9f0..f324495 100644 --- a/fietsboek/templates/admin.jinja2 +++ b/fietsboek/templates/admin.jinja2 @@ -9,6 +9,7 @@ <nav class="nav nav-pills nav-fill flex-column"> <a class="nav-link{% if admin_index == 0 %} active text-bg-dark{% endif %}" href="{{ request.route_url('admin') }}">{{ _("page.admin.nav.overview") }}</a> <a class="nav-link{% if admin_index == 1 %} active text-bg-dark{% endif %}" href="{{ request.route_url('admin-badge') }}">{{ _("page.admin.nav.badges") }}</a> + <a class="nav-link{% if admin_index == 2 %} active text-bg-dark{% endif %}" href="{{ request.route_url('admin-logs') }}">{{ _("page.admin.nav.logs") }}</a> </nav> </aside> diff --git a/fietsboek/templates/admin_logs.jinja2 b/fietsboek/templates/admin_logs.jinja2 new file mode 100644 index 0000000..ac3f956 --- /dev/null +++ b/fietsboek/templates/admin_logs.jinja2 @@ -0,0 +1,46 @@ +{% set admin_index = 2 %} +{% extends "admin.jinja2" %} +{% block admin_content %} +<div> + Filter: + <select class="form-select my-2" id="logLevelSelect"> + <option value="10">Debug</option> + <option value="20" selected>Info</option> + <option value="30">Warning</option> + <option value="40">Error</option> + <option value="50">Critical</option> + </select> +</div> +<div class="logview" style="overflow: scroll; white-space: nowrap;"> + <table> + {% for entry in entries %} + <tr class="logline logline-{{entry.level_name | lower}}" data-level="{{ entry.level }}"> + <td>{{ entry.time }}</td> + <td>{{ entry.level_name }}</td> + <td>{{ entry.name }}:{{ entry.lineno }}</td> + <td>{{ entry.thread }}</td> + <td>{{ entry.message }}</td> + </tr> + {% endfor %} + </table> +</div> +{% endblock %} + +{% block latescripts %} + <script type="text/javascript"> + function filterLogEntries() { + let wantedLevel = parseInt(document.querySelector("#logLevelSelect").value); + document.querySelectorAll(".logline").forEach((line) => { + let lineLevel = parseInt(line.getAttribute("data-level")); + if (lineLevel >= wantedLevel) { + line.style.display = ""; + } else { + line.style.display = "none"; + } + }); + } + + document.querySelector("#logLevelSelect").addEventListener("change", (e) => filterLogEntries()); + filterLogEntries(); + </script> +{% endblock %} diff --git a/fietsboek/views/admin.py b/fietsboek/views/admin.py index f0aa271..9252090 100644 --- a/fietsboek/views/admin.py +++ b/fietsboek/views/admin.py @@ -12,7 +12,7 @@ from pyramid.request import Request from pyramid.view import view_config from sqlalchemy import func, select, text -from .. import models, util +from .. import log, models, util from ..data import DataManager GOOD_CRON_THRESHOLD = datetime.timedelta(hours=1) @@ -147,6 +147,14 @@ def admin(request: Request): "cron_good": cron_good, } +@view_config( + route_name="admin-logs", + renderer="fietsboek:templates/admin_logs.jinja2", + permission="admin", +) +def admin_logs(request: Request): + return {"entries": log.HANDLER.buffer} + @view_config( route_name="admin-badge", |
