"feat: Implement UNICODE encoding fix for database operations"

This commit is contained in:
Till Tomczak 2025-05-29 10:07:11 +02:00
parent fd9e51b291
commit cdf7a27f23
5 changed files with 89 additions and 39 deletions

View File

@ -0,0 +1 @@

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@

View File

@ -82,10 +82,20 @@ EMOJI_FALLBACK = {
def safe_emoji(emoji: str) -> str: def safe_emoji(emoji: str) -> str:
"""Gibt ein Emoji zurück oder einen ASCII-Fallback bei Encoding-Problemen.""" """Gibt ein Emoji zurück oder einen ASCII-Fallback bei Encoding-Problemen."""
try: try:
# Teste, ob das Emoji dargestellt werden kann # Erste Priorität: Teste, ob das Emoji dargestellt werden kann
emoji.encode(sys.stdout.encoding or 'utf-8') 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 return emoji
except (UnicodeEncodeError, LookupError): except (UnicodeEncodeError, LookupError, AttributeError):
return EMOJI_FALLBACK.get(emoji, '[?]') return EMOJI_FALLBACK.get(emoji, '[?]')
# Prüfen, ob das Terminal ANSI-Farben unterstützt # Prüfen, ob das Terminal ANSI-Farben unterstützt
@ -135,39 +145,61 @@ class ColoredFormatter(logging.Formatter):
} }
def format(self, record): def format(self, record):
# Basis-Format erstellen try:
log_fmt = LOG_FORMAT # Basis-Format erstellen
date_fmt = LOG_DATE_FORMAT log_fmt = LOG_FORMAT
date_fmt = LOG_DATE_FORMAT
# Emoji dem Level und der Kategorie hinzufügen
level_name = record.levelname # Emoji dem Level und der Kategorie hinzufügen
category_name = record.name.split('.')[-1] if '.' in record.name else record.name 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, '')) 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 # Record-Objekt modifizieren (aber temporär)
original_name = record.name original_levelname = record.levelname
original_name = record.name
# Emojis hinzufügen
record.levelname = f"{level_emoji} {level_name}" # Emojis hinzufügen
record.name = f"{category_emoji} {category_name}" record.levelname = f"{level_emoji} {level_name}"
record.name = f"{category_emoji} {category_name}"
# Farbe hinzufügen wenn unterstützt
if USE_COLORS: # Farbe hinzufügen wenn unterstützt
level_color = self.level_colors.get(original_levelname, ANSI_COLORS['RESET']) if USE_COLORS:
record.levelname = f"{level_color}{record.levelname}{ANSI_COLORS['RESET']}" level_color = self.level_colors.get(original_levelname, ANSI_COLORS['RESET'])
record.name = f"{ANSI_COLORS['BOLD']}{record.name}{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) # Formatieren
result = super().format(record)
# Originale Werte wiederherstellen
record.levelname = original_levelname # Originale Werte wiederherstellen
record.name = original_name record.levelname = original_levelname
record.name = original_name
return result
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): class DebugInfoFilter(logging.Filter):
"""Filter, der Debug-Informationen zu jedem Log-Eintrag hinzufügt.""" """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.setLevel(log_level)
console_handler.setFormatter(colored_formatter) console_handler.setFormatter(colored_formatter)
console_handler.addFilter(debug_filter) 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) root_logger.addHandler(console_handler)
# File Handler für allgemeine App-Logs # File Handler für allgemeine App-Logs
app_log_file = get_log_file("app") app_log_file = get_log_file("app")
app_handler = logging.handlers.RotatingFileHandler( 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.setLevel(log_level)
app_handler.setFormatter(file_formatter) 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.setLevel(getattr(logging, LOG_LEVEL))
console_handler.setFormatter(colored_formatter) console_handler.setFormatter(colored_formatter)
console_handler.addFilter(debug_filter) 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) logger.addHandler(console_handler)
# File Handler für spezifische Kategorie # File Handler für spezifische Kategorie
log_file = get_log_file(category) log_file = get_log_file(category)
file_handler = logging.handlers.RotatingFileHandler( 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.setLevel(getattr(logging, LOG_LEVEL))
file_handler.setFormatter(file_formatter) file_handler.setFormatter(file_formatter)
@ -291,7 +339,7 @@ def get_logger(category: str) -> logging.Logger:
if category != "errors": if category != "errors":
error_log_file = get_log_file("errors") error_log_file = get_log_file("errors")
error_handler = logging.handlers.RotatingFileHandler( 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.setLevel(logging.ERROR)
error_handler.setFormatter(file_formatter) error_handler.setFormatter(file_formatter)