使用结构化日志高效调试
Debug with structured logging
2023年6月5日
一句话判断
Xcode 15 的 Debug Console 完全重做了——元数据不再抢占视觉焦点,过滤系统支持 token 化查询,还有 LLDB 的 “Do What I Mean Print” 省去了记住各种打印命令的烦恼。
这场 Session 讲了什么
Session 分四个部分介绍 Xcode 15 的调试改进:新版 Debug Console、用日志诊断真实 bug 的演示、LLDB 的改进、以及 Unified Logging API 的使用建议。
新版 Debug Console 的核心变化是信息层级的重新设计。日志消息本身是主角,元数据(类型、库、子系统、类别)默认隐藏,通过底部的元数据选项按钮按需显示。单条日志的完整元数据可以通过 Quick Look(空格键)查看,包括调用位置。错误和故障级别的日志会以黄色和红色背景高亮。
过滤系统是最大的亮点。Xcode 15 引入了 token 化过滤——在过滤栏输入时自动补全,支持按 subsystem、category、type 等维度组合过滤。除了手动输入,还有三种快捷过滤方式:过滤菜单提供常用类型过滤,右键点击日志可以隐藏/显示类似日志,自动生成过滤条件。
Session 通过一个真实的 bug 演示(用户资料更新后未保存)展示了如何利用这些工具定位问题:按 category 过滤到账户相关日志,通过日志的源码位置跳转到问题代码,然后用 LLDB 验证修复。
LLDB 的 “Do What I Mean Print”(DWIM)把 p 命令升级为智能打印——它会根据表达式类型自动选择最快的求值方式,不再需要区分 p、po、v、vo 等命令。
值得深挖的点
日志驱动的调试方法:Session 展示的调试流程值得学习——不是先设断点,而是先看日志。在良好的日志实践中,大多数 bug 的定位不需要断点调试。关键是日志中要包含足够的上下文信息(操作类型、对象状态、结果)。
DWIM Print 的设计哲学:p 命令现在会自动判断你想要什么——如果你实现了 CustomStringConvertible,它用 po 的方式展示;如果没有,它用值展示的方式。这种”少让开发者做选择”的思路在工具设计中很有参考价值。
日志分类的实践价值:按 category 组织日志让你能在调试时快速过滤到相关模块。如果你的项目中日志都是 “print到大杂烩” 的风格,DWIM 和过滤都帮不上忙。使用 os.Logger 的 subsystem 和 category 参数是前提条件。
代码片段
使用 Unified Logging API 记录结构化日志:
import os
// 创建带 subsystem 和 category 的 Logger
let accountLogger = Logger(subsystem: "com.app.backyardbirds", category: "account")
// 在关键操作中记录日志
func updateDisplayName(_ name: String) {
accountLogger.info("开始更新显示名称: \(name)")
do {
try database.updateDisplayName(name)
// 错误!忘记更新本地缓存
accountLogger.info("数据库更新成功")
} catch {
accountLogger.error("更新失败: \(error)")
}
}
Xcode 15 中 LLDB 的 DWIM Print:
// 以前需要记住这些命令:
// po account -> 调用 CustomStringConvertible
// p account -> 展示值结构
// v account -> 直接读取内存(最快)
// vo account -> 读取内存 + CustomStringConvertible
// 现在,DWIM Print 自动选择最佳方式:
// (lldb) p account
// Account(displayName: "旧名称", email: "test@example.com")
// 自动选择最快的方式展示最完整的信息
最佳实践
- 使用
os.Logger替代print,设置有意义的 subsystem 和 category - 日志消息应包含操作上下文(谁在做什么、结果是什么)
- 利用 Debug Console 的 token 化过滤按 category 定位问题模块
- 通过右键日志快速隐藏/显示相关日志,缩小排查范围
- 用
p替代po作为默认打印命令,让 DWIM 替你选择最佳展示方式
还有什么值得关注
os.Logger的不同日志级别(debug、info、error、fault)在 Console 中的展示差异- 日志的持久化策略和性能影响
- 在 Instruments 中使用结构化日志进行性能分析
- Debug Console 的过滤语法完整参考