diff --git a/loggy.py b/loggy.py index d41f6b5..dfc7d9d 100644 --- a/loggy.py +++ b/loggy.py @@ -3,12 +3,11 @@ import pickle import socket import struct import threading -from datetime import datetime # <--- HINZUGEFÜGT -from logging.handlers import SocketHandler +from datetime import datetime from textual.app import App, ComposeResult from textual.containers import Vertical -from textual.widgets import Footer, Header, Input, RichLog +from textual.widgets import Footer, Header, Input, RichLog, Checkbox # Mapping von Log-Level-Namen zu Farben für die Anzeige LEVEL_STYLES = { @@ -60,13 +59,19 @@ class LogViewerApp(App): """Eine Textual-App zum Anzeigen und Filtern von Python-Logs.""" CSS_PATH = "style.tcss" - BINDINGS = [("q", "quit", "Beenden")] + BINDINGS = [("q", "quit", "Quit")] def __init__(self): super().__init__() + # self.all_logs = [] self.module_filter = "" self.level_filter = "" + self.force_critical = True + self.force_error = True + self.force_warning = False + self.force_info = False + self.force_debug = False self.log_display = RichLog(highlight=True, markup=True) def compose(self) -> ComposeResult: @@ -75,8 +80,14 @@ class LogViewerApp(App): with Vertical(id="app-grid"): yield self.log_display with Vertical(id="bottom-bar"): - yield Input(placeholder="Modul filtern...", id="module_filter") - yield Input(placeholder="Level filtern...", id="level_filter") + yield Input(placeholder="module filter...", id="module_filter") + yield Input(placeholder="level filter...", id="level_filter") + with Vertical(id="force-bar"): + yield Checkbox("Force CRITICAL", self.force_critical, id="force_critical") + yield Checkbox("Force ERROR", self.force_error, id="force_error") + yield Checkbox("Force WARNING", self.force_warning, id="force_warning") + yield Checkbox("Force INFO", self.force_info, id="force_info") + yield Checkbox("Force DEBUG", self.force_debug, id="force_debug") yield Footer() def on_mount(self) -> None: @@ -89,6 +100,15 @@ class LogViewerApp(App): self.all_logs.append(record) self._apply_filters_to_log(record) + def _force(self, lvl: str) -> bool: + rv = False + rv |= lvl == 'critical' and self.force_critical + rv |= lvl == 'error' and self.force_error + rv |= lvl == 'warning' and self.force_warning + rv |= lvl == 'info' and self.force_info + rv |= lvl == 'debug' and self.force_debug + return rv + def _apply_filters_to_log(self, record: logging.LogRecord): """Prüft einen einzelnen Log-Eintrag gegen die Filter und zeigt ihn ggf. an.""" module_match = False @@ -99,7 +119,7 @@ class LogViewerApp(App): for level_filter in self.level_filter.split(","): level_match |= level_filter.lower() in record.levelname.lower() - if 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") timestamp_str = datetime.fromtimestamp(record.created).strftime("%Y-%m-%d %H:%M:%S") @@ -129,7 +149,21 @@ class LogViewerApp(App): self._update_display() + def on_checkbox_changed(self, message: Checkbox.Changed) -> None: + if message.checkbox.id == "force_critical": + self.force_critical = message.value + elif message.checkbox.id == "force_error": + self.force_error = message.value + elif message.checkbox.id == "force_warning": + self.force_warning = message.value + elif message.checkbox.id == "force_info": + self.force_info = message.value + elif message.checkbox.id == "force_debug": + self.force_debug = message.value + + self._update_display() + if __name__ == "__main__": app = LogViewerApp() - app.run() \ No newline at end of file + app.run() diff --git a/style.tcss b/style.tcss index bac82ef..3258235 100644 --- a/style.tcss +++ b/style.tcss @@ -2,13 +2,20 @@ layout: vertical; overflow-y: scroll; scrollbar-gutter: stable; - height: 90%; + height: 80%; } #bottom-bar { layout: grid; grid-size: 2; - height: 10%; + height: 11%; + border-top: solid $primary; +} + +#force-bar { + layout: grid; + grid-size: 5; + height: 9%; border-top: solid $primary; } @@ -19,3 +26,23 @@ #level_filter { width: 100%; } + +#force_critical { + width: 100%; +} + +#force_error { + width: 100%; +} + +#force_warning { + width: 100%; +} + +#force_info { + width: 100%; +} + +#force_debug { + width: 100%; +}