refactor: 重构项目结构,将geo_tools重命名为app并更新相关引用
- 将主包名从geo_tools改为app - 更新所有模块中的引用路径 - 迁移并更新测试用例 - 添加项目规则文档 - 保持原有功能不变,仅进行结构调整
This commit is contained in:
107
app/utils/logger.py
Normal file
107
app/utils/logger.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""
|
||||
geo_tools.utils.logger
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
统一日志工厂,支持同时输出到控制台和文件。
|
||||
|
||||
使用方式
|
||||
--------
|
||||
>>> from geo_tools.utils.logger import get_logger
|
||||
>>> logger = get_logger(__name__)
|
||||
>>> logger.info("处理开始")
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
_LOG_FORMAT = "%(asctime)s | %(levelname)-8s | %(name)s | %(message)s"
|
||||
_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
# 已初始化的 logger 集合,避免重复添加 handler
|
||||
_initialized: set[str] = set()
|
||||
|
||||
|
||||
def get_logger(
|
||||
name: str,
|
||||
level: str | None = None,
|
||||
log_file: Path | str | None = None,
|
||||
*,
|
||||
propagate: bool = False,
|
||||
) -> logging.Logger:
|
||||
"""获取(或创建)一个带格式化 handler 的 Logger。
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name:
|
||||
Logger 名称,通常传入 ``__name__``。
|
||||
level:
|
||||
日志等级字符串;``None`` 时读取 ``settings.log_level``。
|
||||
log_file:
|
||||
日志文件路径;``None`` 时读取 ``settings``:
|
||||
若 ``settings.log_to_file`` 为 True,则写到 ``settings.log_dir/geo_tools.log``。
|
||||
propagate:
|
||||
是否向父 logger 传播,默认 False(避免重复输出)。
|
||||
|
||||
Returns
|
||||
-------
|
||||
logging.Logger
|
||||
"""
|
||||
# 延迟导入,避免循环依赖
|
||||
from app.config.settings import settings as _settings
|
||||
|
||||
if level is None:
|
||||
level = _settings.log_level
|
||||
numeric_level = logging.getLevelName(level.upper())
|
||||
|
||||
logger = logging.getLogger(name)
|
||||
logger.propagate = propagate
|
||||
|
||||
# 已初始化则直接返回,level 可动态调整
|
||||
if name in _initialized:
|
||||
logger.setLevel(numeric_level)
|
||||
return logger
|
||||
|
||||
logger.setLevel(numeric_level)
|
||||
|
||||
formatter = logging.Formatter(_LOG_FORMAT, datefmt=_DATE_FORMAT)
|
||||
|
||||
# ── 控制台 handler ────────────────────────────────────────
|
||||
console_handler = logging.StreamHandler(sys.stdout)
|
||||
console_handler.setLevel(numeric_level)
|
||||
console_handler.setFormatter(formatter)
|
||||
logger.addHandler(console_handler)
|
||||
|
||||
# ── 文件 handler ──────────────────────────────────────────
|
||||
_resolve_log_file = log_file
|
||||
if _resolve_log_file is None and _settings.log_to_file:
|
||||
_settings.ensure_dirs()
|
||||
_resolve_log_file = _settings.log_dir / "geo_tools.log"
|
||||
|
||||
if _resolve_log_file is not None:
|
||||
file_path = Path(_resolve_log_file)
|
||||
file_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
file_handler = logging.FileHandler(file_path, encoding="utf-8")
|
||||
file_handler.setLevel(numeric_level)
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
_initialized.add(name)
|
||||
return logger
|
||||
|
||||
|
||||
def set_global_level(level: str) -> None:
|
||||
"""动态调整所有 geo_tools 下 logger 的日志等级。
|
||||
|
||||
Parameters
|
||||
----------
|
||||
level:
|
||||
目标日志等级,例如 ``"DEBUG"``。
|
||||
"""
|
||||
numeric = logging.getLevelName(level.upper())
|
||||
root = logging.getLogger("geo_tools")
|
||||
root.setLevel(numeric)
|
||||
for handler in root.handlers:
|
||||
handler.setLevel(numeric)
|
||||
Reference in New Issue
Block a user