additional logging and error handling

This commit is contained in:
2026-05-29 10:44:50 +02:00
parent 72a0e52e08
commit 9ddc1f5b99
3 changed files with 72 additions and 10 deletions

View File

@@ -8,6 +8,7 @@ import polars as pl
import sqlalchemy as sql import sqlalchemy as sql
from wce_crm import db from wce_crm import db
from wce_crm.logging import logger_back as logger
class CompanyInfo(TypedDict): class CompanyInfo(TypedDict):
@@ -83,6 +84,7 @@ def _transform_for_gui_output(
def comp_search_choices() -> tuple[tuple[str, int], ...]: def comp_search_choices() -> tuple[tuple[str, int], ...]:
# TODO no reload functionality # TODO no reload functionality
logger.debug("[Call backend] comp_search_choices")
q = db.DF_CRM_MASTER.lazy() q = db.DF_CRM_MASTER.lazy()
counter = pl.int_range(0, pl.len()).over(pl.col.ma_unternehmensname) counter = pl.int_range(0, pl.len()).over(pl.col.ma_unternehmensname)
q = q.with_columns( q = q.with_columns(
@@ -98,6 +100,7 @@ def comp_search_choices() -> tuple[tuple[str, int], ...]:
def comp_search_get_info( def comp_search_get_info(
ma_id: int, ma_id: int,
) -> CompanyInfo: ) -> CompanyInfo:
logger.debug("[Call backend] comp_search_get_info")
df = db.DF_CRM_MASTER.filter(pl.col.ma_id == ma_id) df = db.DF_CRM_MASTER.filter(pl.col.ma_id == ma_id)
if df.height > 1 or df.height == 0: if df.height > 1 or df.height == 0:
raise ValueError(f"Größe des zurückgelieferten Datenpakets ungültig: {df.height}") raise ValueError(f"Größe des zurückgelieferten Datenpakets ungültig: {df.height}")
@@ -111,6 +114,7 @@ def contact_person_search_choices(
use_both_names: bool, use_both_names: bool,
) -> tuple[tuple[str, int], ...]: ) -> tuple[tuple[str, int], ...]:
# TODO no reload functionality # TODO no reload functionality
logger.debug("[Call backend] contact_person_search_choices")
q = db.DF_CONTACT_PERSON.lazy() q = db.DF_CONTACT_PERSON.lazy()
if ma_id is not None: if ma_id is not None:
q = q.filter(pl.col.ma_id == ma_id) q = q.filter(pl.col.ma_id == ma_id)
@@ -136,6 +140,7 @@ def contact_person_search_choices(
def contact_person_search_get_info( def contact_person_search_get_info(
an_id: int, an_id: int,
) -> ContactPersonInfo: ) -> ContactPersonInfo:
logger.debug("[Call backend] contact_person_search_get_info")
df = db.DF_CONTACT_PERSON.filter(pl.col.an_id == an_id) df = db.DF_CONTACT_PERSON.filter(pl.col.an_id == an_id)
if df.height > 1 or df.height == 0: if df.height > 1 or df.height == 0:
raise ValueError(f"Größe des zurückgelieferten Datenpakets ungültig: {df.height}") raise ValueError(f"Größe des zurückgelieferten Datenpakets ungültig: {df.height}")
@@ -147,6 +152,7 @@ def contact_person_search_get_info(
def insert_initial_recording( def insert_initial_recording(
data: dict[str, Any], data: dict[str, Any],
) -> None: ) -> None:
logger.debug("[Call backend] insert_initial_recording")
stmt = db.grunderfassung_unternehmen.insert().values(data) stmt = db.grunderfassung_unternehmen.insert().values(data)
with db.ENGINE.begin() as conn: with db.ENGINE.begin() as conn:
conn.execute(stmt) conn.execute(stmt)
@@ -156,6 +162,7 @@ def update_initial_recording(
id_: int, id_: int,
data: dict[str, Any], data: dict[str, Any],
) -> None: ) -> None:
logger.debug("[Call backend] update_initial_recording")
stmt = ( stmt = (
db.grunderfassung_unternehmen.update() db.grunderfassung_unternehmen.update()
.where(db.grunderfassung_unternehmen.c.erfassung_id == id_) .where(db.grunderfassung_unternehmen.c.erfassung_id == id_)
@@ -168,6 +175,7 @@ def update_initial_recording(
def get_initial_recording( def get_initial_recording(
id_: int, id_: int,
) -> dict[str, Any]: ) -> dict[str, Any]:
logger.debug("[Call backend] get_initial_recording")
stmt = db.grunderfassung_unternehmen.select().where( stmt = db.grunderfassung_unternehmen.select().where(
db.grunderfassung_unternehmen.c.erfassung_id == id_ db.grunderfassung_unternehmen.c.erfassung_id == id_
) )
@@ -190,6 +198,7 @@ class FrontpageCompany:
def get_company_list() -> list[FrontpageCompany]: def get_company_list() -> list[FrontpageCompany]:
logger.debug("[Call backend] get_company_list")
stmt = sql.select( stmt = sql.select(
db.grunderfassung_unternehmen.c.erfassung_id, db.grunderfassung_unternehmen.c.erfassung_id,
db.grunderfassung_unternehmen.c.Partnersuche__un_suche, db.grunderfassung_unternehmen.c.Partnersuche__un_suche,

View File

@@ -8,6 +8,7 @@ import json
import pickle import pickle
import re import re
import sys import sys
import traceback
import uuid import uuid
from collections import defaultdict from collections import defaultdict
from collections.abc import Container, Iterable, Sequence from collections.abc import Container, Iterable, Sequence
@@ -33,7 +34,9 @@ from PySide6.QtCore import (
QObject, QObject,
Qt, Qt,
QTimer, QTimer,
QtMsgType,
Signal, Signal,
qInstallMessageHandler,
) )
from PySide6.QtGui import QAction from PySide6.QtGui import QAction
from PySide6.QtWidgets import ( from PySide6.QtWidgets import (
@@ -1073,11 +1076,11 @@ def set_form_data(
value = data value = data
else: else:
if key not in data: if key not in data:
logger_gui.debug("---- Key not in data: %s") logger_gui.error("Key not in data: %s", key)
logger_gui.debug("-------- Data: %s", pformat(data)) logger_gui.error("Data:\n%s", pformat(data))
value = data[key] value = data[key]
logger_gui.debug("---- Key set: %s", key) logger_gui.debug("Key set: %s", key)
set_widget_value(widget, value) set_widget_value(widget, value)
@@ -3634,9 +3637,51 @@ class MainWindow(QMainWindow):
help_menu.addAction(about_action) help_menu.addAction(about_action)
# ** global exception handling
def global_exception_handler(exc_type, exc_value, exc_traceback):
"""catches all unhandled errors"""
# format error
error_msg = "".join(traceback.format_exception(exc_type, exc_value, exc_traceback))
logger_gui.critical(f"UNEXPECTED ERROR:\n{error_msg}")
# message to user
# check if QApplication exists otherwise crashing of crash handler possible)
if QApplication.instance():
msg_box = QMessageBox()
msg_box.setIcon(QMessageBox.Icon.Critical)
msg_box.setWindowTitle("Kritischer Fehler")
msg_box.setText(
"Ein unerwarteter Fehler ist aufgetreten. Die Details wurden protokolliert."
)
# details for user or screenshots
msg_box.setDetailedText(error_msg)
msg_box.exec()
sys.exit(1)
def qt_message_handler(mode, context, message):
"""forwards internal Qt C++ warnings to Python loggers"""
if mode == QtMsgType.QtInfoMsg:
logger_gui.info(message)
elif mode == QtMsgType.QtWarningMsg:
logger_gui.warning(message)
elif mode == QtMsgType.QtCriticalMsg:
logger_gui.error(message)
elif mode == QtMsgType.QtFatalMsg:
logger_gui.critical(message)
if __name__ == "__main__": if __name__ == "__main__":
app = QApplication(sys.argv) sys.excepthook = global_exception_handler
app.setStyleSheet(QSS) qInstallMessageHandler(qt_message_handler)
window = MainWindow()
window.show() try:
sys.exit(app.exec()) app = QApplication(sys.argv)
app.setStyleSheet(QSS)
window = MainWindow()
window.show()
sys.exit(app.exec())
except Exception as err:
logger_gui.critical("Fehler beim Starten der Anwendung:\n%s", str(err), exc_info=True)

View File

@@ -1,6 +1,6 @@
import logging import logging
from dopt_basics.logging import BASE_LOGGER, setup_logging from dopt_basics.logging import BASE_LOGGER, LoggingConfig, setup_logging
from wce_crm.constants import Config from wce_crm.constants import Config
@@ -14,12 +14,16 @@ if Config.DEVELOPMENT_STATE:
if not Config.PATH_LOGGING.exists(): if not Config.PATH_LOGGING.exists():
Config.PATH_LOGGING.mkdir() Config.PATH_LOGGING.mkdir()
setup_logging( LOGGING_CFG: LoggingConfig = LoggingConfig(
enable_stderr=enable_stderr, enable_stderr=enable_stderr,
enable_file=enable_file, enable_file=enable_file,
logging_dir=Config.PATH_LOGGING, logging_dir=Config.PATH_LOGGING,
log_filename=Config.LOG_FILENAME, log_filename=Config.LOG_FILENAME,
file_max_bytes=10_485_760,
file_backup_count=2,
) )
setup_logging(LOGGING_CFG)
logger_base = BASE_LOGGER.getChild("wce_crm") logger_base = BASE_LOGGER.getChild("wce_crm")
# ** GUI # ** GUI
@@ -31,3 +35,7 @@ logger_get_data = logger_gui.getChild("get_data")
logger_get_data.setLevel(logging.DEBUG) logger_get_data.setLevel(logging.DEBUG)
logger_auto_form = logger_gui.getChild("get_data_auto_form") logger_auto_form = logger_gui.getChild("get_data_auto_form")
logger_auto_form.setLevel(logging.DEBUG) logger_auto_form.setLevel(logging.DEBUG)
# ** Backend
logger_back = logger_base.getChild("backend")
logger_back.setLevel(logging.DEBUG)