|
|
@@ -0,0 +1,160 @@
|
|
|
+"""应用日志配置 —— 按功能模块分文件输出,带轮转防爆盘"""
|
|
|
+
|
|
|
+import logging
|
|
|
+import logging.config
|
|
|
+import os
|
|
|
+from pathlib import Path
|
|
|
+
|
|
|
+PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
|
|
|
+LOG_DIR = PROJECT_ROOT / "logs"
|
|
|
+
|
|
|
+
|
|
|
+def _log(name: str) -> str:
|
|
|
+ return str(LOG_DIR / f"{name}.log")
|
|
|
+
|
|
|
+
|
|
|
+LOGGING_CONFIG: dict = {
|
|
|
+ "version": 1,
|
|
|
+ "disable_existing_loggers": False,
|
|
|
+ "formatters": {
|
|
|
+ "default": {
|
|
|
+ "format": "%(asctime)s | %(levelname)-5s | %(name)s | %(message)s",
|
|
|
+ "datefmt": "%Y-%m-%d %H:%M:%S",
|
|
|
+ },
|
|
|
+ "brief": {
|
|
|
+ "format": "%(asctime)s | %(levelname)-5s | %(message)s",
|
|
|
+ "datefmt": "%H:%M:%S",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ "handlers": {
|
|
|
+ # ── 按功能分文件 ──
|
|
|
+ "handler_article": {
|
|
|
+ "class": "logging.handlers.RotatingFileHandler",
|
|
|
+ "filename": _log("handler_article"),
|
|
|
+ "maxBytes": 10 * 1024 * 1024,
|
|
|
+ "backupCount": 3,
|
|
|
+ "formatter": "default",
|
|
|
+ "encoding": "utf-8",
|
|
|
+ },
|
|
|
+ "handler_account": {
|
|
|
+ "class": "logging.handlers.RotatingFileHandler",
|
|
|
+ "filename": _log("handler_account"),
|
|
|
+ "maxBytes": 10 * 1024 * 1024,
|
|
|
+ "backupCount": 3,
|
|
|
+ "formatter": "default",
|
|
|
+ "encoding": "utf-8",
|
|
|
+ },
|
|
|
+ "handler_enqueue": {
|
|
|
+ "class": "logging.handlers.RotatingFileHandler",
|
|
|
+ "filename": _log("handler_enqueue"),
|
|
|
+ "maxBytes": 10 * 1024 * 1024,
|
|
|
+ "backupCount": 3,
|
|
|
+ "formatter": "default",
|
|
|
+ "encoding": "utf-8",
|
|
|
+ },
|
|
|
+ "domain_supply": {
|
|
|
+ "class": "logging.handlers.RotatingFileHandler",
|
|
|
+ "filename": _log("domain_content_supply"),
|
|
|
+ "maxBytes": 10 * 1024 * 1024,
|
|
|
+ "backupCount": 3,
|
|
|
+ "formatter": "default",
|
|
|
+ "encoding": "utf-8",
|
|
|
+ },
|
|
|
+ "domain_enqueue": {
|
|
|
+ "class": "logging.handlers.RotatingFileHandler",
|
|
|
+ "filename": _log("domain_enqueue_task"),
|
|
|
+ "maxBytes": 10 * 1024 * 1024,
|
|
|
+ "backupCount": 3,
|
|
|
+ "formatter": "default",
|
|
|
+ "encoding": "utf-8",
|
|
|
+ },
|
|
|
+ "infra": {
|
|
|
+ "class": "logging.handlers.RotatingFileHandler",
|
|
|
+ "filename": _log("infra"),
|
|
|
+ "maxBytes": 10 * 1024 * 1024,
|
|
|
+ "backupCount": 3,
|
|
|
+ "formatter": "default",
|
|
|
+ "encoding": "utf-8",
|
|
|
+ },
|
|
|
+ "server": {
|
|
|
+ "class": "logging.handlers.RotatingFileHandler",
|
|
|
+ "filename": _log("server"),
|
|
|
+ "maxBytes": 10 * 1024 * 1024,
|
|
|
+ "backupCount": 3,
|
|
|
+ "formatter": "default",
|
|
|
+ "encoding": "utf-8",
|
|
|
+ },
|
|
|
+ # ── 控制台(开发时保留)──
|
|
|
+ "console": {
|
|
|
+ "class": "logging.StreamHandler",
|
|
|
+ "formatter": "brief",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ "loggers": {
|
|
|
+ # handler — 按业务功能分 3 组
|
|
|
+ "src.handlers.article_search": {
|
|
|
+ "handlers": ["handler_article", "console"],
|
|
|
+ "level": "INFO",
|
|
|
+ "propagate": False,
|
|
|
+ },
|
|
|
+ "src.handlers.article_fetch_detail": {
|
|
|
+ "handlers": ["handler_article", "console"],
|
|
|
+ "level": "INFO",
|
|
|
+ "propagate": False,
|
|
|
+ },
|
|
|
+ "src.handlers.account_fetch": {
|
|
|
+ "handlers": ["handler_account", "console"],
|
|
|
+ "level": "INFO",
|
|
|
+ "propagate": False,
|
|
|
+ },
|
|
|
+ "src.handlers.account_article_fetch": {
|
|
|
+ "handlers": ["handler_account", "console"],
|
|
|
+ "level": "INFO",
|
|
|
+ "propagate": False,
|
|
|
+ },
|
|
|
+ "src.handlers.account_article_update": {
|
|
|
+ "handlers": ["handler_account", "console"],
|
|
|
+ "level": "INFO",
|
|
|
+ "propagate": False,
|
|
|
+ },
|
|
|
+ "src.handlers.demand_enqueue": {
|
|
|
+ "handlers": ["handler_enqueue", "console"],
|
|
|
+ "level": "INFO",
|
|
|
+ "propagate": False,
|
|
|
+ },
|
|
|
+ # domain
|
|
|
+ "src.domains.content_supply": {
|
|
|
+ "handlers": ["domain_supply", "console"],
|
|
|
+ "level": "INFO",
|
|
|
+ "propagate": False,
|
|
|
+ },
|
|
|
+ "src.domains.demand_enqueue_task": {
|
|
|
+ "handlers": ["domain_enqueue", "console"],
|
|
|
+ "level": "INFO",
|
|
|
+ "propagate": False,
|
|
|
+ },
|
|
|
+ # infra
|
|
|
+ "src.infra": {
|
|
|
+ "handlers": ["infra", "console"],
|
|
|
+ "level": "INFO",
|
|
|
+ "propagate": False,
|
|
|
+ },
|
|
|
+ # server
|
|
|
+ "src.server": {
|
|
|
+ "handlers": ["server", "console"],
|
|
|
+ "level": "INFO",
|
|
|
+ "propagate": False,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ # root — 兜底,未匹配的日志走这里
|
|
|
+ "root": {
|
|
|
+ "handlers": ["console"],
|
|
|
+ "level": "WARNING",
|
|
|
+ },
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+def setup_logging() -> None:
|
|
|
+ """初始化应用日志配置,自动创建 logs/ 目录"""
|
|
|
+ os.makedirs(LOG_DIR, exist_ok=True)
|
|
|
+ logging.config.dictConfig(LOGGING_CONFIG)
|