Files
Azornes-Comfyui-Model-Resolver/core/log_system/log_funcs.py
T
Dariusz L 780ef9d0ef refactor(log_system): bump to v1.5.2 — bracket-wrapped console output, shared file handlers, and milliseconds toggle
Console output (ColoredFormatter):
- Level name is now wrapped in [LEVEL] and left-padded via _format_level.
- Timestamp and root-label segments are individually bracket-wrapped, keeping
  plain-output layout consistent with coloured output.
- Separator between fields is colourised (colour code derived from level theme)
  so the table structure remains readable.
- New include_milliseconds init flag controls whether a fractional-second suffix
  is appended to the timestamp; _format_time respects it.
- _display_logger_name unchanged; _split_logger_name still decomposes dotted names
  into root / detail parts.

File logging (AzLogsLogger):
- file_handlers dict introduced to cache one RotatingFileHandler per top-level
  root module, preventing duplicate handlers when multiple sub-modules log to
  the same file (_get_file_handler / _get_log_file / _root_module_name).
- File handler formatter upgraded from a bare logging.Formatter to ColoredFormatter
  (colours off, milliseconds on, datefmt hard-coded to
  '%Y-%m-%d %H:%M:%S') so file output carries the same column structure as
  the console formatter.
- reset_loggers method properly removes and closes all handlers (StreamHandler
  and RotatingFileHandler) from every configured logger before clearing
  self.loggers and self.file_handlers, allowing _get_logger to be called again
  with fresh settings.
- set_file_logging now delegates to reset_loggers instead of simply clearing
  the loggers dict.
2026-05-20 01:34:51 +02:00

247 lines
7.1 KiB
Python

"""
@author: Azornes
@title: AzLogs
@version: 1.5.2
@description: Logging Initializator
"""
# ruff: noqa: T201
import os
import sys
import traceback
import logging
_logger = logging.getLogger(__name__)
LOG_MODULE_NAME = None
_default_module_name = __name__
_initialized = False
_project_root = None
try:
from .logger import logger, LogLevel, debug, info, warn, error, exception
from .config import LOG_LEVEL, LOG_MODULE_NAME, USE_COLORS
def _find_project_root(start_path):
current = os.path.dirname(os.path.abspath(start_path))
while current:
if os.path.isdir(os.path.join(current, ".git")):
return current
parent = os.path.dirname(current)
if parent == current:
break
current = parent
return os.path.dirname(os.path.dirname(os.path.abspath(start_path)))
_project_root = _find_project_root(__file__)
_default_module_name = (
LOG_MODULE_NAME
if LOG_MODULE_NAME is not None
else os.path.basename(_project_root)
)
logger.set_global_level(LogLevel[LOG_LEVEL])
logger.configure(
{
"log_to_file": True,
"log_dir": os.path.join(os.path.dirname(os.path.abspath(__file__)), "logs"),
"use_colors": (
logger.config["use_colors"]
if "AZLOGS_USE_COLORS" in os.environ
else USE_COLORS
),
}
)
_initialized = True
except ImportError as e:
_initialized = False
_logger.error(f"Failed to initialize logger: {e}")
def _normalize_module_name(module_name):
module_name = str(module_name or "").strip()
if not module_name:
return _default_module_name
normalized_path = module_name.replace("/", os.sep).replace("\\", os.sep)
if os.path.isabs(normalized_path):
path_no_ext = os.path.splitext(normalized_path)[0]
if _project_root:
try:
relative_path = os.path.relpath(path_no_ext, _project_root)
except ValueError:
relative_path = os.path.basename(path_no_ext)
else:
relative_path = os.path.basename(path_no_ext)
if relative_path.endswith("__init__"):
relative_path = os.path.dirname(relative_path) or os.path.basename(
os.path.dirname(path_no_ext)
)
cleaned = relative_path.replace(os.sep, ".").strip(".")
return cleaned or _default_module_name
if module_name == "__main__":
return _default_module_name
parts = [part for part in module_name.split(".") if part]
if not parts:
return _default_module_name
if parts[-1] == "__init__":
parts = parts[:-1]
if LOG_MODULE_NAME and parts[0] == LOG_MODULE_NAME:
parts = parts[1:]
if "custom_nodes" in parts:
parts = parts[parts.index("custom_nodes") + 2 :]
if "comfyui-model-linker" in parts:
parts = parts[parts.index("comfyui-model-linker") + 1 :]
cleaned = ".".join(parts).strip(".")
return cleaned or _default_module_name
def _normalize_module_path(file_path):
if not file_path:
return _default_module_name
normalized_path = os.path.normpath(file_path)
path_no_ext = os.path.splitext(normalized_path)[0]
if _project_root:
try:
relative_path = os.path.relpath(path_no_ext, _project_root)
except ValueError:
relative_path = os.path.basename(path_no_ext)
else:
relative_path = os.path.basename(path_no_ext)
parts = [part for part in relative_path.split(os.sep) if part]
if not parts:
return _default_module_name
if parts[-1] == "__init__":
parts = parts[:-1]
package_name = LOG_MODULE_NAME or os.path.basename(_project_root or "")
if package_name:
parts.insert(0, package_name)
cleaned = ".".join(parts).strip(".")
return cleaned or _default_module_name
def _resolve_module_name(stack_depth=2):
if not _initialized:
return _normalize_module_name(LOG_MODULE_NAME or __name__)
try:
frame = sys._getframe(stack_depth)
except ValueError:
return _normalize_module_name(_default_module_name)
file_path = frame.f_globals.get("__file__")
if file_path:
return _normalize_module_path(file_path)
module_name = frame.f_globals.get("__name__")
return _normalize_module_name(module_name)
class ModuleLogger:
def __init__(self, module_name):
self.module_name = module_name
def debug(self, *args, **kwargs):
if _initialized:
kwargs.setdefault("stacklevel", 4)
debug(self.module_name, *args, **kwargs)
else:
print(f"[DEBUG] [{self.module_name}]", *args)
def info(self, *args, **kwargs):
if _initialized:
kwargs.setdefault("stacklevel", 4)
info(self.module_name, *args, **kwargs)
else:
print(f"[INFO] [{self.module_name}]", *args)
def warning(self, *args, **kwargs):
if _initialized:
kwargs.setdefault("stacklevel", 4)
warn(self.module_name, *args, **kwargs)
else:
print(f"[WARN] [{self.module_name}]", *args)
def warn(self, *args, **kwargs):
self.warning(*args, **kwargs)
def error(self, *args, **kwargs):
if _initialized:
kwargs.setdefault("stacklevel", 4)
error(self.module_name, *args, **kwargs)
else:
print(f"[ERROR] [{self.module_name}]", *args)
def exception(self, *args):
if _initialized:
exception(self.module_name, *args, stacklevel=4)
else:
print(f"[ERROR] [{self.module_name}]", *args)
traceback.print_exc()
def create_module_logger(module_name=None):
resolved_name = _normalize_module_name(module_name or _resolve_module_name(stack_depth=2))
return ModuleLogger(resolved_name)
def log_debug(*args, **kwargs):
module_name = _resolve_module_name(stack_depth=2)
if _initialized:
kwargs.setdefault("stacklevel", 4)
debug(module_name, *args, **kwargs)
else:
print(f"[DEBUG] [{module_name}]", *args)
def log_info(*args, **kwargs):
module_name = _resolve_module_name(stack_depth=2)
if _initialized:
kwargs.setdefault("stacklevel", 4)
info(module_name, *args, **kwargs)
else:
print(f"[INFO] [{module_name}]", *args)
def log_warn(*args, **kwargs):
module_name = _resolve_module_name(stack_depth=2)
if _initialized:
kwargs.setdefault("stacklevel", 4)
warn(module_name, *args, **kwargs)
else:
print(f"[WARN] [{module_name}]", *args)
def log_error(*args, **kwargs):
module_name = _resolve_module_name(stack_depth=2)
if _initialized:
kwargs.setdefault("stacklevel", 4)
error(module_name, *args, **kwargs)
else:
print(f"[ERROR] [{module_name}]", *args)
def log_exception(*args):
module_name = _resolve_module_name(stack_depth=2)
if _initialized:
exception(module_name, *args, stacklevel=4)
else:
print(f"[ERROR] [{module_name}]", *args)
traceback.print_exc()