SuperAPI AI Directory

logs-start

General & other

View repository

Updated 10-16 01:33

About this skill

logs-start

Start a log capture. Stop it with logs-stop, which resolves the active tier on its own - you never have to name it again.

Argument

$ARGUMENTS selects the tier. Empty means sim.

Argument Tier Reaches extensions? Cost
(empty) or sim Simulator, live unified log yes (all sim processes) none
device Device, live stdout no, main app only none
structured Device, unified log archive yes interactive sudo, large archive

Anything else: say what was passed, list the three, and stop. Do not guess.

When invoked with no argument, start the simulator capture as usual, then close your report with this reminder so the other tiers stay discoverable:

Started the simulator capture (default). Other tiers: /logs-start device for live device stdout (main app only), /logs-start structured for the device unified log (the only tier that sees the keyboard and other extensions).

Do not ask which tier to use instead of starting - the default is the default. Only mention the alternatives after the capture is already running.

Choosing a tier

  • sim is the default because it is free and the richest: real unified-log metadata, timestamps, levels, categories, threads.
  • device is for hardware-only bugs. Live and cheap, but see the limitation below - it cannot see the keyboard or any other extension.
  • structured is the only tier that sees extensions on hardware. Reach for it when the keyboard, share, action, or widget target is involved, or for a post-mortem .logarchive you want to reopen in Console.app.

sim

  1. mkdir -p logs
  2. Run ./scripts/launch_simulator.sh in a background/long-lived shell so log stream keeps running. It also writes logs/.sim-capture.pid naming the streaming process, which is what logs-stop reads to end this capture and nothing else.
  3. Report the logs/sim-YYYYMMDD-HHMMSS.log path the script prints.

Attaches to the already-booted Simulator; it does not relaunch the app, and it fails if none is booted. Captures Logger output filtered to subsystem == "com.antonnovoselov.VivaDicta"; raw print() is not included.

device

  1. ./scripts/launch_device.sh --check first - it resolves device and bundle id without launching. Fix whatever it reports before continuing.
  2. mkdir -p logs
  3. Run ./scripts/launch_device.sh in a background/long-lived shell. It writes logs/.device-capture.pid naming the devicectl process, which is what logs-stop reads.
  4. Report the logs/device-YYYYMMDD-HHMMSS.log path.

Uses xcrun devicectl device process launch --console with ENABLE_PRINT_LOGS=1. --terminate-existing restarts the app, so in-progress state is lost.

Limitation: main app only, no extensions

--console pipes the stdout of the single process devicectl launched. Every extension runs in its own system-spawned process, so devicectl never sees it. Their output is absent entirely and nothing says so - you get a complete-looking stream that is silently missing a target.

Measured: a capture during keyboard use carried 213 lines from VivaDicta/ and 0 from VivaDictaKeyboard/, though the keyboard logs from KeyboardViewController, KeyboardTextProcessor and VivaModeManager. Use structured for extensions.

Timestamps

Lines carry time, level and call site, because LoggerExtension's print mirror stamps them itself:

19:09:40.709 [INFO] VivaDicta/AIService.swift:666 Loaded 1 Viva Modes

That is app-side, so it only appears in builds you install. Bare, unstamped lines mean the installed binary predates the print mirror - rebuild to the device rather than changing the capture. Category and thread are still absent; stdout has no room for unified-log metadata.

structured

Starts nothing - it only records where to collect from. logs-stop does the work.

  1. Find the device:
    xcrun xctrace list devices | grep iPhone | grep -v Simulator | head -1
    
  2. mkdir -p llmtemp
  3. date '+%Y-%m-%d %H:%M:%S' > llmtemp/.device-log-start-time
    echo "<UDID>" > llmtemp/.device-log-udid
    
  4. Report the start time and UDID, and warn that logs-stop will need interactive sudo and will write a large archive.

Why this tier reaches extensions: sudo log collect --device-udid pulls the device's whole unified log, and extension lines survive the subsystem filter because LoggerExtension.swift hardcodes one subsystem across all targets:

private nonisolated let kLoggingSubsystem = "com.antonnovoselov.VivaDicta"

That constant is load-bearing. If a target is ever changed to log under its own bundle id, it disappears from these captures silently.

Concurrent captures

sim and device can run at once; logs-stop handles all active tiers, reading one marker file per tier. Do not start a second capture of the same tier - the marker is overwritten, so the first stream is orphaned and its file stops receiving the lines you expect.

The markers are why logs-stop never has to guess. It ends the tier that was actually started, instead of matching simctl spawn.*log stream against the machine and catching an unrelated log stream someone else is running.

Manual analysis

ls -lt logs/sim-*.log | head -5
grep -i "error\|fault" logs/sim-*.log
grep "\[AppState\]" logs/sim-*.log

log show logs/vivadicta_device_*.logarchive \
  --predicate 'subsystem == "com.antonnovoselov.VivaDicta"'

Related