看清模拟器内部:Baguette logs 实时追踪统一日志与级别/Bundle 过滤完全指南
【免费下载链接】baguetteHeadless control for Apple's Simulators — 3D models, taps, swipes, multi-finger gestures, 60 fps streaming, and a multi-device farm项目地址: https://gitcode.com/gh_mirrors/baguette/baguette
做 iOS 开发或自动化时,截图只能告诉你"屏幕现在长什么样",却回答不了"模拟器此刻正在做什么"。Baguette 是一款面向 Apple 模拟器的无头(headless)控制工具,它的baguette logs子命令可以把已启动模拟器的统一日志实时逐行推送到终端,并支持按日志级别、输出风格、NSPredicate 与Bundle ID 过滤——就像给模拟器装了一台"实时监测仪"。
为什么需要模拟器实时日志流 📡
Baguette 的能力矩阵里,screenshot与describe-ui回答的是"此刻",而日志回答的是"过程":
- 应用生命周期切换、崩溃与异常
- 系统进程之间的请求与错误
- 你在自动化脚本里"盲操作"时,模拟器内部的真实反应
过去要手动敲xcrun simctl spawn <udid> log stream才能做到,参数繁琐、难以和自动化流程组合。baguette logs把这件事压缩成一条命令,并且天然支持 shell 管道组合,例如baguette logs --udid X | grep -i error,或者重定向到文件留档。
一键启动:baguette logs 核心用法
安装 Baguette 后(参考仓库 README.md),只要模拟器处于 booted 状态,这条命令就能立即跑起来:
baguette logs --udid <UDID> # 默认 info 及以上、default 风格 baguette logs --udid <UDID> --level debug # 包含 debug 级的一切"碎碎念" baguette logs --udid <UDID> --style json # 每行一个 JSON 对象 baguette logs --udid <UDID> --bundle-id com.apple.MobileSafari baguette logs --udid <UDID> | grep -i error # 与管道自由组合按 Ctrl-C(SIGINT)即可干净地结束流。全部参数的官方参考见 docs/features/logs/README.md 与 docs/commands.md。
参数速查表
| 参数 | 默认值 | 作用 |
|---|---|---|
--udid | 必填 | 指定要追踪的模拟器 |
--level | info | 最低日志级别:default/info/debug |
--style | default | 输出风格:default/compact/json/syslog/ndjson |
--predicate | 无 | 原样传给log stream --predicate的 NSPredicate |
--bundle-id | 无 | 按进程 Bundle/镜像名过滤,等价于process == "<id>" |
这些选项在 LogsCommand.swift 中定义,取值范围直接读取自领域层,保证 help 文案和实际解析逻辑永不漂移。
级别过滤:只有 default / info / debug 三档
很多从 macOS 宿主log工具迁过来的同学会发现:宿主端支持的notice、error、fault在这里统统不接受⚠️
原因很具体:模拟器 iOS 运行时里打包的log程序是"瘦身版",只认三档级别,每档的语义都是"包含该严重度及以上的事件"——所以default一档其实已经覆盖了 default / error / fault。Baguette 选择在入口处直接拒绝非法级别(快速失败),而不是把参数透传下去等系统报错。级别解析逻辑见 LogFilter.swift。
💡 想只看错误?用 predicate:
--predicate 'messageType == "error"',这是官方推荐的"按严重度过滤"姿势。
Bundle 过滤:精准锁定一个应用
--bundle-id是最高频的便捷参数。它会被翻译成 NSPredicate 中的process == "<id>";如果你同时给了--predicate,两者会用 AND 组合,翻译与转义逻辑都在 LogFilter.swift 里(连com.acme."weird"这类带引号的怪 ID 都已转义处理)。
典型场景——排查双击手势时官方示例(来自 docs/features/double-tap/README.md):
baguette logs --udid "$UDID" \ --predicate 'process == "SpringBoard" OR process == "<your-app>"'NSPredicate 高级过滤与输出风格
--predicate是原样透传的"逃生舱",能按 subsystem、category、事件名等任意维度裁剪日志流:
baguette logs --udid <UDID> --predicate 'subsystem == "com.apple.UIKit"'而--style json/--style ndjson会让每一行都是一个完整 JSON 文档,方便你的脚本二次解析、入库或喂给 AI 分析——这对写自动化断言("日志里是否出现过某事件")特别顺手。
serve 模式:通过 WebSocket 订阅实时日志流
如果你在跑baguette serve起多设备农场,日志同样可以走 WebSocket——每个消费者一条独立 socket:
WS /simulators/<UDID>/logs?level=info&style=compact WS /simulators/<UDID>/logs?bundleId=com.apple.MobileSafari服务端帧结构极简:连接先发{"type":"log_started"},之后每行日志发{"type":"log","line":"…"},结束时发{"type":"log_stopped"};想提前结束就发{"type":"stop"}。注意两个设计约束:
- 过滤条件在连接时固定,想换过滤就重连(便宜且无歧义)
- 慢客户端最多落后 2048 行,再落后会静默丢弃旧行(保留最新),暂无
log_dropped提示
协议细节见 docs/features/logs/README.md。
幕后机制:为什么要借道 simctl
设计文档里有一条耐人寻味的"坑"(docs/features/logs/design.md):直接调用 CoreSimulator 的SimDevice.spawn启动log stream看似几乎可行,但会在模拟器内报Must be admin to run 'stream' command——因为 Apple 只对simctl这类官方签名进程授予特权 bootstrap 上下文。Baguette 因此选择xcrun simctl spawn <udid> log stream …借道执行,稳定且零额外依赖。
数据通路上还有两个小角色,都做到了纯值类型、可单测:
- LineBuffer.swift:把原始字节流按
\n切行,残缺的半行留到下一块再拼,坏 UTF-8 行直接跳过而不是中断整个流 - LogBatcher.swift:面向浏览器端按"200 行或 50ms"成批打包,把每秒几百行的日志量压到约 20 帧/秒,避免打满前端主线程
常见坑位清单 ⚠️
--level只有三档:notice/error/fault会被拒绝,按严重度过滤请用 predicate- 只有实时流:没有历史
log show查询,回放磁盘日志请直接xcrun simctl spawn <udid> log show … - 一条流一个过滤器:改过滤 = 重连/重跑命令
- 别指望慢消费者不丢行:WebSocket 落后 2048 行开始静默截断
相关文档与源码
| 资源 | 路径 |
|---|---|
| 功能速览与示例 | docs/features/logs/README.md |
| 设计决策(为何借道 simctl、线程模型) | docs/features/logs/design.md |
| CLI 命令实现 | Sources/Baguette/App/Commands/LogsCommand.swift |
| 过滤条件与 argv 生成 | Sources/Baguette/Domain/Logs/LogFilter.swift |
| 流生命周期协议 | Sources/Baguette/Domain/Logs/LogStream.swift |
| 子进程封装 | Sources/Baguette/Domain/Logs/Subprocess.swift |
| 全量命令参考 | docs/commands.md |
一条baguette logs,让模拟器的"内心活动"第一次变得可见、可过滤、可断言——调试自动化脚本、观察系统行为、甚至训练 AI 分析日志,从此都有了干净的数据源。
【免费下载链接】baguetteHeadless control for Apple's Simulators — 3D models, taps, swipes, multi-finger gestures, 60 fps streaming, and a multi-device farm项目地址: https://gitcode.com/gh_mirrors/baguette/baguette
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考