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
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
24
app/src/web/log_handler.py
Normal file
24
app/src/web/log_handler.py
Normal file
@@ -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:]
|
||||
@@ -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
|
||||
|
||||
19
app/src/web/notes_list.py
Normal file
19
app/src/web/notes_list.py
Normal file
@@ -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
|
||||
@@ -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(
|
||||
|
||||
@@ -57,7 +57,8 @@
|
||||
<button href="#" class="w3-bar-item w3-button w3-padding-16 w3-hide-large w3-dark-grey w3-hover-black" onclick="w3_close()" title="close menu"><i class="fa fa-remove fa-fw"></i> Close Menu</button>
|
||||
<a href="{{ url_for('.index')}}" class="w3-bar-item w3-button w3-padding {% block menu1_class %}{% endblock %}"><i class="fa fa-network-wired fa-fw"></i> {{_('Connections')}}</a>
|
||||
<a href="{{ url_for('.mqtt')}}" class="w3-bar-item w3-button w3-padding {% block menu2_class %}{% endblock %}"><i class="fa fa-database fa-fw"></i> MQTT</a>
|
||||
<a href="{{ url_for('.logging')}}" class="w3-bar-item w3-button w3-padding {% block menu3_class %}{% endblock %}"><i class="fa fa-file-export fa-fw"></i> {{_('Log Files')}}</a>
|
||||
<a href="{{ url_for('.notes')}}" class="w3-bar-item w3-button w3-padding {% block menu3_class %}{% endblock %}"><i class="fa fa-exclamation-triangle fa-fw"></i> {{_('Important Messages')}}</a>
|
||||
<a href="{{ url_for('.logging')}}" class="w3-bar-item w3-button w3-padding {% block menu4_class %}{% endblock %}"><i class="fa fa-file-export fa-fw"></i> {{_('Log Files')}}</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
@@ -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 %}<i class="fa fa-network-wired"></i> {{_('Proxy Connection Overview')}}{% endblock headline %}
|
||||
|
||||
|
||||
@@ -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 %}<i class="fa fa-file-export fa-fw"></i> {{_('Log Files')}}{% endblock headline %}
|
||||
{% block content %}
|
||||
<div id="id01" class="w3-modal">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% block title %} TSUN Proxy - MQTT Status {% endblock title%}
|
||||
{% block title %}{{_("TSUN Proxy - MQTT Status")}}{% endblock title %}
|
||||
{% block menu2_class %}w3-blue{% endblock %}
|
||||
{% block headline %}<i class="fa fa-database"></i> {{_('MQTT Overview')}}{% endblock headline %}
|
||||
{% block content %}
|
||||
@@ -45,6 +45,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="notes-list"></div>
|
||||
<div id="mqtt-table"></div>
|
||||
{% endblock content%}
|
||||
|
||||
|
||||
10
app/src/web/templates/page_notes.html.j2
Normal file
10
app/src/web/templates/page_notes.html.j2
Normal file
@@ -0,0 +1,10 @@
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% block title %}{{_("TSUN Proxy - Important Messages")}}{% endblock title %}
|
||||
{% block menu3_class %}w3-blue{% endblock %}
|
||||
{% block headline %}<i class="fa fa-exclamation-triangle fa-fw"></i> {{_('Important Messages')}}{% endblock headline %}
|
||||
{% block content %}
|
||||
<div id="notes-list"></div>
|
||||
{% endblock content%}
|
||||
|
||||
{% block footer %}{% endblock footer %}
|
||||
@@ -0,0 +1,23 @@
|
||||
{% if notes|length > 0 %}
|
||||
<div class="w3-container w3-margin-bottom">
|
||||
<h5>{{_("Warnings and error messages")}} </h5>
|
||||
<ul class="w3-ul w3-card-4">
|
||||
{% for note in notes %}
|
||||
<li class="{% if note.level is le(30) %}w3-leftbar w3-rightbar w3-pale-blue w3-border-blue{% else %}w3-leftbar w3-rightbar w3-pale-red w3-border-red{% endif %}">
|
||||
<span class="w3-col" style="width:150px">{{note.ctime|datetimeformat(format='short')}}</span>
|
||||
<span class="w3-col w3-hide-small" style="width:100px">{{note.lname|e}}</span>
|
||||
<span class="w3-rest">{{note.msg|e}}</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% elif not hide_if_empty %}
|
||||
<div class="w3-container w3-margin-bottom">
|
||||
<div class="w3-leftbar w3-rightbar w3-pale-green w3-border-green">
|
||||
<div class="w3-container">
|
||||
<h2>{{_("Well done!")}}</h2>
|
||||
<p>{{_("No warnings or errors have been logged since the last proxy start.")}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
Reference in New Issue
Block a user