chore: 重构前基线 — 9 个 sync task 全部 ok + akshare 移除 + mairui 资金流接入
状态: - 9 个 sync task(stock_basic / kline_daily / kline_index / kline_5min / moneyflow / industry_sector / sector_features / share_snapshot / market_regime) - 数据源:baostock + mairui + 雪球(pysnowball) + 新浪(4 个) - 项目级约束:永远不用 akshare(已落实) - kline_5min 改用 DB 快照统一全量/增量逻辑 - 零后端 Chrome 扩展 xueqiu_sync(独立项目)
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
"""通用工具。"""
|
||||
from app.core.utils.logging import get_logger, setup_logging
|
||||
|
||||
__all__ = ["get_logger", "setup_logging"]
|
||||
@@ -0,0 +1,60 @@
|
||||
"""统一日志:同时输出到控制台 + 文件。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from pathlib import Path
|
||||
|
||||
from app.core.config import settings
|
||||
|
||||
_INITIALIZED = False
|
||||
|
||||
|
||||
def _build_formatter() -> logging.Formatter:
|
||||
return logging.Formatter(
|
||||
"[%(asctime)s] %(levelname)-5s %(name)s | %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
|
||||
|
||||
def setup_logging(level: str | None = None) -> None:
|
||||
global _INITIALIZED
|
||||
if _INITIALIZED:
|
||||
return
|
||||
|
||||
lvl = (level or settings.log_level or "INFO").upper()
|
||||
root = logging.getLogger()
|
||||
root.setLevel(lvl)
|
||||
# 清掉 uvicorn / sqlalchemy 默认 handler,避免重复输出
|
||||
for h in list(root.handlers):
|
||||
root.removeHandler(h)
|
||||
|
||||
fmt = _build_formatter()
|
||||
|
||||
console = logging.StreamHandler(sys.stdout)
|
||||
console.setFormatter(fmt)
|
||||
root.addHandler(console)
|
||||
|
||||
log_path: Path = settings.log_path
|
||||
file_handler = RotatingFileHandler(
|
||||
log_path / "market_data_sync.log",
|
||||
maxBytes=20 * 1024 * 1024,
|
||||
backupCount=5,
|
||||
encoding="utf-8",
|
||||
)
|
||||
file_handler.setFormatter(fmt)
|
||||
root.addHandler(file_handler)
|
||||
|
||||
# 抑制第三方库过度刷屏
|
||||
logging.getLogger("baostock").setLevel(logging.WARNING)
|
||||
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
||||
logging.getLogger("sqlalchemy.engine").setLevel(logging.WARNING)
|
||||
|
||||
_INITIALIZED = True
|
||||
|
||||
|
||||
def get_logger(name: str) -> logging.Logger:
|
||||
if not _INITIALIZED:
|
||||
setup_logging()
|
||||
return logging.getLogger(name)
|
||||
Reference in New Issue
Block a user