1. 使用的系统/方案

本仓库为基于 MicroPython 的掌控板固件,日志系统由两部分组成:

  • Python 层:在 firmware/port/modules/logging.py 和 esp32s3/firmware/modules/logging.py 中实现了 Python 标准库 logging 的一个精简子集(兼容 MicroPython 环境),提供 Logger、getLogger、basicConfig、DEBUG/INFO/WARNING/ERROR/CRITICAL 常量及 debug/info/warning/error/critical/exc/exception 方法。

  • C 层:通过 sys.stderr 作为默认输出流,底层实际依赖 MicroPython 运行时将 print() / _stream.write() 重定向到 REPL 或串口调试输出;C 扩展 builtins 未实现独立的日志框架,仅通过 sys.print_exception 输出异常堆栈。

该实现是 MicroPython 官方 logging 模块的精简移植,并非自研框架。

2. 关键文件

文件

层级

作用

firmware/port/modules/logging.py

Python 扩展模块(ESP32 端口)

提供 logging 模块实现

esp32s3/firmware/modules/logging.py

Python 扩展模块(ESP32-S3 端口)

同上,与 ESP32 端口完全一致

esp32s3/firmware/modules/uwebsockets/client.py

Python 扩展模块

使用 logging.getLogger(__name__) 记录 WebSocket 连接调试信息

esp32s3/firmware/modules/uwebsockets/protocol.py

Python 扩展模块

同上

firmware/port/file_system/uwebsockets/*.py

文件系统 Python 模块

同上,用于 SD/Flash 上的用户代码

3. 架构与约定

日志级别

采用与 Python 标准库一致的数值定义:NOTSET=0, DEBUG=10, INFO=20, WARNING=30, ERROR=40, CRITICAL=50。每个 Logger 实例维护自己的 level,若未设置则回退到模块级全局 _level(默认 INFO)。判断条件为 level >= (self.level or _level)。

输出格式

每条日志输出形如 LEVEL:name:msg,其中 level 标签映射为 CRIT/ERROR/WARN/INFO/DEBUG,未知级别显示为 LVL<n>。名称来自 getLogger(name) 传入的模块名或 None。

输出目标

默认输出流 _stream = sys.stderr,可通过 basicConfig(stream=...) 替换。filename 和 format 参数被显式忽略并打印提示:logging.basicConfig: filename arg is not supported / format arg is not supported。

Logger 缓存

模块内维护 _loggers = {} 字典,getLogger(name) 按 name 复用 Logger 实例,避免重复创建。

异常输出

exc(e, msg) 先以 ERROR 级别输出消息,再调用 sys.print_exception(e, _stream) 输出完整堆栈;exception(msg) 从当前异常上下文获取异常对象后委托给 exc。

顶层便捷函数

logging.info() 和 logging.debug() 直接操作一个默认的 getLogger(None) 实例,便于快速输出。

4. 使用模式与约束

  • 模块级 logger 模式:uwebsockets 等模块通过 LOGGER = logging.getLogger(__name__) 获取命名 logger,并以 __debug__ 条件开关控制 debug 级别输出,这是仓库中观察到的唯一使用方式。

  • 无结构化字段:日志输出仅为字符串拼接,不支持结构化字段(JSON、键值对等)。

  • 无多 sink:仅支持单一 sys.stderr 输出,无法同时写入文件、网络或 SPIFFS/LittleFS。

  • 无异步/线程安全:实现为同步单进程模型,未考虑并发保护。

  • C 层无独立日志:C 扩展 builtins(firmware/port/builtins/、esp32s3/firmware/builtins/)未发现自定义日志宏或 ESP_LOG* 调用,C 层调试依赖 MicroPython 运行时的 printf/REPL 输出。

  • 与 MicroPython 行为对齐:该实现遵循 MicroPython 对 logging 的标准裁剪策略——保留核心 API,移除 handler/formatter 等重量组件。

5. 结论

仓库的日志系统是一个轻量级的 Python 层 logging 适配,面向资源受限的嵌入式 MicroPython 环境,输出统一走 sys.stderr(即串口/REPL)。它不具备生产级日志系统的特性(多 sink、结构化、异步、过滤链),但足以满足开发调试阶段按级别过滤的文本日志需求。