File size: 5,600 Bytes
63f0b06 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | """
Centralized Logging System for Fragmenta Desktop
Replaces scattered print statements with structured logging
"""
import logging
import sys
from pathlib import Path
from typing import Optional
from datetime import datetime
import os
# Color codes for console output
class Colors:
RESET = '\033[0m'
BOLD = '\033[1m'
RED = '\033[91m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
BLUE = '\033[94m'
PURPLE = '\033[95m'
CYAN = '\033[96m'
class ColoredFormatter(logging.Formatter):
"""Custom formatter that adds colors to log levels"""
COLORS = {
'DEBUG': Colors.CYAN,
'INFO': Colors.GREEN,
'WARNING': Colors.YELLOW,
'ERROR': Colors.RED,
'CRITICAL': Colors.RED + Colors.BOLD
}
def format(self, record):
if hasattr(record, 'levelname'):
color = self.COLORS.get(record.levelname, Colors.RESET)
record.levelname = f"{color}{record.levelname}{Colors.RESET}"
formatted = super().format(record)
if sys.platform == 'win32':
try:
formatted.encode('charmap')
except UnicodeEncodeError:
formatted = formatted.encode('ascii', 'replace').decode('ascii')
return formatted
class FragmentaLogger:
_instance = None
_loggers = {}
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self):
if not self._initialized:
self.setup_logging()
self._initialized = True
def setup_logging(self, log_level: str = None, log_file: bool = True):
if sys.platform == 'win32':
try:
sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')
except AttributeError:
import codecs
sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer, 'ignore')
sys.stderr = codecs.getwriter('utf-8')(sys.stderr.buffer, 'ignore')
if log_level is None:
log_level = os.environ.get('FRAGMENTA_LOG_LEVEL', 'INFO').upper()
numeric_level = getattr(logging, log_level, logging.INFO)
log_dir = Path("logs")
log_dir.mkdir(exist_ok=True)
root_logger = logging.getLogger()
root_logger.setLevel(numeric_level)
root_logger.handlers.clear()
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(numeric_level)
console_format = "%(asctime)s | %(levelname)s | %(name)s | %(message)s"
console_formatter = ColoredFormatter(
console_format, datefmt='%H:%M:%S')
console_handler.setFormatter(console_formatter)
root_logger.addHandler(console_handler)
if log_file:
log_filename = f"fragmenta_{datetime.now().strftime('%Y%m%d')}.log"
file_handler = logging.FileHandler(log_dir / log_filename)
file_handler.setLevel(logging.DEBUG)
file_format = "%(asctime)s | %(levelname)s | %(name)s | %(funcName)s:%(lineno)d | %(message)s"
file_formatter = logging.Formatter(
file_format, datefmt='%Y-%m-%d %H:%M:%S')
file_handler.setFormatter(file_formatter)
root_logger.addHandler(file_handler)
logger = self.get_logger('FragmentaLogger')
logger.info(f"Logging system initialized (Level: {log_level})")
if log_file:
logger.info(f"Log file: {log_dir / log_filename}")
def get_logger(self, name: str) -> logging.Logger:
if name not in self._loggers:
self._loggers[name] = logging.getLogger(name)
return self._loggers[name]
_fragmenta_logger = FragmentaLogger()
def setup_logging(log_level: str = None, log_file: bool = True):
_fragmenta_logger.setup_logging(log_level, log_file)
def get_logger(name: str) -> logging.Logger:
return _fragmenta_logger.get_logger(name)
def log_function_call(func):
def wrapper(*args, **kwargs):
logger = get_logger(func.__module__)
logger.debug(
f"[CALL] {func.__name__} with args={args}, kwargs={kwargs}")
try:
result = func(*args, **kwargs)
logger.debug(f"{func.__name__} completed successfully")
return result
except Exception as e:
logger.error(f"{func.__name__} failed: {e}")
raise
return wrapper
def log_performance(func):
def wrapper(*args, **kwargs):
import time
logger = get_logger(func.__module__)
start_time = time.time()
try:
result = func(*args, **kwargs)
elapsed = time.time() - start_time
logger.info(f"{func.__name__} completed in {elapsed:.2f}s")
return result
except Exception as e:
elapsed = time.time() - start_time
logger.error(f"{func.__name__} failed after {elapsed:.2f}s: {e}")
raise
return wrapper
def print_info(message: str, component: str = "Legacy"):
logger = get_logger(component)
logger.info(message)
def print_error(message: str, component: str = "Legacy"):
logger = get_logger(component)
logger.error(message)
def print_warning(message: str, component: str = "Legacy"):
logger = get_logger(component)
logger.warning(message)
def print_debug(message: str, component: str = "Legacy"):
logger = get_logger(component)
logger.debug(message)
|