Compare commits

...

3 Commits

Author SHA1 Message Date
716ec42b48 MultiSelect moved to pylib 2025-07-25 19:52:20 +02:00
0506b5f02c filter selection improved 2025-07-25 00:02:00 +02:00
88b826414a Selection for module added 2025-07-24 22:41:25 +02:00
5 changed files with 32 additions and 24 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "report"] [submodule "report"]
path = report path = report
url = https://git.mount-mockery.de/pylib/report.git url = https://git.mount-mockery.de/pylib/report.git
[submodule "mytui"]
path = mytui
url = https://git.mount-mockery.de/pylib/mytui.git

2
loggy
View File

@ -2,5 +2,5 @@
# #
BASEPATH=$(dirname $0) BASEPATH=$(dirname $0)
$BASEPATH/venv/bin/python $BASEPATH/loggy.py $BASEPATH/venv/bin/python $BASEPATH/loggy.py $*

View File

@ -1,5 +1,6 @@
import logging import logging
import pickle import pickle
import re
import socket import socket
import struct import struct
import threading import threading
@ -7,7 +8,9 @@ from datetime import datetime
from textual.app import App, ComposeResult from textual.app import App, ComposeResult
from textual.containers import Vertical from textual.containers import Vertical
from textual.widgets import Footer, Header, Input, RichLog, Checkbox from textual.widgets import Footer, Header, Input, RichLog, Checkbox, Select
from mytui import MultiSelect
# Mapping von Log-Level-Namen zu Farben für die Anzeige # Mapping von Log-Level-Namen zu Farben für die Anzeige
LEVEL_STYLES = { LEVEL_STYLES = {
@ -63,13 +66,14 @@ class LogViewerApp(App):
("q", "quit", "Quit"), ("q", "quit", "Quit"),
("c", "clear_screen", "Clear") ("c", "clear_screen", "Clear")
] ]
MAX_LOGS = 1000
def __init__(self): def __init__(self):
super().__init__() super().__init__()
# #
self.all_logs = [] self.all_logs = []
self.module_filter = "" self.__module_selection__ = MultiSelect((), prompt="Module", id="module_filter")
self.level_filter = "" self.__level_selection__ = MultiSelect((), prompt="Level", id="level_filter")
self.force_critical = True self.force_critical = True
self.force_error = True self.force_error = True
self.force_warning = False self.force_warning = False
@ -81,8 +85,9 @@ class LogViewerApp(App):
with Vertical(id="app-grid"): with Vertical(id="app-grid"):
yield self.log_display yield self.log_display
with Vertical(id="bottom-bar"): with Vertical(id="bottom-bar"):
yield Input(placeholder="module filter...", id="module_filter") yield self.__module_selection__
yield Input(placeholder="level filter...", id="level_filter") yield Input(placeholder="Filter", id="select_filter")
yield self.__level_selection__
yield Checkbox("CRITICAL", self.force_critical, id="force_critical") yield Checkbox("CRITICAL", self.force_critical, id="force_critical")
yield Checkbox("ERROR", self.force_error, id="force_error") yield Checkbox("ERROR", self.force_error, id="force_error")
yield Checkbox("WARNING", self.force_warning, id="force_warning") yield Checkbox("WARNING", self.force_warning, id="force_warning")
@ -95,7 +100,11 @@ class LogViewerApp(App):
def add_log(self, record: logging.LogRecord) -> None: def add_log(self, record: logging.LogRecord) -> None:
"""Fügt einen neuen Log-Eintrag hinzu und aktualisiert die Anzeige.""" """Fügt einen neuen Log-Eintrag hinzu und aktualisiert die Anzeige."""
self.__module_selection__.AddEntry(record.name)
self.__level_selection__.AddEntry(record.levelname)
self.all_logs.append(record) self.all_logs.append(record)
if len(self.all_logs) > self.MAX_LOGS:
self.all_logs = self.all_logs[-self.MAX_LOGS:]
self._apply_filters_to_log(record) self._apply_filters_to_log(record)
def _force(self, lvl: str) -> bool: def _force(self, lvl: str) -> bool:
@ -107,13 +116,8 @@ class LogViewerApp(App):
def _apply_filters_to_log(self, record: logging.LogRecord): def _apply_filters_to_log(self, record: logging.LogRecord):
"""Prüft einen einzelnen Log-Eintrag gegen die Filter und zeigt ihn ggf. an.""" """Prüft einen einzelnen Log-Eintrag gegen die Filter und zeigt ihn ggf. an."""
module_match = False module_match = self.__module_selection__.IsSelected(record.name)
for module_filter in self.module_filter.split(","): level_match = self.__level_selection__.IsSelected(record.levelname)
module_match |= module_filter.lower() in record.name.lower()
level_match = False
for level_filter in self.level_filter.split(","):
level_match |= level_filter.lower() in record.levelname.lower()
if self._force(record.levelname.lower()) or (module_match and level_match): if self._force(record.levelname.lower()) or (module_match and level_match):
level_style = LEVEL_STYLES.get(record.levelname, "white") level_style = LEVEL_STYLES.get(record.levelname, "white")
@ -140,15 +144,6 @@ class LogViewerApp(App):
for record in self.all_logs: for record in self.all_logs:
self._apply_filters_to_log(record) self._apply_filters_to_log(record)
def on_input_changed(self, message: Input.Changed) -> None:
"""Aktualisiert die Filter und die Anzeige, wenn der Benutzer tippt."""
if message.input.id == "module_filter":
self.module_filter = message.value
elif message.input.id == "level_filter":
self.level_filter = message.value
self._update_display()
def on_checkbox_changed(self, message: Checkbox.Changed) -> None: def on_checkbox_changed(self, message: Checkbox.Changed) -> None:
if message.checkbox.id == "force_critical": if message.checkbox.id == "force_critical":
self.force_critical = message.value self.force_critical = message.value
@ -159,6 +154,15 @@ class LogViewerApp(App):
self._update_display() self._update_display()
def on_input_changed(self, message: Input.Changed) -> None:
"""Update the tui inputs and execute task, if requireed."""
if message.input.id == "select_filter":
self.__module_selection__.SetSelectionRegEx(message.value)
def on_select_changed(self, message: Select.Changed) -> None:
if message.select.id in ('module_filter', 'level_filter'):
self._update_display()
if __name__ == "__main__": if __name__ == "__main__":
app = LogViewerApp() app = LogViewerApp()

1
mytui Submodule

@ -0,0 +1 @@
Subproject commit bd390d27f00147c1305e244fbd6d0650a6bdcec9

View File

@ -7,8 +7,8 @@
#bottom-bar { #bottom-bar {
layout: grid; layout: grid;
grid-size: 5; grid-size: 6;
grid-columns: 1fr 1fr 15 15 15; grid-columns: 4fr 1fr 2fr 15 15 15;
height: 4; height: 4;
border-top: solid $primary; border-top: solid $primary;
} }