tasks/douyin/(task_type=douyin_nurture)整体删除,唯一任务类型是 generic_steps。 所有默认值/文档/接口示例同步改成 generic_steps: - tasks/:删 douyin 包;__init__ 只注册 generic;base.py/generic 注释改为照 generic 抄 - 默认值:core/models.py(列默认 + 旧 JSON 迁移默认)、core/task_manager.py TaskJob、 web/tasks_api.py 建任务默认、static/admin/tasks.js 新建任务默认 - core/task_manager.py:去掉 douyin 专属的"清理废弃 comment 参数"迁移块,改为**启动时告警** 仍残留已删类型的任务(只告警不改数据);run_job_now 对已删类型直接返回明确错误, 不再"报已触发、线程里静默失败" - 清理残留:douyin_running 状态位(无任何读取方)、core/__init__、core/actions/*、 core/logger.py 注释里的抖音示例 - 文档:README(特性/目录树/类型表/参数表/示例)、TASK_DEV(目录树/注册说明/模板引用)、 ARCHITECTURE(注册示例/action 注册表示例)、API.md(task_types 与任务 JSON 示例)、 AI_TASK_GEN(P1 去掉 douyin 预设)、DEVELOPMENT - 注:示例里"抖音"作为**App 名**(MCP 列应用、AI 建任务的需求举例)保留,与任务类型无关 自测(全部通过):类型列表只剩 generic_steps;建任务不传类型默认 generic_steps;传 douyin_nurture 被 400 拒;库里塞残留旧类型任务 → 启动日志告警 + 执行返回明确错误 + 不自动删用户数据;前端新建任务下拉 1 项且默认选中、界面建任务成功;监控页卡片两个按钮 + 覆盖设备正常。临时任务/数据验完已清理,任务集合复原。
85 lines
2.5 KiB
Python
85 lines
2.5 KiB
Python
"""统一日志系统:按模块分文件,带时间戳和级别,自动滚动。
|
||
|
||
用法:
|
||
from core.logger import get_logger
|
||
log = get_logger("task") # 写 logs/task.log + 控制台
|
||
log.info("开始任务")
|
||
log.error("失败", exc_info=True)
|
||
|
||
模块划分:
|
||
core — 核心程序(STF/adb/worker/task_manager)
|
||
task — 任务执行(worker 业务逻辑)
|
||
web — web_server 请求/管理
|
||
action — 操作执行(点赞/评论等)
|
||
|
||
所有日志同时输出到控制台和对应文件,logs/ 目录自动创建。
|
||
文件按 10MB 滚动,保留 5 个历史文件。
|
||
"""
|
||
import os
|
||
import logging
|
||
from logging.handlers import RotatingFileHandler
|
||
|
||
_LOG_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "logs")
|
||
os.makedirs(_LOG_DIR, exist_ok=True)
|
||
|
||
# 已创建的 logger,避免重复添加 handler
|
||
_LOGGERS = {}
|
||
|
||
# 模块 → 文件名映射
|
||
_MODULE_FILES = {
|
||
"core": "core.log",
|
||
"task": "task.log",
|
||
"web": "web.log",
|
||
"action": "action.log",
|
||
}
|
||
|
||
_FORMAT = "%(asctime)s [%(levelname)s] [%(name)s] %(message)s"
|
||
_DATE_FMT = "%Y-%m-%d %H:%M:%S"
|
||
|
||
|
||
def get_logger(name="core"):
|
||
"""获取指定模块的 logger。
|
||
|
||
name: 模块名(core/task/web/action),决定写哪个文件。
|
||
也可传子模块名如 "task.generic",会归到 task.log。
|
||
返回配置好的 logging.Logger。
|
||
"""
|
||
if name in _LOGGERS:
|
||
return _LOGGERS[name]
|
||
|
||
# 归类到对应文件:取顶层模块名
|
||
top = name.split(".")[0]
|
||
filename = _MODULE_FILES.get(top, "core.log")
|
||
|
||
log = logging.getLogger(name)
|
||
log.setLevel(logging.DEBUG)
|
||
# 避免向 root logger 传播导致重复输出
|
||
log.propagate = False
|
||
|
||
fmt = logging.Formatter(_FORMAT, _DATE_FMT)
|
||
|
||
# 文件 handler:10MB 滚动,保留 5 个
|
||
file_path = os.path.join(_LOG_DIR, filename)
|
||
fh = RotatingFileHandler(file_path, maxBytes=10 * 1024 * 1024,
|
||
backupCount=5, encoding="utf-8")
|
||
fh.setLevel(logging.DEBUG)
|
||
fh.setFormatter(fmt)
|
||
|
||
# 控制台 handler
|
||
ch = logging.StreamHandler()
|
||
ch.setLevel(logging.INFO)
|
||
ch.setFormatter(fmt)
|
||
|
||
log.addHandler(fh)
|
||
log.addHandler(ch)
|
||
|
||
_LOGGERS[name] = log
|
||
return log
|
||
|
||
|
||
# 兼容旧代码的 print 风格:紧急排查时可临时用
|
||
def log_print(msg, level="info", module="core"):
|
||
"""print 的替代品,转发到 logging。"""
|
||
log = get_logger(module)
|
||
getattr(log, level, log.info)(msg)
|