123 lines
3.7 KiB
Python
123 lines
3.7 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
|
|
APP_LOGGER_NAME = "sync_state_machine"
|
|
|
|
|
|
class ScopeLoggerAdapter(logging.LoggerAdapter):
|
|
def process(self, msg, kwargs):
|
|
scope = self.extra.get("scope")
|
|
if scope and not str(msg).startswith("["):
|
|
msg = f"[{scope}] {msg}"
|
|
return msg, kwargs
|
|
|
|
|
|
class _NodeLogFilter(logging.Filter):
|
|
def filter(self, record: logging.LogRecord) -> bool:
|
|
message = record.getMessage()
|
|
if "node=" in message:
|
|
return False
|
|
if "节点 " in message and "状态" in message:
|
|
return False
|
|
return True
|
|
|
|
|
|
def get_app_logger() -> logging.Logger:
|
|
return logging.getLogger(APP_LOGGER_NAME)
|
|
|
|
|
|
def get_logger(name: Optional[str] = None) -> logging.Logger:
|
|
if not name or name == "__main__":
|
|
return get_app_logger()
|
|
if name == APP_LOGGER_NAME or name.startswith(f"{APP_LOGGER_NAME}."):
|
|
return logging.getLogger(name)
|
|
return logging.getLogger(f"{APP_LOGGER_NAME}.{name}")
|
|
|
|
|
|
def get_scope_logger(scope: str, name: Optional[str] = None) -> logging.LoggerAdapter:
|
|
return ScopeLoggerAdapter(get_logger(name), {"scope": scope})
|
|
|
|
|
|
def clear_app_logger_handlers(logger: Optional[logging.Logger] = None) -> None:
|
|
target = logger or get_app_logger()
|
|
handlers = list(target.handlers)
|
|
for handler in handlers:
|
|
target.removeHandler(handler)
|
|
try:
|
|
handler.close()
|
|
except Exception:
|
|
pass
|
|
target.propagate = True
|
|
|
|
|
|
def init_app_logger(
|
|
*,
|
|
log_file_path: Optional[str] = None,
|
|
level: int = logging.INFO,
|
|
mirror_console: bool = True,
|
|
replace_handlers: bool = True,
|
|
suppress_node_logs: bool = True,
|
|
) -> logging.Logger:
|
|
logger = get_app_logger()
|
|
logger.setLevel(level)
|
|
logger.propagate = False
|
|
|
|
if logger.handlers and not replace_handlers:
|
|
return logger
|
|
|
|
if replace_handlers:
|
|
clear_app_logger_handlers(logger)
|
|
|
|
formatter = logging.Formatter("%(message)s")
|
|
node_filter = _NodeLogFilter() if suppress_node_logs else None
|
|
|
|
if mirror_console:
|
|
console_handler = logging.StreamHandler()
|
|
console_handler.setLevel(level)
|
|
console_handler.setFormatter(formatter)
|
|
if node_filter is not None:
|
|
console_handler.addFilter(node_filter)
|
|
logger.addHandler(console_handler)
|
|
|
|
if log_file_path:
|
|
path = Path(log_file_path)
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
file_handler = logging.FileHandler(path, mode="w", encoding="utf-8")
|
|
file_handler.setLevel(level)
|
|
file_handler.setFormatter(formatter)
|
|
if node_filter is not None:
|
|
file_handler.addFilter(node_filter)
|
|
logger.addHandler(file_handler)
|
|
|
|
return logger
|
|
|
|
|
|
def configure_app_logging(config, *, replace_handlers: bool = False, mirror_console: bool = True) -> logging.Logger:
|
|
if not getattr(config, "initialize", True):
|
|
return get_app_logger()
|
|
|
|
if not getattr(config, "file_path", None):
|
|
from .config.logging_config import resolve_log_file_path
|
|
|
|
config.file_path = resolve_log_file_path(config)
|
|
|
|
return init_app_logger(
|
|
log_file_path=config.file_path,
|
|
level=config.level,
|
|
mirror_console=mirror_console,
|
|
replace_handlers=replace_handlers,
|
|
suppress_node_logs=config.suppress_node_logs,
|
|
)
|
|
|
|
|
|
def ensure_app_logging(config, *, mirror_console: bool = True) -> logging.Logger:
|
|
logger = get_app_logger()
|
|
if not getattr(config, "initialize", True):
|
|
return logger
|
|
if logger.handlers:
|
|
return logger
|
|
return configure_app_logging(config, replace_handlers=False, mirror_console=mirror_console) |