Selection for module added
This commit is contained in:
parent
4d937f14b3
commit
88b826414a
2
loggy
2
loggy
@ -2,5 +2,5 @@
|
||||
#
|
||||
BASEPATH=$(dirname $0)
|
||||
|
||||
$BASEPATH/venv/bin/python $BASEPATH/loggy.py
|
||||
$BASEPATH/venv/bin/python $BASEPATH/loggy.py $*
|
||||
|
||||
|
119
loggy.py
119
loggy.py
@ -1,5 +1,6 @@
|
||||
import logging
|
||||
import pickle
|
||||
import re
|
||||
import socket
|
||||
import struct
|
||||
import threading
|
||||
@ -7,7 +8,7 @@ from datetime import datetime
|
||||
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.containers import Vertical
|
||||
from textual.widgets import Footer, Header, Input, RichLog, Checkbox
|
||||
from textual.widgets import Footer, Header, Input, RichLog, Checkbox, Select
|
||||
|
||||
# Mapping von Log-Level-Namen zu Farben für die Anzeige
|
||||
LEVEL_STYLES = {
|
||||
@ -55,6 +56,68 @@ class LogReceiver(threading.Thread):
|
||||
logging.error(f"LogReceiver-Fehler: {e}", exc_info=True)
|
||||
|
||||
|
||||
class OptionSelectList(dict):
|
||||
def __init__(self):
|
||||
super().__init__(self)
|
||||
#
|
||||
self.__default_value__ = True
|
||||
self.__selection_regex__ = ""
|
||||
|
||||
def __sorted_keys__(self):
|
||||
rv = list(self.keys())
|
||||
rv.sort()
|
||||
return rv
|
||||
|
||||
def SetSelectionRegEx(self, regex: str) -> None:
|
||||
self.__selection_regex__ = regex
|
||||
|
||||
def AddEntry(self, entry) -> None:
|
||||
if entry not in self:
|
||||
self[entry] = self.__default_value__
|
||||
|
||||
def Toggle(self, entry_num):
|
||||
if entry_num < 0:
|
||||
self.__default_value__ = entry_num == -1
|
||||
for key in self:
|
||||
self[key] = self.__default_value__
|
||||
elif entry_num > len(self):
|
||||
raise ValueError(f"The Entry '{entry} is not in the list")
|
||||
else:
|
||||
entry = self.__sorted_keys__()[entry_num]
|
||||
self[entry] = not self[entry]
|
||||
|
||||
def GetSelectList(self):
|
||||
rv = []
|
||||
if len(self) > 2:
|
||||
rv.append(('All', -1))
|
||||
rv.append(('None', -2))
|
||||
for index, key in enumerate(self.__sorted_keys__()):
|
||||
try:
|
||||
match = len(re.findall(self.__selection_regex__, key)) > 0
|
||||
except re.error:
|
||||
match = True # No valid regular expression
|
||||
if match:
|
||||
prefix = "\\[X] " if self[key] else "\\[-] "
|
||||
rv.append((prefix + key, index))
|
||||
return rv
|
||||
|
||||
def IsSelected(self, entry):
|
||||
return self.get(entry, False)
|
||||
|
||||
|
||||
class MySelect(Select):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.__new_options__ = []
|
||||
|
||||
def set_options(self, options):
|
||||
self.__new_options__ = options
|
||||
|
||||
def _on_enter(self, event):
|
||||
super().set_options(self.__new_options__)
|
||||
return super()._on_enter(event)
|
||||
|
||||
|
||||
class LogViewerApp(App):
|
||||
"""Eine Textual-App zum Anzeigen und Filtern von Python-Logs."""
|
||||
|
||||
@ -68,8 +131,10 @@ class LogViewerApp(App):
|
||||
super().__init__()
|
||||
#
|
||||
self.all_logs = []
|
||||
self.module_filter = ""
|
||||
self.level_filter = ""
|
||||
self.__module_select_list__ = OptionSelectList()
|
||||
self.__module_selection__ = MySelect((), prompt="Module", id="module_filter")
|
||||
self.__level_select_list__ = OptionSelectList()
|
||||
self.__level_selection__ = MySelect((), prompt="Level", id="level_filter")
|
||||
self.force_critical = True
|
||||
self.force_error = True
|
||||
self.force_warning = False
|
||||
@ -81,8 +146,9 @@ class LogViewerApp(App):
|
||||
with Vertical(id="app-grid"):
|
||||
yield self.log_display
|
||||
with Vertical(id="bottom-bar"):
|
||||
yield Input(placeholder="module filter...", id="module_filter")
|
||||
yield Input(placeholder="level filter...", id="level_filter")
|
||||
yield self.__module_selection__
|
||||
yield Input(placeholder="Filter", id="select_filter")
|
||||
yield self.__level_selection__
|
||||
yield Checkbox("CRITICAL", self.force_critical, id="force_critical")
|
||||
yield Checkbox("ERROR", self.force_error, id="force_error")
|
||||
yield Checkbox("WARNING", self.force_warning, id="force_warning")
|
||||
@ -95,6 +161,10 @@ class LogViewerApp(App):
|
||||
|
||||
def add_log(self, record: logging.LogRecord) -> None:
|
||||
"""Fügt einen neuen Log-Eintrag hinzu und aktualisiert die Anzeige."""
|
||||
self.__module_select_list__.AddEntry(record.name)
|
||||
self.__module_selection__.set_options(self.__module_select_list__.GetSelectList())
|
||||
self.__level_select_list__.AddEntry(record.levelname)
|
||||
self.__level_selection__.set_options(self.__level_select_list__.GetSelectList())
|
||||
self.all_logs.append(record)
|
||||
self._apply_filters_to_log(record)
|
||||
|
||||
@ -107,13 +177,8 @@ class LogViewerApp(App):
|
||||
|
||||
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
|
||||
for module_filter in self.module_filter.split(","):
|
||||
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()
|
||||
module_match = self.__module_select_list__.IsSelected(record.name)
|
||||
level_match = self.__level_select_list__.IsSelected(record.levelname)
|
||||
|
||||
if self._force(record.levelname.lower()) or (module_match and level_match):
|
||||
level_style = LEVEL_STYLES.get(record.levelname, "white")
|
||||
@ -140,15 +205,6 @@ class LogViewerApp(App):
|
||||
for record in self.all_logs:
|
||||
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:
|
||||
if message.checkbox.id == "force_critical":
|
||||
self.force_critical = message.value
|
||||
@ -159,6 +215,27 @@ class LogViewerApp(App):
|
||||
|
||||
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_select_list__.SetSelectionRegEx(message.value)
|
||||
self.__module_selection__.set_options(self.__module_select_list__.GetSelectList())
|
||||
self.__module_selection__.prompt = "Full" if not message.value else "Filtered"
|
||||
|
||||
def on_select_changed(self, message: Select.Changed) -> None:
|
||||
if message.select.id == 'module_filter':
|
||||
if type(message.value) is int:
|
||||
self.__module_select_list__.Toggle(message.value)
|
||||
self.__module_selection__.clear()
|
||||
self.__module_selection__.set_options(self.__module_select_list__.GetSelectList())
|
||||
elif message.select.id == 'level_filter':
|
||||
if type(message.value) is int:
|
||||
self.__level_select_list__.Toggle(message.value)
|
||||
self.__level_selection__.clear()
|
||||
self.__level_selection__.set_options(self.__level_select_list__.GetSelectList())
|
||||
|
||||
self._update_display()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = LogViewerApp()
|
||||
|
@ -7,8 +7,8 @@
|
||||
|
||||
#bottom-bar {
|
||||
layout: grid;
|
||||
grid-size: 5;
|
||||
grid-columns: 1fr 1fr 15 15 15;
|
||||
grid-size: 6;
|
||||
grid-columns: 4fr 1fr 2fr 15 15 15;
|
||||
height: 4;
|
||||
border-top: solid $primary;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user