- 人工智能
- 语音
- 交互助手
- 智能硬件
【免费下载链接】mycroft-core
Mycroft Core, the Mycroft Artificial Intelligence platform.
导读
本文聚焦 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参数。
三个关键信息:
- 统一入口:整个项目不鼓励各处各自
logging.getLogger(),而是统一走LOG; - 配置优先:默认级别由系统/用户级配置文件决定,而不是写死在代码里;
- 可编程调整:运行时可以通过修改
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 messageLOG类复制了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)负责:
- 构造默认格式:
'{asctime} | {levelname:8} | {process:5} | {name} | {message}',使用logging.Formatter(..., style='{'),即str.format风格; - 设置毫秒精度:
formatter.default_msec_format = '%s.%03d',时间戳精确到毫秒; - 创建共享 Handler:
logging.StreamHandler(sys.stdout),输出到标准输出; - 读取配置覆盖:若配置中存在
log_format则替换格式,log_level则替换级别; - 开启外部模块日志:
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)展示了总线日志的过滤链:
- whitelist(可选):若定义,仅记录
type以列表中任一字符串开头的消息(如'mycroft.audio.service'可匹配'mycroft.audio.service.play'); - blacklist(必选):读取配置中的
ignore_logs,命中即跳过; - 敏感信息脱敏:对
registration消息,将data["token"]置为None后再输出,防止认证令牌泄露到日志; - 最终输出:仅当
_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两个要点:
propagate = False:每条日志由共享的StreamHandler处理一次即止,不会向上冒泡到根 logger,避免重复输出;这也解释了为什么LOG与logging.getLogger()直用的行为不同——本模块体系完全自洽。- 共享 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模式做日志断言。
九、最佳实践与注意事项
- 始终使用
LOG而非getLogger:getLogger已被标记废弃;LOG自动附带的模块:函数:行号定位信息在排查多进程问题时价值极高。 - 需要临时打标签时:用
LOG('my_tag').debug(...),它会生成一条my_tag命名的日志且不会影响后续日志的自动命名。 - 生产环境调级:优先在
/etc/mycroft/mycroft.conf或~/.config/mycroft/mycroft.conf中修改log_level;不要试图在 DEFAULT 或 REMOTE 配置中设置,否则不会生效(见 mycroft/configuration/mycroft.conf 的注释说明)。 - 运行时免重启调级:使用
mycroft-cli-client的:log level DEBUG/:log bus on命令,或向总线发送mycroft.debug.log消息,即可热切换所有进程的日志级别与总线流量输出。 - 控制总线日志噪音:通过
ignore_logs配置过滤高频消息类型;用create_echo_function的whitelist参数(进程启动时传入)限定只记录关心的消息前缀。 - 敏感信息: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.
相关推荐
如何用codex resume继续任务:codex-plugin-cc到Codex App的完整交接
如何用codex resume继续任务:codex plugin cc到Codex App的完整交接 codex plugin cc 是一款让 Claude C
人工智能AI 插件代码智能体VisDrone-MOT数据集实战:使用IOU-Tracker实现27.7%MOTA的完整流程
VisDrone MOT数据集实战:使用IOU Tracker实现27.7%MOTA的完整流程 IOU Tracker是一个轻量级的Python实现目标跟踪算法
TDengine 日志系统深度解析:普通日志、慢日志与日志级别配置指南
TDengine 日志系统深度解析:普通日志、慢日志与日志级别配置指南 导读 TDengine 通过日志文件记录系统运行状态,是日常运维监控与问题排查的第一手依
数据库时序数据库物联网大数据实时分析云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考