From 888e1475e45661e1c5746f86a57e7d40e37504a5 Mon Sep 17 00:00:00 2001 From: Stefan Allius <122395479+s-allius@users.noreply.github.com> Date: Sun, 4 May 2025 18:50:31 +0200 Subject: [PATCH] S allius/issue397 (#405) * add Dashboards log handler to all known loggers * add list of last 3 warnings/errors to page * add note list to page * create LogHandler for the dashboard - simple memory log handler which stores the last 64 warnings/errors for the dashboard * render warnings/errors as note list * add page for warnings and errors * fix double defined build target * add well done message if no errors in the logs * translate page titles * more translations * add Notes page and table for important messages * add unit tests --- CHANGELOG.md | 1 + Makefile | 2 +- app/src/web/__init__.py | 7 ++ app/src/web/conn_table.py | 6 +- app/src/web/log_handler.py | 24 +++++++ app/src/web/mqtt_table.py | 6 ++ app/src/web/notes_list.py | 19 +++++ app/src/web/pages.py | 7 ++ app/src/web/templates/base.html.j2 | 3 +- app/src/web/templates/page_index.html.j2 | 2 +- app/src/web/templates/page_logging.html.j2 | 4 +- app/src/web/templates/page_mqtt.html.j2 | 3 +- app/src/web/templates/page_notes.html.j2 | 10 +++ .../web/templates/templ_notes_list.html.j2 | 23 ++++++ app/tests/test_web_route.py | 16 +++++ app/translations/de/LC_MESSAGES/messages.po | 71 +++++++++++-------- 16 files changed, 168 insertions(+), 36 deletions(-) create mode 100644 app/src/web/log_handler.py create mode 100644 app/src/web/notes_list.py create mode 100644 app/src/web/templates/page_notes.html.j2 diff --git a/CHANGELOG.md b/CHANGELOG.md index eedb850..46be5df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +- Dashboard: add Notes page and table for important messages - Dashboard: add Log-File page - Dashboard: add Connection page - add web UI to add-on diff --git a/Makefile b/Makefile index b98463f..5964e6e 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ babel: build: $(MAKE) -C ha_addons $@ -clean build: +clean: $(MAKE) -C app $@ $(MAKE) -C ha_addons $@ diff --git a/app/src/web/__init__.py b/app/src/web/__init__.py index 24b0e87..ef3728c 100644 --- a/app/src/web/__init__.py +++ b/app/src/web/__init__.py @@ -7,6 +7,8 @@ Usage: from quart import Quart, Blueprint from quart_babel import Babel from utils import load_modules +from .log_handler import LogHandler +import logging web = Blueprint('web', __name__) @@ -30,3 +32,8 @@ class Web: locale_selector=get_locale, timezone_selector=get_tz, default_translation_directories=translation_directories) + + h = LogHandler() + logging.getLogger().addHandler(h) + for name in logging.root.manager.loggerDict: + logging.getLogger(name).addHandler(h) diff --git a/app/src/web/conn_table.py b/app/src/web/conn_table.py index ae6fe38..4b81868 100644 --- a/app/src/web/conn_table.py +++ b/app/src/web/conn_table.py @@ -4,6 +4,7 @@ from quart_babel import format_datetime, _ from infos import Infos from . import web +from .log_handler import LogHandler def _get_device_icon(client_mode: bool): @@ -79,5 +80,8 @@ async def data_fetch(): data["conn-table"] = await render_template('templ_table.html.j2', table=get_table_data()) - data["notes-list"] = await render_template('templ_notes_list.html.j2') + data["notes-list"] = await render_template( + 'templ_notes_list.html.j2', + notes=LogHandler().get_buffer(3), + hide_if_empty=True) return data diff --git a/app/src/web/log_handler.py b/app/src/web/log_handler.py new file mode 100644 index 0000000..7565649 --- /dev/null +++ b/app/src/web/log_handler.py @@ -0,0 +1,24 @@ +from logging import Handler +from logging import LogRecord +import logging +from collections import deque + +from singleton import Singleton + + +class LogHandler(Handler, metaclass=Singleton): + def __init__(self, capacity=64): + super().__init__(logging.WARNING) + self.capacity = capacity + self.buffer = deque(maxlen=capacity) + + def emit(self, record: LogRecord): + self.buffer.append({ + 'ctime': record.created, + 'level': record.levelno, + 'lname': record.levelname, + 'msg': record.getMessage() + }) + + def get_buffer(self, elms=0) -> list: + return list(self.buffer)[-elms:] diff --git a/app/src/web/mqtt_table.py b/app/src/web/mqtt_table.py index fcd0477..8370c17 100644 --- a/app/src/web/mqtt_table.py +++ b/app/src/web/mqtt_table.py @@ -4,6 +4,7 @@ from quart_babel import format_datetime, _ from mqtt import Mqtt from . import web +from .log_handler import LogHandler def _get_row(inv: InverterBase): @@ -55,4 +56,9 @@ async def mqtt_fetch(): data["mqtt-table"] = await render_template('templ_table.html.j2', table=get_table_data()) + data["notes-list"] = await render_template( + 'templ_notes_list.html.j2', + notes=LogHandler().get_buffer(3), + hide_if_empty=True) + return data diff --git a/app/src/web/notes_list.py b/app/src/web/notes_list.py new file mode 100644 index 0000000..e96c319 --- /dev/null +++ b/app/src/web/notes_list.py @@ -0,0 +1,19 @@ +from quart import render_template +from quart_babel import format_datetime + +from . import web +from .log_handler import LogHandler + + +@web.route('/notes-fetch') +async def notes_fetch(): + data = { + "update-time": format_datetime(format="medium"), + } + + data["notes-list"] = await render_template( + 'templ_notes_list.html.j2', + notes=LogHandler().get_buffer(), + hide_if_empty=False) + + return data diff --git a/app/src/web/pages.py b/app/src/web/pages.py index f365239..49d720a 100644 --- a/app/src/web/pages.py +++ b/app/src/web/pages.py @@ -18,6 +18,13 @@ async def mqtt(): fetch_url=url_for('.mqtt_fetch')) +@web.route('/notes') +async def notes(): + return await render_template( + 'page_notes.html.j2', + fetch_url=url_for('.notes_fetch')) + + @web.route('/logging') async def logging(): return await render_template( diff --git a/app/src/web/templates/base.html.j2 b/app/src/web/templates/base.html.j2 index 34b6f57..0ef1f7e 100644 --- a/app/src/web/templates/base.html.j2 +++ b/app/src/web/templates/base.html.j2 @@ -57,7 +57,8 @@ {{_('Connections')}} MQTT - {{_('Log Files')}} + {{_('Important Messages')}} + {{_('Log Files')}} diff --git a/app/src/web/templates/page_index.html.j2 b/app/src/web/templates/page_index.html.j2 index f8364c5..65cae0d 100644 --- a/app/src/web/templates/page_index.html.j2 +++ b/app/src/web/templates/page_index.html.j2 @@ -1,6 +1,6 @@ {% extends 'base.html.j2' %} -{% block title %} TSUN Proxy - Connections {% endblock title%} +{% block title %}{{_("TSUN Proxy - Connections")}}{% endblock title %} {% block menu1_class %}w3-blue{% endblock %} {% block headline %} {{_('Proxy Connection Overview')}}{% endblock headline %} diff --git a/app/src/web/templates/page_logging.html.j2 b/app/src/web/templates/page_logging.html.j2 index 720a1e6..f80763c 100644 --- a/app/src/web/templates/page_logging.html.j2 +++ b/app/src/web/templates/page_logging.html.j2 @@ -1,7 +1,7 @@ {% extends 'base.html.j2' %} -{% block title %} TSUN Proxy - Log Files {% endblock title%} -{% block menu3_class %}w3-blue{% endblock %} +{% block title %}{{_("TSUN Proxy - Log Files")}}{% endblock title %} +{% block menu4_class %}w3-blue{% endblock %} {% block headline %} {{_('Log Files')}}{% endblock headline %} {% block content %}