From d9e41bc12fdc0d566d3a475f69f79be36bf74a6b Mon Sep 17 00:00:00 2001 From: Broque Thomas Date: Sat, 9 Aug 2025 13:17:11 -0700 Subject: [PATCH] fix logging issue --- core/plex_scan_manager.py | 16 ++++---- .../logging_config.cpython-310.pyc | Bin 2004 -> 3112 bytes utils/logging_config.py | 36 ++++++++++++++++-- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/core/plex_scan_manager.py b/core/plex_scan_manager.py index 8a59055f..32d1b4a2 100644 --- a/core/plex_scan_manager.py +++ b/core/plex_scan_manager.py @@ -49,7 +49,7 @@ class PlexScanManager: Args: reason: Optional reason for the scan request (for logging) """ - logger.info(f"🔍 DEBUG: Plex scan requested - reason: {reason}") + logger.info(f"DEBUG: Plex scan requested - reason: {reason}") with self._lock: if self._scan_in_progress: # Plex is currently scanning - mark that we need another scan later @@ -78,8 +78,8 @@ class PlexScanManager: with self._lock: if callback not in self._scan_completion_callbacks: self._scan_completion_callbacks.append(callback) - logger.info(f"🔍 DEBUG: Added scan completion callback: {callback.__name__}") - logger.info(f"🔍 DEBUG: Total callbacks registered: {len(self._scan_completion_callbacks)}") + logger.info(f"DEBUG: Added scan completion callback: {callback.__name__}") + logger.info(f"DEBUG: Total callbacks registered: {len(self._scan_completion_callbacks)}") def remove_scan_completion_callback(self, callback): """ @@ -213,11 +213,11 @@ class PlexScanManager: # Check if Plex is still scanning is_scanning = self.plex_client.is_library_scanning("Music") - logger.info(f"🔍 DEBUG: Plex scan status check - is_scanning: {is_scanning}") + logger.info(f"DEBUG: Plex scan status check - is_scanning: {is_scanning}") if is_scanning: # Still scanning, poll again in 30 seconds - logger.info("🔍 DEBUG: Plex library still scanning, will check again in 30 seconds") + logger.info("DEBUG: Plex library still scanning, will check again in 30 seconds") threading.Timer(30, self._poll_scan_status).start() else: # Scan completed! @@ -260,12 +260,12 @@ class PlexScanManager: with self._lock: callbacks = self._scan_completion_callbacks.copy() # Copy to avoid lock issues - logger.info(f"🔍 DEBUG: Calling {len(callbacks)} scan completion callbacks") + logger.info(f"DEBUG: Calling {len(callbacks)} scan completion callbacks") for callback in callbacks: try: - logger.info(f"🔍 DEBUG: Executing callback: {callback.__name__}") + logger.info(f"DEBUG: Executing callback: {callback.__name__}") callback() - logger.info(f"🔍 DEBUG: Callback {callback.__name__} completed successfully") + logger.info(f"DEBUG: Callback {callback.__name__} completed successfully") except Exception as e: logger.error(f"Error in scan completion callback {callback.__name__}: {e}") diff --git a/utils/__pycache__/logging_config.cpython-310.pyc b/utils/__pycache__/logging_config.cpython-310.pyc index c42ed8729f531c39ca86fe42d0993449759523cf..6f4c8041fb86c5bbeb90159e721f810add0d07c1 100644 GIT binary patch literal 3112 zcmb7G-ESMm5x>1}Qlv!5iXF$TduYMdY%3{koHlg~BZ(qA0vsxk>>8m_9L~2(@tFHy zc9(HPP(Tq0kP9>@iaw;R-CBM$(1-p9`9Jp2ed?QD8=ysJ_9#kf^3prp-0be$?Ci{M zX0E8$s|H-@-@fR*TsMq=;NbM-!Qd@;#1kOYpd>Xq<(qVf9-AE#-eziLcE={TW~EN% zbR5mwshfEnj~KTM>QHyzpe{4|{+`vTz>G(InDJQ!##MTbR@n@lVIG^gXwVwS)w(XN z)7gEeQ>SyVR?gY9LFf1F&Mcdy3wxw9N6D7aTKp$iXtY~I*&jr*2XCK7lF1}v$Zrf} zQshw@qtxlknheB`fnf%o3Qj~i7PF~It$hP_a1M+vp*D5){f>KJ*ha^L9bHx5in{D( z!Lvw8#z${X*+BLp8T6u@rc4BP^CT`P3*uhHqZlMbAmGDvCn)mZUXs(|p@_*TqfFp! zcvj&N-vT0yKA{AtNzKpAT{0$z7PZF4GZXBvM{jPjtoVclK>Nw*ZMwY30?9s=LAT(? zTLp2E4I-I5NYX^^41Wgt?;kz=kAXQj1m@t&7f(K0 zdhyr4zxcyvF#OH$fAu5qtJ6)RZK1#jWpbuGRGp;2+-V zgw4ST`E!HM!rou~d?m}}3R`)H7atE<@BuISES6#=XAiTXNaB^DOj5Cu7TeoNz8%Iz z-c7cb2Ro`JBu@sRRw`!DS3VHewmtV>HGlNVndmH^7LL)w#~1SWAtFKC05bBVv1c5T zN5(U9&)9-cNOR{hG4MVx4oDa9LCt;tkr7%alCJR~$UZb$R{Lup!(g66^#PDa@!cZrmc<(&sqBb@cdblpYgautmCIRNaH?#<(ypH5b13OwPowMs zjc$AgMgor%7^Cl>^#EW1kh*+5E#fE@H-ITWf#5k}IAC14rHERXKz1!h;I46Aa8=!A z@_i;mw9Q&3e+hQri$IRn=H6(t)(*0jt&GhT1f*e+_Rif~%3g2Z z+)&=Vw>R7C?OV!O+uYpPRQ~Gb`knRFw{I(Fb8Tzw&KX1_-0+kd(Qg4WHu`|)G3lGg zQF0L~$L^HhwZ`US16P4skBz@rV-lLuf*i2NL_^YS^A_l7Im%t#xV^Etr7VDhs-)}_ zrenh|z_JcO%RT`I2o#vH-~=_pnP9RUa2*XD932t_3)Wwqz~>2s!>p0fh5z;5atY6t z%fF4gT}Fa<=RZV(O89q?d{flF2Mf3;7J&GGNRu4j?pKQyj_bS$L^=9U%16_?Sj-^j zF}5{FcrNG1 zWRL8+W4FK1KSwKYSM|4~zc_Y5*9?5^jlJo9FVWgWrw_ApV}GjCn{el8eQW?UCZ_;& z&$g9+T%s|!WnCU}HgbltyYzYGzAK8Z_U#)_nh3a|@JP-ApPEn>{dhV8R;?J^ z*Mims8vX5v233?O2 zek_3HL)l5*Em{@6f*N1N8J*8%ezeyye#3K#H-IdVDpYJ2o|=B3tLSWY|5LTA#5R4>AhWP?dbVNO zgx|p<*od?rK%58S8$R)&SL3~4HeR_rzxaci F^ncD delta 839 zcmZ8e&ubGw6rMLbJNqNMX%Z_|Z7XOIL+Qz)AZ-Of?Li9aZ4uUx*~En1q|9y*WNQz} z(IRDzBBU3wXa57wo}{PskFfp&;+t*I;wZ^5F zUEH6bCy0QU1ZO7%fIf|BVgv?g&WKsU0#@2AHWMCjAdiVK1)mVXBht6VMqrD&up>t} z5s#e9M7YSi9WE-uo0vgG_!v9mn5c@m2@AZ)6P4N+0$;#$(rg@lyZhz3=>k;L8eh6r znCWOYk_GP!Wzx!;tYB#rcM2|}_D~A-k}p(`p>V>m9knCp$&IO>v(f??X4M?Vu*Y-WpX=999u(++0?A-n&-oGTS-CYebE@xW&~FH9R?$Y@ z%k94vt(kQ}*g5$?KI)8lY=$B^JB2-nUMHip*M76Ee%Y()ll?&bwA01;!s)CsWjCOXX{GgJSqjvP+Qg;bcRhwF6n8P)tcLW@lO`5Na3eZ zHrfqm1vQnfBQ(IJE^yo)Zb~Uo;J;nw0;4w6$|yU>)+htHsZQPPXE$}PTL?{%TiX7w zql;6N{UW)6;gllOK;FlrU`eYtXi{mRv(v1~veueRU{2aVu!#*``8DWreSXC={s1EJ!P@`; diff --git a/utils/logging_config.py b/utils/logging_config.py index 9bcf2a70..6457c0dc 100644 --- a/utils/logging_config.py +++ b/utils/logging_config.py @@ -1,10 +1,37 @@ import logging import sys +import re from pathlib import Path from datetime import datetime from typing import Optional -class ColoredFormatter(logging.Formatter): +class SafeFormatter(logging.Formatter): + """Formatter that handles Unicode characters safely on Windows""" + + @staticmethod + def strip_emojis(text): + """Remove emoji characters from text for Windows compatibility""" + # Remove emoji characters but keep other Unicode + emoji_pattern = re.compile("[" + u"\U0001F600-\U0001F64F" # emoticons + u"\U0001F300-\U0001F5FF" # symbols & pictographs + u"\U0001F680-\U0001F6FF" # transport & map symbols + u"\U0001F1E0-\U0001F1FF" # flags (iOS) + u"\U00002702-\U000027B0" + u"\U000024C2-\U0001F251" + "]+", flags=re.UNICODE) + return emoji_pattern.sub('', text) + + def format(self, record): + # Try to format with emojis first, fall back to stripped version + try: + return super().format(record) + except UnicodeEncodeError: + # Strip emojis and try again for Windows compatibility + record.getMessage = lambda: self.strip_emojis(record.msg % record.args if record.args else record.msg) + return super().format(record) + +class ColoredFormatter(SafeFormatter): COLORS = { 'DEBUG': '\033[94m', 'INFO': '\033[92m', @@ -32,6 +59,9 @@ def setup_logging(level: str = "INFO", log_file: Optional[str] = None) -> loggin console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(log_level) + # Force UTF-8 encoding for Windows compatibility with Unicode characters + if hasattr(console_handler.stream, 'reconfigure'): + console_handler.stream.reconfigure(encoding='utf-8', errors='replace') console_formatter = ColoredFormatter( fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', @@ -44,10 +74,10 @@ def setup_logging(level: str = "INFO", log_file: Optional[str] = None) -> loggin log_path = Path(log_file) log_path.parent.mkdir(parents=True, exist_ok=True) - file_handler = logging.FileHandler(log_path) + file_handler = logging.FileHandler(log_path, encoding='utf-8') file_handler.setLevel(log_level) - file_formatter = logging.Formatter( + file_formatter = SafeFormatter( fmt='%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' )