From fe7ae29b8aa2b8f4fa3f473cde6005f3573cb75c Mon Sep 17 00:00:00 2001 From: Antti Kettunen Date: Mon, 20 Apr 2026 09:21:50 +0300 Subject: [PATCH] Replace more print logs with proper logger usage --- config/settings.py | 56 ++++++------ core/acoustid_client.py | 2 +- core/api_call_tracker.py | 11 ++- core/matching_engine.py | 10 +-- core/metadata_service.py | 20 ++--- scripts/system_info.py | 14 ++- tools/diagnose_itunes_discover.py | 143 +++++++++++++----------------- utils/logging_config.py | 4 +- 8 files changed, 131 insertions(+), 129 deletions(-) diff --git a/config/settings.py b/config/settings.py index e304f1aa..2289bbaf 100644 --- a/config/settings.py +++ b/config/settings.py @@ -5,6 +5,10 @@ import sqlite3 from typing import Dict, Any, Optional from cryptography.fernet import Fernet, InvalidToken from pathlib import Path +from utils.logging_config import get_logger + + +logger = get_logger("config") class ConfigManager: def __init__(self, config_path: str = "config/config.json"): @@ -33,7 +37,7 @@ class ConfigManager: # Default to project path even if it doesn't exist yet (for creation/fallback) self.config_path = project_path - print(f"ConfigManager initialized with path: {self.config_path}") + logger.info(f"ConfigManager initialized with path: {self.config_path}") self.config_data: Dict[str, Any] = {} self._fernet: Optional[Fernet] = None @@ -45,7 +49,7 @@ class ConfigManager: else: self.database_path = self.base_dir / "database" / "music_library.db" - print(f"Database path set to: {self.database_path}") + logger.info(f"Database path set to: {self.database_path}") self.load_config(str(self.config_path)) @@ -107,7 +111,7 @@ class ConfigManager: try: import shutil shutil.move(str(old_key_file), str(key_file)) - print(f"[MIGRATE] Moved encryption key to {key_file}") + logger.info(f"Moved encryption key to {key_file}") except Exception: key_file = old_key_file # Fall back to old location if key_file.exists(): @@ -155,8 +159,10 @@ class ConfigManager: return decrypted except InvalidToken: # Key mismatch — encrypted with a different key (key file deleted/replaced) - print(f"[ERROR] Failed to decrypt a config value — encryption key may have changed. " - f"Re-enter credentials in Settings or restore the original .encryption_key file.") + logger.error( + "Failed to decrypt a config value — encryption key may have changed. " + "Re-enter credentials in Settings or restore the original .encryption_key file." + ) return value except Exception: return value @@ -243,11 +249,11 @@ class ConfigManager: needs_migration = True break if needs_migration: - print("[MIGRATE] Encrypting sensitive config values at rest...") + logger.info("Encrypting sensitive config values at rest...") self._save_to_database(self.config_data) - print("[OK] Sensitive config values encrypted successfully") + logger.info("Sensitive config values encrypted successfully") except Exception as e: - print(f"[WARN] Could not migrate encryption: {e}") + logger.warning(f"Could not migrate encryption: {e}") def _ensure_database_exists(self): """Ensure database file and metadata table exist""" @@ -271,7 +277,7 @@ class ConfigManager: conn.commit() conn.close() except Exception as e: - print(f"Warning: Could not ensure database exists: {e}") + logger.warning(f"Could not ensure database exists: {e}") def _load_from_database(self) -> Optional[Dict[str, Any]]: """Load configuration from database, decrypting sensitive values.""" @@ -289,13 +295,13 @@ class ConfigManager: config_data = json.loads(row[0]) # Decrypt sensitive values (gracefully handles plaintext migration) config_data = self._decrypt_sensitive(config_data) - print("[OK] Configuration loaded from database") + logger.info("Configuration loaded from database") return config_data else: return None except Exception as e: - print(f"Warning: Could not load config from database: {e}") + logger.warning(f"Could not load config from database: {e}") return None finally: if conn: @@ -325,7 +331,7 @@ class ConfigManager: return True except Exception as e: - print(f"Error: Could not save config to database: {e}") + logger.error(f"Could not save config to database: {e}") return False finally: if conn: @@ -337,12 +343,12 @@ class ConfigManager: if self.config_path.exists(): with open(self.config_path, 'r') as f: config_data = json.load(f) - print(f"[OK] Configuration loaded from {self.config_path}") + logger.info(f"Configuration loaded from {self.config_path}") return config_data else: return None except Exception as e: - print(f"Warning: Could not load config from file: {e}") + logger.warning(f"Could not load config from file: {e}") return None def _get_default_config(self) -> Dict[str, Any]: @@ -506,7 +512,7 @@ class ConfigManager: 2. config.json (migration from file-based config) 3. Defaults (fresh install) """ - print(f"Loading configuration...") + logger.info("Loading configuration...") # Try loading from database first config_data = self._load_from_database() @@ -519,30 +525,30 @@ class ConfigManager: return # Database is empty - try migration from config.json - print(f"Configuration not found in database. Attempting migration from: {self.config_path}") + logger.info(f"Configuration not found in database. Attempting migration from: {self.config_path}") config_data = self._load_from_config_file() if config_data: # Migrate from config.json to database - print("[MIGRATE] Migrating configuration from config.json to database...") + logger.info("Migrating configuration from config.json to database...") if self._save_to_database(config_data): - print("[OK] Configuration migrated successfully to database.") + logger.info("Configuration migrated successfully to database.") self.config_data = config_data return else: - print("[WARN] Migration failed - using file-based config temporarily.") + logger.warning("Migration failed - using file-based config temporarily.") self.config_data = config_data return # No config.json either - use defaults - print("[INFO] ℹ️ No existing configuration found (DB or File) - using defaults") + logger.info("No existing configuration found (DB or File) - using defaults") config_data = self._get_default_config() # Try to save defaults to database if self._save_to_database(config_data): - print("[OK] Default configuration saved to database") + logger.info("Default configuration saved to database") else: - print("[WARN] Could not save defaults to database - using in-memory config") + logger.warning("Could not save defaults to database - using in-memory config") self.config_data = config_data @@ -558,14 +564,14 @@ class ConfigManager: if not success: # Fallback: Try to save to config.json if database fails - print("[WARN] Database save failed - attempting file fallback") + logger.warning("Database save failed - attempting file fallback") try: self.config_path.parent.mkdir(parents=True, exist_ok=True) with open(self.config_path, 'w') as f: json.dump(self.config_data, f, indent=2) - print("[OK] Configuration saved to config.json as fallback") + logger.info("Configuration saved to config.json as fallback") except Exception as e: - print(f"[ERROR] Failed to save configuration: {e}") + logger.error(f"Failed to save configuration: {e}") def get(self, key: str, default: Any = None) -> Any: keys = key.split('.') diff --git a/core/acoustid_client.py b/core/acoustid_client.py index 80c64709..d1d9eedc 100644 --- a/core/acoustid_client.py +++ b/core/acoustid_client.py @@ -194,7 +194,7 @@ class AcoustIDClient: result = client.fingerprint_and_lookup("/path/to/audio.mp3") if result: for mbid in result['recording_mbids']: - print(f"Match: {mbid}") + logger.info(f"Match: {mbid}") """ def __init__(self): diff --git a/core/api_call_tracker.py b/core/api_call_tracker.py index 104e1a29..0293270b 100644 --- a/core/api_call_tracker.py +++ b/core/api_call_tracker.py @@ -12,6 +12,11 @@ import threading import time from collections import deque, defaultdict +from utils.logging_config import get_logger + + +logger = get_logger("api_call_tracker") + # Known rate limits per service (calls/minute) RATE_LIMITS = { @@ -281,7 +286,7 @@ class ApiCallTracker: with open(_PERSIST_PATH, 'w') as f: json.dump({'ts': now, 'history': data, 'events': events}, f) except Exception as e: - print(f"[ApiCallTracker] Failed to save history: {e}") + logger.error(f"[ApiCallTracker] Failed to save history: {e}") def _load(self): """Restore 24h minute history from disk. Called on init.""" @@ -305,9 +310,9 @@ class ApiCallTracker: for e in events: if e.get('ts', 0) >= cutoff: self._events.append(e) - print(f"[ApiCallTracker] Restored history for {len(history)} services, {len(events)} events") + logger.info(f"[ApiCallTracker] Restored history for {len(history)} services, {len(events)} events") except Exception as e: - print(f"[ApiCallTracker] Failed to load history: {e}") + logger.error(f"[ApiCallTracker] Failed to load history: {e}") # Singleton instance diff --git a/core/matching_engine.py b/core/matching_engine.py index d38a5916..da1fb9bc 100644 --- a/core/matching_engine.py +++ b/core/matching_engine.py @@ -421,7 +421,7 @@ class MusicMatchingEngine: if is_likely_album and 4 <= len(potential_album_part) <= 30: cleaned_title = re.sub(dash_pattern, '', track_title).strip() - print(f"Heuristic album detection: '{original_title}' → '{cleaned_title}' (removed: '{potential_album_part}')") + logger.debug(f"Heuristic album detection: '{original_title}' → '{cleaned_title}' (removed: '{potential_album_part}')") return cleaned_title, True return track_title, False @@ -1004,13 +1004,13 @@ class MusicMatchingEngine: # Debug logging for troubleshooting if scored_results and not confident_results: - print(f"DEBUG: Found {len(scored_results)} scored results but none met confidence threshold 0.58") + logger.debug(f"Found {len(scored_results)} scored results but none met confidence threshold 0.58") for i, result in enumerate(sorted_results[:3]): # Show top 3 - print(f" {i+1}. {result.confidence:.3f} - {getattr(result, 'version_type', 'unknown')} - {result.filename[:60]}...") + logger.debug(f" {i+1}. {result.confidence:.3f} - {getattr(result, 'version_type', 'unknown')} - {result.filename[:60]}...") elif confident_results: - print(f"DEBUG: {len(confident_results)} results passed confidence threshold 0.58") + logger.debug(f"{len(confident_results)} results passed confidence threshold 0.58") for i, result in enumerate(confident_results[:3]): # Show top 3 - print(f" {i+1}. {result.confidence:.3f} - {getattr(result, 'version_type', 'unknown')} - {result.filename[:60]}...") + logger.debug(f" {i+1}. {result.confidence:.3f} - {getattr(result, 'version_type', 'unknown')} - {result.filename[:60]}...") return confident_results diff --git a/core/metadata_service.py b/core/metadata_service.py index bebe1f92..0ab4f46d 100644 --- a/core/metadata_service.py +++ b/core/metadata_service.py @@ -1045,7 +1045,7 @@ def check_album_completion( if total_tracks == 0 and album_id: logger.debug("No track count found for '%s' (%s)", album_name, album_id) - print(f"Checking album: '{album_name}' ({total_tracks} tracks)") + logger.debug(f"Checking album: '{album_name}' ({total_tracks} tracks)") formats = [] # Check if album exists in database with completeness info @@ -1060,7 +1060,7 @@ def check_album_completion( server_source=active_server ) except Exception as db_error: - print(f"Database error for album '{album_name}': {db_error}") + logger.error(f"Database error for album '{album_name}': {db_error}") return { "id": album_id, "name": album_name, @@ -1088,7 +1088,7 @@ def check_album_completion( else: status = "missing" - print(f" Result: {owned_tracks}/{expected_tracks or total_tracks} tracks ({completion_percentage:.1f}%) - {status}") + logger.debug(f" Result: {owned_tracks}/{expected_tracks or total_tracks} tracks ({completion_percentage:.1f}%) - {status}") return { "id": album_id, @@ -1103,7 +1103,7 @@ def check_album_completion( } except Exception as e: - print(f"Error checking album completion for '{album_data.get('name', 'Unknown')}': {e}") + logger.error(f"Error checking album completion for '{album_data.get('name', 'Unknown')}': {e}") return { "id": album_data.get('id', ''), "name": album_data.get('name', 'Unknown'), @@ -1137,7 +1137,7 @@ def check_single_completion( if total_tracks == 0: total_tracks = _resolve_completion_track_total(single_data, source_chain) or 1 - print(f"Checking {album_type}: '{single_name}' ({total_tracks} tracks)") + logger.debug(f"Checking {album_type}: '{single_name}' ({total_tracks} tracks)") if album_type == 'ep' or total_tracks > 1: try: @@ -1151,7 +1151,7 @@ def check_single_completion( server_source=active_server ) except Exception as db_error: - print(f"Database error for EP '{single_name}': {db_error}") + logger.error(f"Database error for EP '{single_name}': {db_error}") owned_tracks, expected_tracks, confidence = 0, total_tracks, 0.0 db_album = None @@ -1167,7 +1167,7 @@ def check_single_completion( else: status = "missing" - print(f" EP Result: {owned_tracks}/{expected_tracks or total_tracks} tracks ({completion_percentage:.1f}%) - {status}") + logger.debug(f" EP Result: {owned_tracks}/{expected_tracks or total_tracks} tracks ({completion_percentage:.1f}%) - {status}") return { "id": single_id, @@ -1192,7 +1192,7 @@ def check_single_completion( server_source=active_server ) except Exception as db_error: - print(f"Database error for single '{single_name}': {db_error}") + logger.error(f"Database error for single '{single_name}': {db_error}") db_track, confidence = None, 0.0 owned_tracks = 1 if db_track else 0 @@ -1208,7 +1208,7 @@ def check_single_completion( elif ext: formats = [ext] - print(f" Single Result: {owned_tracks}/1 tracks ({completion_percentage:.1f}%) - {status}") + logger.debug(f" Single Result: {owned_tracks}/1 tracks ({completion_percentage:.1f}%) - {status}") return { "id": single_id, @@ -1224,7 +1224,7 @@ def check_single_completion( } except Exception as e: - print(f"Error checking single/EP completion for '{single_data.get('name', 'Unknown')}': {e}") + logger.error(f"Error checking single/EP completion for '{single_data.get('name', 'Unknown')}': {e}") return { "id": single_data.get('id', ''), "name": single_data.get('name', 'Unknown'), diff --git a/scripts/system_info.py b/scripts/system_info.py index d3229caf..c594e9e6 100644 --- a/scripts/system_info.py +++ b/scripts/system_info.py @@ -1,12 +1,18 @@ #!/usr/bin/env python3 """Reports basic system info — useful for debugging Docker setups.""" +import logging import os import platform import shutil -print(f"Platform: {platform.system()} {platform.release()}") -print(f"Python: {platform.python_version()}") -print(f"Working Dir: {os.getcwd()}") +if not logging.getLogger().handlers: + logging.basicConfig(level=logging.INFO, format="%(message)s") + +logger = logging.getLogger("system_info") + +logger.info(f"Platform: {platform.system()} {platform.release()}") +logger.info(f"Python: {platform.python_version()}") +logger.info(f"Working Dir: {os.getcwd()}") # Disk usage for common SoulSync paths for path in ['/app/downloads', '/app/Transfer', '/app/data', './downloads', './Transfer']: @@ -14,4 +20,4 @@ for path in ['/app/downloads', '/app/Transfer', '/app/data', './downloads', './T usage = shutil.disk_usage(path) free_gb = usage.free / (1024**3) total_gb = usage.total / (1024**3) - print(f"Disk {path}: {free_gb:.1f} GB free / {total_gb:.1f} GB total") + logger.info(f"Disk {path}: {free_gb:.1f} GB free / {total_gb:.1f} GB total") diff --git a/tools/diagnose_itunes_discover.py b/tools/diagnose_itunes_discover.py index f3b0a15b..ff047c26 100644 --- a/tools/diagnose_itunes_discover.py +++ b/tools/diagnose_itunes_discover.py @@ -7,14 +7,12 @@ Run this script to identify issues with iTunes data population: - Discovery pool tracks by source - Recent albums by source - Curated playlists status - -Usage: - python tools/diagnose_itunes_discover.py """ -import sys -import os import json +import logging +import os +import sys # Add parent directory to path for imports sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) @@ -22,36 +20,42 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from database.music_database import MusicDatabase +if not logging.getLogger().handlers: + logging.basicConfig(level=logging.INFO, format="%(message)s") + +logger = logging.getLogger("diagnose_itunes_discover") + + +def _section(title: str) -> None: + logger.info("") + logger.info(title) + logger.info("-" * 40) + + def diagnose_itunes_discover(): """Run diagnostic checks for iTunes discover data.""" - print("=" * 60) - print("iTunes Discover Page Diagnostic Report") - print("=" * 60) + logger.info("=" * 60) + logger.info("iTunes Discover Page Diagnostic Report") + logger.info("=" * 60) db = MusicDatabase() # 1. Check Similar Artists - print("\n[1] SIMILAR ARTISTS") - print("-" * 40) - + _section("[1] SIMILAR ARTISTS") try: with db._get_connection() as conn: cursor = conn.cursor() - # Total similar artists cursor.execute("SELECT COUNT(*) as total FROM similar_artists") total = cursor.fetchone()['total'] - # With iTunes IDs cursor.execute("SELECT COUNT(*) as count FROM similar_artists WHERE similar_artist_itunes_id IS NOT NULL") with_itunes = cursor.fetchone()['count'] - # With Spotify IDs cursor.execute("SELECT COUNT(*) as count FROM similar_artists WHERE similar_artist_spotify_id IS NOT NULL") with_spotify = cursor.fetchone()['count'] - # With both cursor.execute(""" SELECT COUNT(*) as count FROM similar_artists WHERE similar_artist_itunes_id IS NOT NULL @@ -59,34 +63,29 @@ def diagnose_itunes_discover(): """) with_both = cursor.fetchone()['count'] - print(f" Total similar artists: {total}") - print(f" With iTunes ID: {with_itunes} ({100*with_itunes/total:.1f}%)" if total > 0 else " With iTunes ID: 0") - print(f" With Spotify ID: {with_spotify} ({100*with_spotify/total:.1f}%)" if total > 0 else " With Spotify ID: 0") - print(f" With BOTH IDs: {with_both} ({100*with_both/total:.1f}%)" if total > 0 else " With BOTH IDs: 0") + logger.info(f" Total similar artists: {total}") + logger.info(f" With iTunes ID: {with_itunes} ({100 * with_itunes / total:.1f}%)" if total > 0 else " With iTunes ID: 0") + logger.info(f" With Spotify ID: {with_spotify} ({100 * with_spotify / total:.1f}%)" if total > 0 else " With Spotify ID: 0") + logger.info(f" With BOTH IDs: {with_both} ({100 * with_both / total:.1f}%)" if total > 0 else " With BOTH IDs: 0") if with_itunes == 0 and total > 0: - print(" [CRITICAL] No similar artists have iTunes IDs - Hero section will be empty!") + logger.critical("No similar artists have iTunes IDs - Hero section will be empty!") elif with_itunes < total * 0.5: - print(" [WARNING] Less than 50% of similar artists have iTunes IDs") + logger.warning("Less than 50% of similar artists have iTunes IDs") else: - print(" [OK] iTunes coverage is adequate") - + logger.info("iTunes coverage is adequate") except Exception as e: - print(f" [ERROR] Could not check similar artists: {e}") + logger.error(f"Could not check similar artists: {e}") # 2. Check Discovery Pool - print("\n[2] DISCOVERY POOL") - print("-" * 40) - + _section("[2] DISCOVERY POOL") try: with db._get_connection() as conn: cursor = conn.cursor() - # Total tracks cursor.execute("SELECT COUNT(*) as total FROM discovery_pool") total = cursor.fetchone()['total'] - # By source cursor.execute(""" SELECT source, COUNT(*) as count FROM discovery_pool @@ -94,33 +93,28 @@ def diagnose_itunes_discover(): """) source_counts = {row['source']: row['count'] for row in cursor.fetchall()} - print(f" Total tracks: {total}") - print(f" Spotify tracks: {source_counts.get('spotify', 0)}") - print(f" iTunes tracks: {source_counts.get('itunes', 0)}") + logger.info(f" Total tracks: {total}") + logger.info(f" Spotify tracks: {source_counts.get('spotify', 0)}") + logger.info(f" iTunes tracks: {source_counts.get('itunes', 0)}") if source_counts.get('itunes', 0) == 0 and total > 0: - print(" [CRITICAL] No iTunes tracks in discovery pool - Fresh Tape/Archives will be empty!") + logger.critical("No iTunes tracks in discovery pool - Fresh Tape/Archives will be empty!") elif source_counts.get('itunes', 0) < total * 0.3: - print(" [WARNING] Low iTunes track count in discovery pool") + logger.warning("Low iTunes track count in discovery pool") else: - print(" [OK] iTunes tracks present") - + logger.info("iTunes tracks present") except Exception as e: - print(f" [ERROR] Could not check discovery pool: {e}") + logger.error(f"Could not check discovery pool: {e}") # 3. Check Recent Albums - print("\n[3] RECENT ALBUMS CACHE") - print("-" * 40) - + _section("[3] RECENT ALBUMS CACHE") try: with db._get_connection() as conn: cursor = conn.cursor() - # Total albums cursor.execute("SELECT COUNT(*) as total FROM discovery_recent_albums") total = cursor.fetchone()['total'] - # By source cursor.execute(""" SELECT source, COUNT(*) as count FROM discovery_recent_albums @@ -128,24 +122,21 @@ def diagnose_itunes_discover(): """) source_counts = {row['source']: row['count'] for row in cursor.fetchall()} - print(f" Total recent albums: {total}") - print(f" Spotify albums: {source_counts.get('spotify', 0)}") - print(f" iTunes albums: {source_counts.get('itunes', 0)}") + logger.info(f" Total recent albums: {total}") + logger.info(f" Spotify albums: {source_counts.get('spotify', 0)}") + logger.info(f" iTunes albums: {source_counts.get('itunes', 0)}") if source_counts.get('itunes', 0) == 0 and total > 0: - print(" [CRITICAL] No iTunes albums cached - Recent Releases section will be empty!") + logger.critical("No iTunes albums cached - Recent Releases section will be empty!") elif source_counts.get('itunes', 0) < 5: - print(" [WARNING] Very few iTunes albums cached") + logger.warning("Very few iTunes albums cached") else: - print(" [OK] iTunes albums cached") - + logger.info("iTunes albums cached") except Exception as e: - print(f" [ERROR] Could not check recent albums: {e}") + logger.error(f"Could not check recent albums: {e}") # 4. Check Curated Playlists - print("\n[4] CURATED PLAYLISTS") - print("-" * 40) - + _section("[4] CURATED PLAYLISTS") try: with db._get_connection() as conn: cursor = conn.cursor() @@ -156,7 +147,7 @@ def diagnose_itunes_discover(): 'release_radar_itunes', 'discovery_weekly', 'discovery_weekly_spotify', - 'discovery_weekly_itunes' + 'discovery_weekly_itunes', ] for playlist_type in playlists_to_check: @@ -174,9 +165,8 @@ def diagnose_itunes_discover(): else: status = "[NOT FOUND]" - print(f" {playlist_type}: {status}") + logger.info(f" {playlist_type}: {status}") - # Check iTunes-specific playlists cursor.execute(""" SELECT track_ids_json FROM discovery_curated_playlists WHERE playlist_type = 'release_radar_itunes' @@ -190,49 +180,43 @@ def diagnose_itunes_discover(): itunes_dw = cursor.fetchone() if not itunes_rr or len(json.loads(itunes_rr['track_ids_json'])) == 0: - print("\n [CRITICAL] release_radar_itunes is empty or missing!") + logger.critical("release_radar_itunes is empty or missing!") if not itunes_dw or len(json.loads(itunes_dw['track_ids_json'])) == 0: - print(" [CRITICAL] discovery_weekly_itunes is empty or missing!") - + logger.critical("discovery_weekly_itunes is empty or missing!") except Exception as e: - print(f" [ERROR] Could not check curated playlists: {e}") + logger.error(f"Could not check curated playlists: {e}") # 5. Check Watchlist Artists - print("\n[5] WATCHLIST ARTISTS") - print("-" * 40) - + _section("[5] WATCHLIST ARTISTS") try: with db._get_connection() as conn: cursor = conn.cursor() - # Total artists cursor.execute("SELECT COUNT(*) as total FROM watchlist_artists") total = cursor.fetchone()['total'] - # With iTunes IDs cursor.execute("SELECT COUNT(*) as count FROM watchlist_artists WHERE itunes_artist_id IS NOT NULL") with_itunes = cursor.fetchone()['count'] - # With Spotify IDs cursor.execute("SELECT COUNT(*) as count FROM watchlist_artists WHERE spotify_artist_id IS NOT NULL") with_spotify = cursor.fetchone()['count'] - print(f" Total watchlist artists: {total}") - print(f" With iTunes ID: {with_itunes} ({100*with_itunes/total:.1f}%)" if total > 0 else " With iTunes ID: 0") - print(f" With Spotify ID: {with_spotify} ({100*with_spotify/total:.1f}%)" if total > 0 else " With Spotify ID: 0") + logger.info(f" Total watchlist artists: {total}") + logger.info(f" With iTunes ID: {with_itunes} ({100 * with_itunes / total:.1f}%)" if total > 0 else " With iTunes ID: 0") + logger.info(f" With Spotify ID: {with_spotify} ({100 * with_spotify / total:.1f}%)" if total > 0 else " With Spotify ID: 0") if with_itunes == 0 and total > 0: - print(" [WARNING] No watchlist artists have iTunes IDs - source artist data limited") - + logger.warning("No watchlist artists have iTunes IDs - source artist data limited") except Exception as e: - print(f" [ERROR] Could not check watchlist artists: {e}") + logger.error(f"Could not check watchlist artists: {e}") - # Summary - print("\n" + "=" * 60) - print("SUMMARY & RECOMMENDED ACTIONS") - print("=" * 60) - print(""" -If you see [CRITICAL] or [WARNING] messages above, follow these steps: + logger.info("") + logger.info("=" * 60) + logger.info("SUMMARY & RECOMMENDED ACTIONS") + logger.info("=" * 60) + logger.info( + """ +If you see critical or warning messages above, follow these steps: QUICK FIX - Force Refresh Discover Data: ----------------------------------------- @@ -263,7 +247,8 @@ ROOT CAUSE NOTES: The discover page will now fall back to watchlist artists if similar artists are not available, so basic functionality should still work. -""") +""".strip() + ) if __name__ == '__main__': diff --git a/utils/logging_config.py b/utils/logging_config.py index b29af7ef..1a4beae9 100644 --- a/utils/logging_config.py +++ b/utils/logging_config.py @@ -109,7 +109,7 @@ def set_log_level(level: str) -> bool: root_logger.info(f"Log level changed to: {level.upper()}") return True except Exception as e: - print(f"Error setting log level: {e}") + logging.getLogger("newmusic").error(f"Error setting log level: {e}") return False def get_current_log_level() -> str: @@ -117,4 +117,4 @@ def get_current_log_level() -> str: root_logger = logging.getLogger("newmusic") return logging.getLevelName(root_logger.level) -main_logger = get_logger("main") \ No newline at end of file +main_logger = get_logger("main")