关于 axiom-xclog-ref
这是 xclog 的参考技能;xclog 是无需依赖的二进制工具,可捕获 iOS 模拟器控制台日志,也可查询连接设备的历史日志,供开发者排查崩溃、静默故障和 Swift 日志问题。
主要功能
- 01捕获 print、debugPrint、NSLog、os_log 和 Logger
- 02列出模拟器中已安装的应用
- 03启动应用并监控日志
- 04查询模拟器或设备的近期日志
- 05过滤输出并限制采集时长或行数
适用场景
- 01检查应用崩溃前的日志
- 02追踪界面无反馈的故障
- 03按子系统或级别查看结构化日志
- 04采集限定范围的日志流用于调试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ charleswiltgen/ axiom --skill axiom-xclog-ref安装后在 Claude Code 中输入/axiom-xclog-ref确认已加载。
详细介绍
xclog 参考(iOS 模拟器控制台捕获)
xclog 通过结合 simctl launch --console(print/debugPrint/NSLog)与 log stream --style json(os_log/Logger)来捕获 iOS 模拟器控制台输出。单个二进制文件,无依赖项。
二进制文件位置
${CLAUDE_PLUGIN_ROOT}/bin/xclog
适用场景
- 运行时崩溃 — 捕获应用崩溃前输出的日志
- 静默失败 — 捕获没有 UI 反馈的网络调用、数据操作失败
- 调试 print() 输出 — 查看应用输出到 stdout/stderr 的内容
- os_log 分析 — 按子系统、类别和级别筛选结构化日志
- 自动化日志捕获 — 使用
--timeout和--max-lines限制收集范围
关键最佳实践
先检查 .axiom/preferences.yaml。 如果没有已保存的偏好设置,先运行 list,再运行 launch,以查找正确的 bundle ID。
应用已在运行? launch 会终止并重新启动应用。如果需要保留当前状态,请使用 attach(仅限 os_log — 不捕获 print())。
# 1. FIRST: Check .axiom/preferences.yaml for saved device and bundle ID
# 2. If no preferences: Discover installed apps
${CLAUDE_PLUGIN_ROOT}/bin/xclog list
# 3. Find the target app's bundle_id from output
# 4. THEN: Launch with the correct bundle ID (restarts app)
${CLAUDE_PLUGIN_ROOT}/bin/xclog launch com.example.MyApp --timeout 30s --max-lines 200
# OR: Attach to running app without restarting (os_log only)
${CLAUDE_PLUGIN_ROOT}/bin/xclog attach MyApp --timeout 30s --max-lines 200
偏好设置
Axiom 会将模拟器偏好设置保存到项目根目录下的 .axiom/preferences.yaml。运行 xclog list 前请先检查此文件 — 如果存在偏好设置,请直接使用已保存的设备和 bundle ID。
读取偏好设置
运行 xclog list 前,请先读取 .axiom/preferences.yaml:
simulator:
device: iPhone 16 Pro
deviceUDID: 1A2B3C4D-5E6F-7890-ABCD-EF1234567890
bundleId: com.example.MyApp
如果文件存在且包含 simulator 部分,请在 xclog 命令中使用已保存的 deviceUDID 和 bundleId。除非用户要求使用其他应用,或已保存的值无效,否则跳过 xclog list。
${CLAUDE_PLUGIN_ROOT}/bin/xclog launch <bundleId> --device <deviceUDID> --timeout 30s --max-lines 200
如果文件不存在或缺少 simulator 部分,则回退到通过 xclog list 查找。
如果在可用模拟器中找不到已保存的 deviceUDID(xclog 或 simctl 运行失败),则回退到查找并保存新的选择。
如果 YAML 格式错误,请提醒开发者并回退到查找。不要覆盖格式错误的文件。
写入偏好设置
成功运行 xclog launch 后,或用户从 xclog list 输出中选择目标应用后,保存设备和 bundle ID:
- 如果
.axiom/不存在,请创建它。然后检查.gitignore:如果文件存在,请检查是否有某一行与.axiom/完全匹配;如果没有,请在新行中追加.axiom/。如果.gitignore不存在,请创建该文件,并将.axiom/作为其内容。 - 如果
.axiom/preferences.yaml存在,请读取它(以保留其他键) - 使用
device、deviceUDID和bundleId更新simulator:部分 - 使用 Write 工具写入合并后的 YAML
写入与上文“读取偏好设置”中所示相同的 simulator: 结构。
命令
list — 查找已安装的应用
${CLAUDE_PLUGIN_ROOT}/bin/xclog list
${CLAUDE_PLUGIN_ROOT}/bin/xclog list --device <udid>
输出(JSON 行):
{"bundle_id":"com.example.MyApp","name":"MyApp","version":"1.2.0"}
{"bundle_id":"com.apple.mobilesafari","name":"Safari","version":"18.0"}
launch — 完整控制台捕获
启动应用并捕获全部输出:print()、debugPrint()、NSLog()、os_log()、Logger。
# Basic launch (JSON output, runs until app exits or Ctrl-C)
${CLAUDE_PLUGIN_ROOT}/bin/xclog launch com.example.MyApp
# Bounded capture (recommended for LLM use)
${CLAUDE_PLUGIN_ROOT}/bin/xclog launch com.example.MyApp --timeout 30s --max-lines 200
# Filter by subsystem
${CLAUDE_PLUGIN_ROOT}/bin/xclog launch com.example.MyApp --subsystem com.example.MyApp.networking
# Filter by regex
${CLAUDE_PLUGIN_ROOT}/bin/xclog launch com.example.MyApp --filter "error|warning|crash"
# Save to file
${CLAUDE_PLUGIN_ROOT}/bin/xclog launch com.example.MyApp --output /tmp/console.log --timeout 60s
attach — 监控运行中的进程
仅通过 os_log 附加到运行中的进程。不捕获 print()/debugPrint()。仅限模拟器。
# By process name
${CLAUDE_PLUGIN_ROOT}/bin/xclog attach MyApp --timeout 30s
# By PID
${CLAUDE_PLUGIN_ROOT}/bin/xclog attach 12345 --max-lines 100
# Filter for errors only
${CLAUDE_PLUGIN_ROOT}/bin/xclog attach MyApp --filter "(?i)error|fault"
show — 搜索历史日志(模拟器 + 实体设备)
搜索近期日志,无需预先启动捕获。适用于模拟器和已连接的实体设备。
# Simulator: show last 5 minutes of MyApp logs
${CLAUDE_PLUGIN_ROOT}/bin/xclog show MyApp --last 5m --max-lines 200
# Simulator: show last 10 minutes, errors only
${CLAUDE_PLUGIN_ROOT}/bin/xclog show MyApp --last 10m --max-lines 100 --filter "(?i)error|fault"
# Physical device: collect and show logs (device must be connected + unlocked)
${CLAUDE_PLUGIN_ROOT}/bin/xclog show MyApp --device-udid 00008101-... --last 5m --max-lines 200
# By PID
${CLAUDE_PLUGIN_ROOT}/bin/xclog show 12345 --last 2m
实体设备工作流:show --device-udid 会运行 log collect,通过 USB 从设备提取日志归档,然后在本地解析。设备必须已连接且已解锁。
何时使用 show 或 attach:
show— “刚才发生了什么?”(事后分析,无需预先设置)attach— “现在正在发生什么?”(实时流式传输,必须在事件发生前启动)
输出格式
默认输出为 JSON 行(每行一个 JSON 对象)。
JSON Schema(默认)
{
"time": "10:30:45.123",
"source": "os_log",
"level": "error",
"subsystem": "com.example.MyApp",
"category": "networking",
"process": "MyApp",
"pid": 12345,
"text": "Connection failed: timeout"
}
| 字段 | 类型 | 是否存在 | 描述 |
|---|---|---|---|
| time | string | 始终 | HH:MM:SS.mmm 时间戳 |
| source | string | 始终 | "print"、"stderr" 或 "os_log" |
| level | string | 仅 os_log | "debug"、"default"、"info"、"error"、"fault" |
| subsystem | string | 仅 os_log | 反向 DNS 子系统(例如 com.example.MyApp) |
| category | string | 仅 os_log | 子系统中的日志类别 |
| process | string | 仅 os_log | 进程二进制文件名 |
| pid | int | 仅 os_log | 进程 ID |
| text | string | 始终 | 日志消息内容 |
不适用于某个来源的字段会被省略(而不是设为 null)。
人类可读模式
${CLAUDE_PLUGIN_ROOT}/bin/xclog attach MyApp --human
${CLAUDE_PLUGIN_ROOT}/bin/xclog attach MyApp --human --no-color
选项参考
| 选项 | 默认值 | 描述 |
|---|---|---|
--device <udid> | booted | 目标模拟器 UDID |
--device-udid <udid> | none | 实体设备 UDID(show 命令) |
--output <file> | stdout | 同时写入文件 |
--human | off | 人类可读的彩色输出 |
--no-color | off | 禁用 ANSI 颜色(--human 模式) |
--filter <regex> | none | 使用 Go 正则表达式筛选行 |
--subsystem <name> | none | 按子系统筛选 os_log |
--max-lines <n> | 0 (unlimited) | 达到 n 行后停止 |
--timeout <duration> | 0 (unlimited) | 达到指定时长后停止(例如 30s、5m) |
--last <duration> | 5m | 向前搜索的时间范围(show 命令) |
各来源的覆盖情况
| Swift API | launch | attach | show |
|---|---|---|---|
print() | 是 | 否 | 否 |
debugPrint() | 是 | 否 | 否 |
NSLog() | 是 | 是 | 是 |
os_log() | 是 | 是 | 是 |
Logger | 是 | 是 | 是 |
| 模拟器 | 实体设备 | |
|---|---|---|
launch | 是 | 否 |
attach | 是 | 否 |
show | 是 | 是 |
Logger | 是 | 是 |
如需完整覆盖,请使用 launch。 attach 用于监控已在运行的进程。
注意:launch 会在重新启动应用前终止其所有现有实例。如果应用已在运行,且你不想重启它,请使用 attach(仅限 os_log)。
错误行为
xclog 会将错误打印到 stderr,并以代码 1 退出。常见错误:
| 错误 | 原因 | 修复方法 |
|---|---|---|
simctl launch: ... | Bundle ID 错误或没有已启动的模拟器 | 运行 xclog list 验证 Bundle ID;检查 xcrun simctl list devices booted |
could not parse PID from simctl output | 应用启动失败 | 检查应用是否能在模拟器中成功构建和运行 |
invalid filter regex | --filter 模式错误 | 检查 Go 正则表达式语法(类似 RE2) |
invalid subsystem | 子系统包含空格或特殊字符 | 使用反向 DNS 格式:com.example.MyApp(仅限字母数字字符、点、下划线和连字符) |
解读输出
按级别筛选
os_log 级别表示严重程度。诊断崩溃时,请重点关注 error 和 fault。
注意:--filter 匹配的是消息文本,而不是 JSON 输出。要按级别筛选,请使用 jq:
${CLAUDE_PLUGIN_ROOT}/bin/xclog launch com.example.MyApp --timeout 30s 2>/dev/null | jq -c 'select(.level == "error" or .level == "fault")'
要按文本筛选,--filter 会匹配消息内容:
# Filter messages containing "error" or "failed" (case-insensitive)
${CLAUDE_PLUGIN_ROOT}/bin/xclog launch com.example.MyApp --filter "(?i)error|failed"
常见子系统模式
| 子系统 | 表示内容 |
|---|---|
com.apple.network | URLSession / 网络层 |
com.apple.coredata | Core Data / 持久化 |
com.apple.swiftui | SwiftUI 框架 |
com.apple.uikit | UIKit 框架 |
| 应用自身的子系统 | 应用级日志记录 |
工作流:诊断运行时崩溃
xclog list→ 查找 Bundle IDxclog launch <bundle-id> --timeout 60s --max-lines 500 --output /tmp/crash.log→ 开始捕获(这会重启应用,属于预期行为)- 在模拟器中重现崩溃
- 读取
/tmp/crash.log并筛选错误:jq 'select(.level == "error" or .level == "fault")' /tmp/crash.log - 检查流结束前的最后几行(崩溃点)
如果崩溃是间歇性的,请增大限制:--timeout 120s --max-lines 1000,然后重试。
工作流:排查静默故障
xclog launch <bundle-id> --subsystem com.example.MyApp --timeout 30s- 触发失败的操作
- 查找应用子系统中的错误级别消息
- 如果应用日志没有输出,请与网络或数据子系统交叉参照
资源
技能:axiom-xcode-debugging、axiom-performance-profiling、axiom-lldb