What is a sysdiagnose, how do you use Console.app and the log command, and what should you ask a user or tester to send?
Predict first
A program logs an info line and an error with a private value. Does log show with a subsystem predicate find them, and how is the private value shown?
// === main.swift ===
import OSLog
let logger = Logger(subsystem: "com.example.sysd", category: "net")
logger.info("info-line \(7)")
logger.error("error-line \("secret", privacy: .private)")
- Yes, including the info line (with --info), and the private value as <private>
- No, logs cannot be read from the command line
- It shows the secret in clear
Mental model. A sysdiagnose is the black-box recorder plus the cockpit photo at the moment of the incident. It is rich and private, so you handle it like medical records.
A sysdiagnose is a bundle of system diagnostic data gathered at one moment: the unified logs, crash and hang reports, process snapshots (spindumps), memory and disk state, network and power information and system configuration. On an iPhone a tester triggers it with a documented button combination (Apple’s bug-reporting instructions give the exact one for each device), waits, then finds it under Settings ▸ Privacy & Security ▸ Analytics & Improvements ▸ Analytics Data and shares it; on a Mac there is a keyboard shortcut and the sysdiagnose command. It is the right artefact for “the app froze for a minute”, “battery drained overnight” or “it crashed and I have no details”, because it records the state around the event, but it is large and contains personal data: ask for it deliberately, share it over a secure channel and handle it as sensitive (Q347).
To read logs live or from an archive use Console.app, which streams the unified log from your Mac or a connected device and filters by subsystem, category, process, level and text; save useful filters. From a shell, log show (past entries, with --last 5m and --predicate) and log stream (live) do the same: the check below logs from a small program and finds the entries with log show --predicate 'subsystem == "…"', including a redacted <private> value. Add --info or --debug to include those levels. A good tester report contains the app version and build, OS and device, exact time and steps, what they expected, a screenshot or recording, and a sysdiagnose or the app’s own exported logs taken soon after the event, because old entries age out. In your own app, make that easy: a “send diagnostics” action that gathers OSLogStore entries and the build and configuration details (see the logging question).
The log tool reads the unified log with predicates, and redaction applies to dynamic private values.
Common traps
- Asking for a sysdiagnose days after the problem. Log entries age out; ask for it soon after, with the time of the event.
- Forwarding a sysdiagnose casually. It contains personal data from the whole device.
They might follow up with
- How do you filter to your app in Console? By subsystem and category, which is why you set them on your
Logger. - What is in a good bug report? Build, OS, device, time, steps, expected and actual result, and logs from soon after.
Related questions
- 23.4.1 How does the unified logging system work: Logger, levels, subsystems and categories, privacy, and how do you…
- 23.6.2 How do you reproduce a bug reliably: environment, feature flags, seeded data, launch arguments, simulator…
- 23.5.2 How do you build a production diagnostics pipeline: collection, symbolication, grouping, prioritisation…
- 14.3.3 How do you keep personal data out of logs, screenshots, the pasteboard and the app switcher?
How do you reproduce a bug reliably: environment, feature flags… →