- core/: database/redis_client/jwt/password/response/exceptions/security/logger/deps/middleware/app - create_app 迁移到 core/app.py,中间件注册顺序与异常处理器原样保留 - extensions/ utils/ apps/ 旧文件全部改为 re-export 垫片,import 路径保持兼容 - 新增 core 单元测试(jwt/password/response/request 共 12 个) Co-Authored-By: Claude <noreply@anthropic.com>
54 lines
1.8 KiB
Python
54 lines
1.8 KiB
Python
# +======================================================================
|
|
# | DjangoAdmin 企业数字化开发平台 [ 赋能开发者,助力企业发展 ]
|
|
# +----------------------------------------------------------------------
|
|
# | Copyright (c) 2021-2026 一米阳光团队 版权所有
|
|
# | 开源协议: Apache-2.0
|
|
# +======================================================================
|
|
|
|
"""结构化日志配置:控制台 + 文件双输出,日志文件位于 logs/ 目录。"""
|
|
|
|
import logging
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# 日志目录(项目根目录下 logs/)
|
|
LOG_DIR = Path(__file__).resolve().parent.parent / "logs"
|
|
LOG_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
_FORMAT = "%(asctime)s | %(levelname)-7s | %(name)s | %(message)s"
|
|
|
|
|
|
def setup_logging(level: int = logging.INFO, log_file: str = "app.log") -> None:
|
|
"""
|
|
配置全局日志:root logger 输出到控制台与文件。
|
|
|
|
Args:
|
|
level: 日志级别
|
|
log_file: 日志文件名(位于 logs/ 目录下)
|
|
"""
|
|
root = logging.getLogger()
|
|
# 避免重复添加 handler
|
|
if any(getattr(h, '_djangoadmin', False) for h in root.handlers):
|
|
return
|
|
|
|
root.setLevel(level)
|
|
formatter = logging.Formatter(_FORMAT)
|
|
|
|
# 控制台
|
|
console = logging.StreamHandler(sys.stdout)
|
|
console.setFormatter(formatter)
|
|
console._djangoadmin = True # type: ignore[attr-defined]
|
|
root.addHandler(console)
|
|
|
|
# 文件
|
|
file_handler = logging.FileHandler(LOG_DIR / log_file, encoding="utf-8")
|
|
file_handler.setFormatter(formatter)
|
|
file_handler._djangoadmin = True # type: ignore[attr-defined]
|
|
root.addHandler(file_handler)
|
|
|
|
# uvicorn/fastapi 默认日志走同样 handler
|
|
for name in ("uvicorn", "fastapi"):
|
|
lg = logging.getLogger(name)
|
|
lg.handlers.clear()
|
|
lg.propagate = True
|