Files
2025-11-29 18:28:37 +08:00

7.7 KiB

CLI Observability

Complete debugging and monitoring without opening Xcode. Claude has full visibility into build errors, runtime logs, crashes, memory issues, and network traffic.

```bash # Install observability tools (one-time) brew tap ldomaradzki/xcsift && brew install xcsift brew install mitmproxy xcbeautify ```

<build_output>

Build Error Parsing

xcsift converts verbose xcodebuild output to token-efficient JSON for AI agents:

xcodebuild -project MyApp.xcodeproj -scheme MyApp build 2>&1 | xcsift

Output includes structured errors with file paths and line numbers:

{
  "status": "failed",
  "errors": [
    {"file": "/path/File.swift", "line": 42, "message": "Type mismatch..."}
  ]
}

Alternative (human-readable):

xcodebuild build 2>&1 | xcbeautify

</build_output>

<runtime_logging>

Runtime Logs

In-App Logging Pattern

Add to all apps:

import os

extension Logger {
    static let app = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "App")
    static let network = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "Network")
    static let data = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "Data")
}

// Usage
Logger.network.debug("Request: \(url)")
Logger.data.error("Save failed: \(error)")

Stream Logs from Running App

# All logs from your app
log stream --level debug --predicate 'subsystem == "com.yourcompany.MyApp"'

# Filter by category
log stream --level debug \
  --predicate 'subsystem == "com.yourcompany.MyApp" AND category == "Network"'

# Errors only
log stream --predicate 'subsystem == "com.yourcompany.MyApp" AND messageType == error'

# JSON output for parsing
log stream --level debug --style json \
  --predicate 'subsystem == "com.yourcompany.MyApp"'

Search Historical Logs

# Last hour
log show --predicate 'subsystem == "com.yourcompany.MyApp"' --last 1h

# Export to file
log show --predicate 'subsystem == "com.yourcompany.MyApp"' --last 1h > logs.txt

</runtime_logging>

<crash_analysis>

Crash Logs

Find Crashes

# List crash reports
ls ~/Library/Logs/DiagnosticReports/ | grep MyApp

# View latest crash
cat ~/Library/Logs/DiagnosticReports/MyApp_*.ips | head -200

Symbolicate with atos

# Get load address from "Binary Images:" section of crash report
xcrun atos -arch arm64 \
  -o MyApp.app.dSYM/Contents/Resources/DWARF/MyApp \
  -l 0x104600000 \
  0x104605ca4

# Verify dSYM matches
xcrun dwarfdump --uuid MyApp.app.dSYM

Symbolicate with LLDB

xcrun lldb
(lldb) command script import lldb.macosx.crashlog
(lldb) crashlog /path/to/crash.ips

</crash_analysis>

## LLDB Debugging

Attach to Running App

# By name
lldb -n MyApp

# By PID
lldb -p $(pgrep MyApp)

Launch and Debug

lldb ./build/Build/Products/Debug/MyApp.app/Contents/MacOS/MyApp
(lldb) run

Essential Commands

# Breakpoints
(lldb) breakpoint set --file ContentView.swift --line 42
(lldb) breakpoint set --name "AppState.addItem"
(lldb) breakpoint set --name saveItem --condition 'item.name == "Test"'

# Watchpoints (break when value changes)
(lldb) watchpoint set variable self.items.count

# Execution
(lldb) continue    # or 'c'
(lldb) next        # step over
(lldb) step        # step into
(lldb) finish      # step out

# Inspection
(lldb) p variable
(lldb) po object
(lldb) frame variable   # all local vars
(lldb) bt               # backtrace
(lldb) bt all           # all threads

# Evaluate expressions
(lldb) expr self.items.count
(lldb) expr self.items.append(newItem)

<memory_debugging>

Memory Debugging

Leak Detection

# Check running process for leaks
leaks MyApp

# Run with leak check at exit
leaks --atExit -- ./MyApp

# With stack traces (shows where leak originated)
MallocStackLogging=1 ./MyApp &
leaks MyApp

Heap Analysis

# Show heap summary
heap MyApp

# Show allocations of specific class
heap MyApp -class NSString

# Virtual memory regions
vmmap --summary MyApp

Profiling with xctrace

# List templates
xcrun xctrace list templates

# Time Profiler
xcrun xctrace record \
  --template 'Time Profiler' \
  --time-limit 30s \
  --output profile.trace \
  --launch -- ./MyApp.app/Contents/MacOS/MyApp

# Leaks
xcrun xctrace record \
  --template 'Leaks' \
  --time-limit 5m \
  --attach $(pgrep MyApp) \
  --output leaks.trace

# Export data
xcrun xctrace export --input profile.trace --toc

</memory_debugging>

## Sanitizers

Enable via xcodebuild flags:

# Address Sanitizer (memory errors, buffer overflows)
xcodebuild test \
  -project MyApp.xcodeproj \
  -scheme MyApp \
  -enableAddressSanitizer YES

# Thread Sanitizer (race conditions)
xcodebuild test \
  -project MyApp.xcodeproj \
  -scheme MyApp \
  -enableThreadSanitizer YES

# Undefined Behavior Sanitizer
xcodebuild test \
  -project MyApp.xcodeproj \
  -scheme MyApp \
  -enableUndefinedBehaviorSanitizer YES

Note: ASAN and TSAN cannot run simultaneously.

<network_inspection>

Network Traffic Inspection

mitmproxy Setup

# Run proxy (defaults to localhost:8080)
mitmproxy   # TUI
mitmdump    # CLI output only

Configure macOS Proxy

# Enable
networksetup -setwebproxy "Wi-Fi" 127.0.0.1 8080
networksetup -setsecurewebproxy "Wi-Fi" 127.0.0.1 8080

# Disable when done
networksetup -setwebproxystate "Wi-Fi" off
networksetup -setsecurewebproxystate "Wi-Fi" off

Log Traffic

# Log all requests
mitmdump -w traffic.log

# Filter by domain
mitmdump --filter "~d api.example.com"

# Verbose (show bodies)
mitmdump -v

</network_inspection>

<test_results>

Test Result Parsing

# Run tests with result bundle
xcodebuild test \
  -project MyApp.xcodeproj \
  -scheme MyApp \
  -resultBundlePath TestResults.xcresult

# Get summary
xcrun xcresulttool get test-results summary --path TestResults.xcresult

# Export as JSON
xcrun xcresulttool get --path TestResults.xcresult --format json > results.json

# Coverage report
xcrun xccov view --report TestResults.xcresult

# Coverage as JSON
xcrun xccov view --report --json TestResults.xcresult > coverage.json

</test_results>

<swiftui_debugging>

SwiftUI Debugging

Track View Re-evaluation

var body: some View {
    let _ = Self._printChanges()  // Logs what caused re-render
    VStack {
        // ...
    }
}

Dump Objects

let _ = dump(someObject)  // Full object hierarchy to console

Note: No CLI equivalent for Xcode's visual view hierarchy inspector. Use logging extensively. </swiftui_debugging>

<standard_debug_workflow>

Standard Debug Workflow

# 1. Build with error parsing
xcodebuild -project MyApp.xcodeproj -scheme MyApp build 2>&1 | xcsift

# 2. Run with log streaming (background terminal)
log stream --level debug --predicate 'subsystem == "com.yourcompany.MyApp"' &

# 3. Launch app
open ./build/Build/Products/Debug/MyApp.app

# 4. If crash occurs
cat ~/Library/Logs/DiagnosticReports/MyApp_*.ips | head -100

# 5. Memory check
leaks MyApp

# 6. Deep debugging
lldb -n MyApp

</standard_debug_workflow>

<cli_vs_xcode>

What CLI Can and Cannot Do

Task CLI Tool
Build errors xcsift
Runtime logs log stream
Crash symbolication atos, lldb
Breakpoints/debugging lldb
Memory leaks leaks, xctrace
CPU profiling xctrace
Network inspection mitmproxy
Test results xcresulttool
Sanitizers xcodebuild flags
View hierarchy ⚠️ _printChanges() only
GPU debugging Requires Xcode
</cli_vs_xcode>