Skip to content

[Feature] 为插件提供独立的 Logger,允许插件自行控制自身日志等级(log level) #9186

Description

@WsureDev

Description / 描述

背景 / 问题

当前 AstrBot 所有插件与核心共用同一个全局 loggerlogging.getLogger("astrbot")):

  • astrbot/__init__.pylogger = logging.getLogger("astrbot")
  • 插件作者通过 from astrbot.api import logger 获取的就是这个全局 logger(见 docs/zh/dev/star/plugin.md请务必使用 from astrbot.api import logger 来获取日志对象)。
  • Star 基类(astrbot/core/star/base.py)内部也是 logger = logging.getLogger("astrbot")
  • LogManager.configure_logger()astrbot/core/log.py)直接对这个共享 logger 调用 logger.setLevel(level)

这意味着无法针对单个插件单独调整日志等级。作者想临时观察某个插件的 debug 细节时,目前只有三种方案,但三者皆有明显缺陷:

方案 1:开启全局 DEBUG level

直接把全局日志等级调到 DEBUG。

  • 🔴 缺陷:会导致所有插件、核心、以及第三方库的 raw 信息一起涌入日志,海量噪声把真正想看的信息淹没,排查效率极差。

方案 2:插件自己写 debug 开关,用 INFO 级别打印

在插件里自己实现一个 debug 配置开关,然后在需要的地方 if self.debug: logger.info(...)

  • 🔴 缺陷:产生大量冗余的 if 判断代码,不够优雅;本质上是在应用层重新发明日志分级,使得 logger 自带的 level 设计被架空。

方案 3:插件运行时动态 logger.setLevel(...)

插件在运行时对共享 logger 调用 setLevel

  • 🔴 缺陷:由于是同一个全局 logger 实例,A 插件改了 level 会直接影响 B 插件乃至核心,插件之间状态互相干涉,稳定性差、行为不可预测。

提议 / 期望行为

为每个插件提供独立的 logger(例如以插件 ID / 模块路径作为 logger name 的 child logger),并允许插件独立设置自身 logger 的 level,互不干扰。

这样带来的收益:

  • 插件作者只需在需要展示细节的地方直接使用 logger.debug(...),无需反复写 if debug: 判断,代码更优雅,也让 logger 的 level 分级机制回归其本来的设计意图。
  • 想分析某个插件行为时,只调高该插件自己的 logger level 到 DEBUG 即可,不会污染全局日志,也不会淹没其他插件/核心的输出。
  • 每个插件的 level 相互隔离,动态调整不会像现在这样产生插件间的状态串扰,稳定性更好。
  • 日志行中已有 plugin_tag(见 _LoguruInterceptHandler / 各 sink 的 format),天然适合按插件维度做过滤与分级。

可选的实现方向(供参考,非硬性要求)

  1. 基于 child logger:在 Star 基类或插件加载流程中,为插件生成 logging.getLogger(f"astrbot.plugin.{plugin_id}") 之类的独立 logger,并让 from astrbot.api import logger 在插件上下文中拿到的是该插件专属 logger(或额外暴露 self.logger)。
    • 现有 LogManager.GetLogger(log_name=...) 已经支持按名字获取并挂载 loguru intercept handler,可复用。
    • 需要注意 propagate 与 handler 的挂载关系,避免重复输出。
  2. 每插件 level 配置 + WebUI 支持:在插件配置或 WebUI「管理行为」中允许为单个插件设置日志等级,PluginManager.load() 时读取并应用到该插件的独立 logger。
  3. 保持向后兼容:核心仍使用 astrbot logger;插件默认继承一个合理的默认等级(如 INFO),仅在作者显式开启时降到 DEBUG。

相关代码位置

  • astrbot/__init__.py — 全局 logger = logging.getLogger("astrbot")
  • astrbot/api/__init__.py — 对外导出 logger
  • astrbot/core/star/base.pyStar 基类中的 logger = logging.getLogger("astrbot")
  • astrbot/core/log.pyLogManager.GetLogger() / configure_logger() / set_queue_handler()
  • astrbot/core/star/star_manager.pyPluginManager.load() 插件加载流程(可在此处为插件注入独立 logger 并应用 level)
  • docs/zh/dev/star/plugin.md — 现有「请使用 from astrbot.api import logger」的开发者指引,需同步更新

Use Case / 使用场景

插件作者在调试/分析单个插件行为时:

  1. 只想看某一个插件的 debug 细节,而不希望开启全局 DEBUG 后被其他插件和核心的海量日志淹没。
  2. 希望在代码里直接写 logger.debug(...),不必再为每条调试日志包裹 if self.debug: 判断,减少冗余代码。
  3. 多个插件同时运行时,某个插件调整自身日志等级不应影响其他插件的日志行为,避免动态 setLevel 造成的插件间状态干涉与不稳定。

典型操作流程(期望):在 WebUI 或插件配置中,把目标插件的日志等级设为 DEBUG → 只有该插件输出 debug 日志 → 排查完毕改回 INFO,全程不影响其他插件与核心。

Willing to Submit PR? / 是否愿意提交PR?

  • Yes, I am willing to submit a PR. / 是的,我愿意提交 PR。

Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:coreThe bug / feature is about astrbot's core, backendenhancementNew feature or requestfeature:pluginThe bug / feature is about AstrBot plugin system.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions