☰
Mycroft Core 日志模块深度指南:LOG 类、配置调级与 messagebus 动态日志控制
2026/10/15 16:19:34 网站建设 项目流程
  • 人工智能
  • 语音
  • 交互助手
  • 智能硬件

【免费下载链接】mycroft-core

Mycroft Core, the Mycroft Artificial Intelligence platform.

项目地址:https://gitcode.com/gh_mirrors/my/mycroft-core
点击查看免费下载

导读

本文聚焦 Mycroft Core 的核心日志设施 ——mycroft.util.log模块(对应 API 文档 doc/source/mycroft.util.log.rst)。该模块提供全局唯一的LOG伪函数式日志类,让开发者无需手动创建 logger 即可获得自动带调用位置(模块名:函数名:行号)的日志输出,同时支持通过mycroft.conf中的log_level/log_format配置全局级别与格式,并能借助 messagebus 上的mycroft.debug.log消息在运行时动态调整所有进程的日志级别。读完本文,你将掌握LOG类的全部用法、底层实现原理、配置方式,以及运行时动态调级的实战技巧。

一、模块定位:一个"伪函数"式的全局日志入口

在 Mycroft Core 中,几乎每一个进程(音频服务、语音服务、技能管理器、enclosure 等)都会使用统一的日志接口。mycroft.util.log模块在文档中是一个 API 参考页面(通过 Sphinxautomodule指令自动生成成员文档),其文档主体即 mycroft/util/log.py 中的实现。模块顶部 docstring 明确说明了设计意图:

该模块提供LOG伪函数(pseudo function),可快速创建一个供使用的 logger 实例。此处创建的 logger 的默认日志级别只能在/etc/mycroft/mycroft.conf或~/.config/mycroft/mycroft.conf中设置;默认级别也可通过编程方式修改LOG.level参数。

三个关键信息:

  1. 统一入口:整个项目不鼓励各处各自logging.getLogger(),而是统一走LOG;
  2. 配置优先:默认级别由系统/用户级配置文件决定,而不是写死在代码里;
  3. 可编程调整:运行时可以通过修改LOG.level类属性立即改变级别。

模块同时保留了一个getLogger(name="MYCROFT")函数,但其 docstring 明确标注"Depreciated. Use LOG instead",属于向后兼容的遗留接口,新代码应一律使用LOG。

二、LOG 类快速上手:两种调用形态

LOG是一个类对象,其用法与标准库logging.Logger极为相似。模块 docstring 中给出了两个典型示例:

>>> LOG.debug('My message: %s', debug_str) 13:12:43.673 - :<module>:1 - DEBUG - My message: hi >>> LOG('custom_name').debug('Another message') 13:13:10.462 - custom_name - DEBUG - Another message

LOG类复制了logging.Logger的标准日志方法,通过_make_log_method(logging.Logger.debug)等调用生成(见 mycroft/util/log.py):

方法对应标准库方法说明
LOG.debug(msg, *args, **kwargs)Logger.debug调试级别,通常仅用于开发期
LOG.info(msg, *args, **kwargs)Logger.info信息级别(默认输出级别)
LOG.warning(msg, *args, **kwargs)Logger.warning警告级别
LOG.error(msg, *args, **kwargs)Logger.error错误级别
LOG.exception(msg, *args, **kwargs)Logger.exception在异常上下文中调用,附带堆栈信息

由于这些方法本质上是标准库Logger方法的代理,因此完全支持标准库的格式化风格,例如LOG.info('Value is %d', 42)以及exc_info=True等关键字参数。

三、自动命名机制:从调用栈推导"模块:函数:行号"

LOG最独特的设计在于 logger 名称的自动生成。在_log()类方法中(mycroft/util/log.py),若未显式设置自定义名称,则通过inspect.stack()回溯调用栈:

  • stack[0]是_log()自身;
  • stack[1]是debug()/info()等代理方法;
  • stack[2]才是真正的调用者,从中取出文件名与行号,并通过inspect.getmodule()获取调用者所在模块的__name__。

最终生成的 logger 名格式为:

模块名:函数名:行号

例如mycroft.skills.skill_loader:load_skill:312。这意味着无需任何额外参数,每条日志天然携带精确的出处,极大方便了多进程环境下(音频、语音、技能各自独立进程)的日志溯源。若栈回溯失败(例如在某些异常线程环境中),则回退为固定名称Mycroft。

当使用LOG('custom_name')形式时,__init__会把_custom_name记录下来,_log()优先使用该自定义名称并在使用后将其重置为None,保证不会污染后续日志。这种"一次性命名"的设计让开发者可以临时为某段逻辑打上专属标签。

四、初始化与全局配置:log_level 与 log_format

4.1 LOG.init() 做了什么

LOG.init()(mycroft/util/log.py)负责:

  1. 构造默认格式:'{asctime} | {levelname:8} | {process:5} | {name} | {message}',使用logging.Formatter(..., style='{'),即str.format风格;
  2. 设置毫秒精度:formatter.default_msec_format = '%s.%03d',时间戳精确到毫秒;
  3. 创建共享 Handler:logging.StreamHandler(sys.stdout),输出到标准输出;
  4. 读取配置覆盖:若配置中存在log_format则替换格式,log_level则替换级别;
  5. 开启外部模块日志:cls.create_logger('').setLevel(cls.level),让第三方库(如urllib3等)也能被本项目统一控制。

init()在包导入时即被调用:mycroft/__init__.py末尾有LOG.init() # read log level from config(mycroft/init.py),因此任何导入mycroft包的进程在启动瞬间就已具备正确的日志配置。

4.2 配置项详解

在默认配置文件 mycroft/configuration/mycroft.conf 中,两个日志配置项的注释非常关键:

// Level of logs to store, one of "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG" // NOTE: This configuration setting is special and can only be changed in the // SYSTEM or USER configuration file, it will not be read if defined in the // DEFAULT (here) or in the REMOTE mycroft config. // If not defined, the default log level is INFO. //"log_level": "INFO", // Format of logs to store. // NOTE: This configuration setting is special and can only be changed in the // SYSTEM or USER configuration file, it will not be read if defined in the // DEFAULT (here) or in the REMOTE mycroft config. // If not defined, the default log format is: // {asctime} | {levelname:8} | {process:5} | {name} | {message} //"log_format": "{asctime} | {levelname:8} | {process:5} | {name} | {message}",

log_level:可选值为"CRITICAL"、"ERROR"、"WARNING"、"INFO"、"DEBUG",未定义时默认INFO。它由logging.getLevelName(config.get('log_level', 'INFO'))解析。

log_format:使用str.format风格(style='{')的格式化字符串,可用的标准字段包括:

字段含义
{asctime}时间戳(含毫秒,如2026-10-14 01:14:28.123)
{levelname:8}级别名,右对齐占 8 字符宽度
{process:5}进程 ID,右对齐占 5 字符宽度
{name}logger 名称(即自动生成的模块:函数:行号)
{message}日志正文

极其重要的限制:log_level与log_format是"特殊配置项",只能写在 SYSTEM 或 USER 级别配置文件,写在 DEFAULT(即本仓库内的mycroft.conf)或 REMOTE(云端下发的mycroft.ai配置)中不会生效。这是 mycroft/util/log.py 中Configuration.get(cache=False, remote=False)这一调用方式的直接体现——读取日志配置时显式排除了 remote 来源。

4.3 配置文件位置

根据 mycroft/configuration/locations.py,Mycroft Core 的本地配置层级为:

  • DEFAULT:mycroft/configuration/mycroft.conf(随仓库发布,仅提供默认值与注释说明);
  • SYSTEM:/etc/mycroft/mycroft.conf(可由环境变量MYCROFT_SYSTEM_CONFIG覆盖);
  • USER:~/.config/mycroft/mycroft.conf(遵循 XDG 规范,由xdg.BaseDirectory解析);
  • 旧版兼容位置:~/.mycroft/mycroft.conf(已废弃,仅作兼容)。

因此,实际调整日志级别的标准做法是在/etc/mycroft/mycroft.conf或~/.config/mycroft/mycroft.conf中加入:

{ "log_level": "DEBUG", "log_format": "{asctime} | {levelname:8} | {process:5} | {name} | {message}" }

配置文件本身支持注释(通过load_commented_json解析,见 mycroft/configuration/config.py),与上面的示例风格一致。

五、运行时动态调级:LOG.level 与 messagebus

5.1 编程方式直接修改

模块 docstring 提到默认级别"也可以通过编程方式修改LOG.level参数"。由于level是类属性,直接在代码中赋值即可全局生效:

from mycroft.util.log import LOG LOG.level = 'DEBUG' # 立即切换到 DEBUG 级别

5.2 通过 messagebus 消息远程调级

Mycroft Core 的日志体系与 messagebus 深度集成。每个基于 messagebus 的进程在启动时都会调用create_echo_function(service, whitelist)(见 mycroft/util/process_utils.py),它注册一个消息回显函数,专门监听总线流量并处理两类日志控制消息:

1)mycroft.debug.log消息 —— 动态调整日志级别:

# 数据格式:{'level': 'DEBUG'} 或 {'bus': True/False}

_update_log_level()会校验level是否属于CRITICAL / ERROR / WARNING / INFO / DEBUG五个合法值,合法则:

  • 设置LOG.level = lvl;
  • 同步设置根 logger 与urllib3的级别(logging.getLogger().setLevel(lvl)),从而也能控制第三方 HTTP 库的输出;
  • 记录一条"Changing log level to: ..."信息日志。

非法值则记录"Invalid level provided: ..."。消息还可以携带bus字段(True/False),用于开关 messagebus 流量日志(见下文第六节)。

2)消息白名单保护:create_echo_function在构建 whitelist 时会强制追加'mycroft.debug.log'(mycroft/util/process_utils.py),确保即使进程只监听指定类型的消息,调级指令也永远不会被过滤掉。

5.3 从 mycroft-cli-client 触发

最终用户无需写代码也能调级:Mycroft 的交互式命令行客户端mycroft-cli-client(mycroft/client/text/text_client.py)内置了log命令:

:log level DEBUG # 广播 mycroft.debug.log {'level': 'DEBUG'} :log bus on # 开启 messagebus 流量日志(on/true/yes 均接受) :log bus off # 关闭(off/false/no)

这些命令会向总线发射Message("mycroft.debug.log", data={'level': level}),由各进程的 echo 函数接收并执行调级。这意味着在多进程部署时,一条消息即可同步调整音频、语音、技能等所有进程的日志级别,无需逐个重启服务。

六、messagebus 流量日志与 ignore_logs 过滤

create_echo_function的完整逻辑(mycroft/util/process_utils.py)展示了总线日志的过滤链:

  1. whitelist(可选):若定义,仅记录type以列表中任一字符串开头的消息(如'mycroft.audio.service'可匹配'mycroft.audio.service.play');
  2. blacklist(必选):读取配置中的ignore_logs,命中即跳过;
  3. 敏感信息脱敏:对registration消息,将data["token"]置为None后再输出,防止认证令牌泄露到日志;
  4. 最终输出:仅当_log_all_bus_messages为真时,以BUS: {...}前缀记录消息 JSON。

默认配置在 mycroft/configuration/mycroft.conf 中:

"ignore_logs": ["enclosure.mouth.viseme", "enclosure.mouth.display"],

这两个是 Mark 1/2 设备外壳的高频动画消息,被默认过滤以避免刷屏。开发者可以按需扩展该列表。注意ignore_logs属于普通配置项,与log_level不同,它可以在 DEFAULT/REMOTE 各级配置中正常生效。

七、create_logger 与 propagate 语义

LOG.create_logger(name)(mycroft/util/log.py)是内部工厂:

@classmethod def create_logger(cls, name): logger = logging.getLogger(name) logger.propagate = False logger.addHandler(cls.handler) return logger

两个要点:

  1. propagate = False:每条日志由共享的StreamHandler处理一次即止,不会向上冒泡到根 logger,避免重复输出;这也解释了为什么LOG与logging.getLogger()直用的行为不同——本模块体系完全自洽。
  2. 共享 handler:所有LOG生成的 logger 复用同一个 handler 与 formatter,格式与目标输出全局一致。

需要留意的是,LOG.init()最后一行cls.create_logger('').setLevel(cls.level)创建的是根 logger(空名称),它的 handler 也是共享的cls.handler,用于兜底那些没有走LOG的第三方模块日志。

八、线程安全与测试佐证

日志模块的线程安全性有专门的单元测试覆盖:test/unittests/util/test_log.py。

测试中的CaptureLogs上下文管理器将sys.stdout重定向到StringIO,并在进入/退出时调用LOG.init()重置状态。核心用例test_threads同时启动100 个线程,每个线程依次输出debug / info / warning / error以及自定义名LOG('testing custom')日志,随后断言所有输出行都能匹配到对应消息内容:

def test_logging(): LOG.debug('testing debug') LOG.info('testing info') LOG.warning('testing warning') LOG.error('testing error') LOG('testing custom').debug('test') for _ in range(100): t = Thread(target=test_logging) t.start() threads.append(t)

该测试同时验证了:自定义命名不会互相污染、多线程并发下日志不丢失、sys.stdout输出路径正确。开发者若需在自己的 skill 或服务中扩展日志行为,可参考该测试的CaptureLogs模式做日志断言。

九、最佳实践与注意事项

  1. 始终使用LOG而非getLogger:getLogger已被标记废弃;LOG自动附带的模块:函数:行号定位信息在排查多进程问题时价值极高。
  2. 需要临时打标签时:用LOG('my_tag').debug(...),它会生成一条my_tag命名的日志且不会影响后续日志的自动命名。
  3. 生产环境调级:优先在/etc/mycroft/mycroft.conf或~/.config/mycroft/mycroft.conf中修改log_level;不要试图在 DEFAULT 或 REMOTE 配置中设置,否则不会生效(见 mycroft/configuration/mycroft.conf 的注释说明)。
  4. 运行时免重启调级:使用mycroft-cli-client的:log level DEBUG/:log bus on命令,或向总线发送mycroft.debug.log消息,即可热切换所有进程的日志级别与总线流量输出。
  5. 控制总线日志噪音:通过ignore_logs配置过滤高频消息类型;用create_echo_function的whitelist参数(进程启动时传入)限定只记录关心的消息前缀。
  6. 敏感信息:messagebus 日志链路会对registration消息的 token 字段自动脱敏;自行扩展日志输出时也应遵循同样的安全原则。

总结

mycroft.util.log虽在文档中只是一个由automodule生成的 API 参考页面,但其背后的实现(mycroft/util/log.py)承载着 Mycroft Core 全部进程的统一日志能力:自动调用位置命名、配置文件驱动的级别与格式、以及通过 messagebus 实现的运行时热调级。配合 mycroft/util/process_utils.py 的总线日志过滤与mycroft-cli-client的交互命令,开发者可以在不重启服务的情况下完成从 INFO 到 DEBUG 的切换、总线流量观测与敏感消息脱敏,这正是排查技能与系统问题时最实用的一套基础设施。

  • 人工智能
  • 语音
  • 交互助手
  • 智能硬件

【免费下载链接】mycroft-core

Mycroft Core, the Mycroft Artificial Intelligence platform.

项目地址:https://gitcode.com/gh_mirrors/my/mycroft-core
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询