2026-05-26 06:31:02 +02:00

124 lines
3.5 KiB
Python

"""
Central logging setup for the application.
- Provides a unified logger via get_logger(__name__)
- Writes all logs to a central rotating log file (logs/app.log)
- Writes errors separately to logs/errors.log
- Automatically includes the module name in each log entry
- Supports standard logging levels: DEBUG, INFO, WARNING, ERROR, CRITICAL
Usage:
from backend.managers.debug_logger import get_logger
logger = get_logger(__name__)
logger.info("Service started")
logger.debug("Debug details")
logger.error("Something went wrong")
try:
...
except Exception:
logger.exception("Unexpected error")
Logging levels (use consistently):
DEBUG: Detailed technical info for developers (variables, flow, internal state).
INFO: Normal application events (start/stop, successful operations, key milestones).
WARNING: Something unexpected happened, but the program continues normally.
ERROR: A specific operation failed, but the application is still running.
CRITICAL: A severe failure that may stop the application or make it unusable.
EXCEPTION: Same as ERROR, but used inside an `except` block and includes stacktrace
(via logger.exception()).
"""
import logging
from logging.handlers import RotatingFileHandler
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
LOG_DIR = BASE_DIR / "logs"
LOG_DIR.mkdir(exist_ok=True)
class DebugLogger:
_initialized = False
_error_log: list[str] = []
@classmethod
def setup(cls):
# prevents multiple setup
if cls._initialized:
return
formatter = logging.Formatter(
"%(asctime)s [%(levelname)s] [%(name)s: Line %(lineno)d] %(message)s"
)
# Main log file
file_handler = RotatingFileHandler(
LOG_DIR / "app.log",
maxBytes=5_000_000,
backupCount=5,
encoding="utf-8"
)
file_handler.setFormatter(formatter)
# Separate Error-Log
error_handler = RotatingFileHandler(
LOG_DIR / "errors.log",
maxBytes=5_000_000,
backupCount=3,
encoding="utf-8"
)
error_handler.setLevel(logging.ERROR)
error_handler.setFormatter(formatter)
root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)
root_logger.addHandler(file_handler)
root_logger.addHandler(error_handler)
#root_logger.propagate = False
cls._initialized = True
@classmethod
def get_logger(cls, name: str):
cls.setup()
return logging.getLogger(name)
@classmethod
def log_error(cls, error_message: str) -> None:
cls.setup()
logging.error(error_message)
cls._error_log.append(error_message)
@classmethod
def get_errors(cls) -> list[str]:
return cls._error_log
@classmethod
def clear_errors(cls) -> None:
cls._error_log.clear()
@classmethod
def format_debug_output(cls, output: dict) -> str:
stdout = output.get("stdout", "").strip() or "(none)"
stderr = output.get("stderr", "").strip() or "(none)"
return_code = output.get("return_code", "")
return (
"=== Execution Result ===\n"
f"Exit Code: {return_code}\n"
"--- stdout ---\n"
f"{stdout}\n"
"--- stderr ---\n"
f"{stderr}"
)
# praktische shortcut function
def get_logger(name: str):
return DebugLogger.get_logger(name)