From cdf7a27f234b6f1ffb6ec8c6aa3c699233a1d29c Mon Sep 17 00:00:00 2001 From: Till Tomczak Date: Thu, 29 May 2025 10:07:11 +0200 Subject: [PATCH] "feat: Implement UNICODE encoding fix for database operations" --- backend/app/UNICODE_ENCODING_FIX.md | 1 + backend/app/database/myp.db-shm | Bin 32768 -> 32768 bytes backend/app/database/myp.db-wal | Bin 263712 -> 292552 bytes backend/app/test_unicode_fix.py | 1 + backend/app/utils/logging_config.py | 126 +++++++++++++++++++--------- 5 files changed, 89 insertions(+), 39 deletions(-) create mode 100644 backend/app/UNICODE_ENCODING_FIX.md create mode 100644 backend/app/test_unicode_fix.py diff --git a/backend/app/UNICODE_ENCODING_FIX.md b/backend/app/UNICODE_ENCODING_FIX.md new file mode 100644 index 00000000..0519ecba --- /dev/null +++ b/backend/app/UNICODE_ENCODING_FIX.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/app/database/myp.db-shm b/backend/app/database/myp.db-shm index 5cfb43b2ad0baffc4a1845666cf8c7894f7dbded..d354fc3f014581b05792798d77ea4044190ef28c 100644 GIT binary patch delta 189 zcmZo@U}|V!s+V}A%K!q55G>#hqy>TaUoLmyp5vP5Po^gbmboNw7llV7xlFHLB zq^buR1qKd4@;?%Qh%zuS*luiOXWYDmG0JiB21c39|D5=kH!os*#j*LDAD1Bj0J%3< diff --git a/backend/app/database/myp.db-wal b/backend/app/database/myp.db-wal index 5e34f2e2e697f85631606b7bf3514b47b3e577f5..a9f81cd884bcdd54bf47fca676b74944e6b51184 100644 GIT binary patch delta 537 zcmXZXJ&)300KoAe#*kbtp5MUHb7-N!k&Xpg`UWk~mbTk-eW8Vx9&H~Az2ydOb8+h8 za4|74>gLN}Ow>i)P~)mM-FV4Ox?GHjd`3^%HLIl#oB+3yKyIZ{PnI2P`xE&EWaXdLJc zgGKdl=5T?VLth`gEOc;-#laCXcowZq*PH(lX?UJoB-c%l1RRe?)jJ zP$8l*p%?H9l6{kkY_{{exLeAuKV3$gh~!mXa-j3IxT)cUIU-WOitvtQAw!nwa~+^f zBh{cqm!tGRX%765?lb~_yZ7sC^J4kF_A!T29*XhQR2#aW7(6jPXxhO_fHsa(OjL`} zq_qH=f&$!WACamT=^@$MLQk&FOV=*^kwbO>DCl85z)p0@ZozgXffhn?#F7Utg+#N7 zX)SsqZ7{@Tk`|$hy3`h$@A!W=`=8(Ckk6))B%%wJN}A)QZPTvldxD)-gTScMX str: """Gibt ein Emoji zurück oder einen ASCII-Fallback bei Encoding-Problemen.""" try: - # Teste, ob das Emoji dargestellt werden kann - emoji.encode(sys.stdout.encoding or 'utf-8') + # Erste Priorität: Teste, ob das Emoji dargestellt werden kann + test_encoding = sys.stdout.encoding or 'utf-8' + emoji.encode(test_encoding) + + # Zweite Prüfung: Windows-spezifische cp1252-Codierung + if os.name == 'nt': + try: + emoji.encode('cp1252') + except UnicodeEncodeError: + # Wenn cp1252 fehlschlägt, verwende Fallback + return EMOJI_FALLBACK.get(emoji, '[?]') + return emoji - except (UnicodeEncodeError, LookupError): + except (UnicodeEncodeError, LookupError, AttributeError): return EMOJI_FALLBACK.get(emoji, '[?]') # Prüfen, ob das Terminal ANSI-Farben unterstützt @@ -135,39 +145,61 @@ class ColoredFormatter(logging.Formatter): } def format(self, record): - # Basis-Format erstellen - log_fmt = LOG_FORMAT - date_fmt = LOG_DATE_FORMAT - - # Emoji dem Level und der Kategorie hinzufügen - level_name = record.levelname - category_name = record.name.split('.')[-1] if '.' in record.name else record.name - - level_emoji = safe_emoji(LOG_EMOJIS.get(level_name, '')) - category_emoji = safe_emoji(LOG_EMOJIS.get(category_name, '')) - - # Record-Objekt modifizieren (aber temporär) - original_levelname = record.levelname - original_name = record.name - - # Emojis hinzufügen - record.levelname = f"{level_emoji} {level_name}" - record.name = f"{category_emoji} {category_name}" - - # Farbe hinzufügen wenn unterstützt - if USE_COLORS: - level_color = self.level_colors.get(original_levelname, ANSI_COLORS['RESET']) - record.levelname = f"{level_color}{record.levelname}{ANSI_COLORS['RESET']}" - record.name = f"{ANSI_COLORS['BOLD']}{record.name}{ANSI_COLORS['RESET']}" - - # Formatieren - result = super().format(record) - - # Originale Werte wiederherstellen - record.levelname = original_levelname - record.name = original_name - - return result + try: + # Basis-Format erstellen + log_fmt = LOG_FORMAT + date_fmt = LOG_DATE_FORMAT + + # Emoji dem Level und der Kategorie hinzufügen + level_name = record.levelname + category_name = record.name.split('.')[-1] if '.' in record.name else record.name + + level_emoji = safe_emoji(LOG_EMOJIS.get(level_name, '')) + category_emoji = safe_emoji(LOG_EMOJIS.get(category_name, '')) + + # Record-Objekt modifizieren (aber temporär) + original_levelname = record.levelname + original_name = record.name + + # Emojis hinzufügen + record.levelname = f"{level_emoji} {level_name}" + record.name = f"{category_emoji} {category_name}" + + # Farbe hinzufügen wenn unterstützt + if USE_COLORS: + level_color = self.level_colors.get(original_levelname, ANSI_COLORS['RESET']) + record.levelname = f"{level_color}{record.levelname}{ANSI_COLORS['RESET']}" + record.name = f"{ANSI_COLORS['BOLD']}{record.name}{ANSI_COLORS['RESET']}" + + # Formatieren + result = super().format(record) + + # Originale Werte wiederherstellen + record.levelname = original_levelname + record.name = original_name + + return result + except (UnicodeEncodeError, UnicodeDecodeError, AttributeError) as e: + # Fallback bei Unicode-Problemen: Verwende nur ASCII-Text + original_levelname = record.levelname + original_name = record.name + + # Emojis durch ASCII-Fallbacks ersetzen + level_fallback = EMOJI_FALLBACK.get(LOG_EMOJIS.get(original_levelname, ''), '[LOG]') + category_name = record.name.split('.')[-1] if '.' in record.name else record.name + category_fallback = EMOJI_FALLBACK.get(LOG_EMOJIS.get(category_name, ''), '[CAT]') + + record.levelname = f"{level_fallback} {original_levelname}" + record.name = f"{category_fallback} {category_name}" + + # Basis-Formatierung ohne Farben + result = super().format(record) + + # Originale Werte wiederherstellen + record.levelname = original_levelname + record.name = original_name + + return result class DebugInfoFilter(logging.Filter): """Filter, der Debug-Informationen zu jedem Log-Eintrag hinzufügt.""" @@ -228,12 +260,20 @@ def setup_logging(debug_mode: bool = False): console_handler.setLevel(log_level) console_handler.setFormatter(colored_formatter) console_handler.addFilter(debug_filter) + + # Windows PowerShell UTF-8 Encoding-Unterstützung + if os.name == 'nt' and hasattr(console_handler.stream, 'reconfigure'): + try: + console_handler.stream.reconfigure(encoding='utf-8') + except: + pass + root_logger.addHandler(console_handler) # File Handler für allgemeine App-Logs app_log_file = get_log_file("app") app_handler = logging.handlers.RotatingFileHandler( - app_log_file, maxBytes=10*1024*1024, backupCount=5 + app_log_file, maxBytes=10*1024*1024, backupCount=5, encoding='utf-8' ) app_handler.setLevel(log_level) app_handler.setFormatter(file_formatter) @@ -276,12 +316,20 @@ def get_logger(category: str) -> logging.Logger: console_handler.setLevel(getattr(logging, LOG_LEVEL)) console_handler.setFormatter(colored_formatter) console_handler.addFilter(debug_filter) + + # Windows PowerShell UTF-8 Encoding-Unterstützung + if os.name == 'nt' and hasattr(console_handler.stream, 'reconfigure'): + try: + console_handler.stream.reconfigure(encoding='utf-8') + except: + pass + logger.addHandler(console_handler) # File Handler für spezifische Kategorie log_file = get_log_file(category) file_handler = logging.handlers.RotatingFileHandler( - log_file, maxBytes=10*1024*1024, backupCount=5 + log_file, maxBytes=10*1024*1024, backupCount=5, encoding='utf-8' ) file_handler.setLevel(getattr(logging, LOG_LEVEL)) file_handler.setFormatter(file_formatter) @@ -291,7 +339,7 @@ def get_logger(category: str) -> logging.Logger: if category != "errors": error_log_file = get_log_file("errors") error_handler = logging.handlers.RotatingFileHandler( - error_log_file, maxBytes=10*1024*1024, backupCount=5 + error_log_file, maxBytes=10*1024*1024, backupCount=5, encoding='utf-8' ) error_handler.setLevel(logging.ERROR) error_handler.setFormatter(file_formatter)