The End of Plaintext Logs
For decades, if an application crashed on macOS, or if a user experienced Wi-Fi drops, system administrators opened the Console app or used the terminal to read plaintext log files located in /var/log/ (like system.log).
With the release of macOS Sierra, Apple completely destroyed the traditional UNIX logging architecture. They introduced the Unified Logging System (ULS). ULS does not write standard plaintext files. Instead, it writes highly compressed, binary, proprietary database files scattered across the system. Furthermore, to preserve SSD lifespans, ULS stores massive amounts of log data strictly in RAM, meaning if the Mac reboots, the volatile logs vanish.
You cannot use cat, grep, or tail on these new binary logs. To extract, filter, and read data from the Unified Logging System, administrators must use the incredibly complex, yet immensely powerful, log command.
Step 1: Streaming Logs in Real-Time (log stream)
The most immediate use of the log command is mimicking the behavior of the legacy tail -f /var/log/system.log command to watch events occurring right now.
Open the Terminal and run:
sudo log stream
The terminal will instantly become an unreadable blur. The Unified Logging System captures thousands of events per second from every single process, kernel extension, and application on the Mac. You must aggressively filter this stream.
If you are troubleshooting a Wi-Fi connectivity issue, you can filter the live stream to only show events generated by the AirPort subsystem:
sudo log stream --predicate 'subsystem == "com.apple.wifi"'
If a developer wants to see only error-level messages generated by their specific application (e.g., Google Chrome), they filter by the process name and the message type:
sudo log stream --predicate 'process == "Google Chrome"' --level error
Step 2: Searching Historical Logs (log show)
While stream is for live debugging, log show is for forensic investigation of events that occurred in the past.
By default, log show will attempt to dump the entire historical database (which could be gigabytes of text). You must constrain the search using time boundaries.
Suppose a user reported that their Mac forcefully rebooted due to a Kernel Panic at exactly 3:00 PM yesterday. You can instruct the log command to extract all kernel logs from a specific 10-minute window:
sudo log show --predicate 'process == "kernel"' --start "2023-10-25 14:55:00" --end "2023-10-25 15:05:00" --info
The output will display the exact millisecond timestamps, the thread IDs, and the raw hexadecimal panic data, allowing you to identify if a faulty third-party USB driver caused the crash.
Step 3: Mastering the Predicate Syntax
The true power of the log command is the --predicate flag. It uses an SQL-like query language (specifically, NSPredicate syntax) to surgically extract data.
The most useful predicate keys are:
process: The name of the application (e.g.,"Safari").subsystem: The internal macOS framework (e.g.,"com.apple.TimeMachine").category: A sub-grouping within a subsystem (e.g.,"Bluetooth").eventMessage: The actual text content of the log line.
You can combine these using AND, OR, and CONTAINS.
To find every single time the word “failed” appeared in the logs related to the sshd (Remote Login) process over the last 24 hours (a classic sign of a brute-force SSH attack):
sudo log show --last 24h --predicate 'process == "sshd" AND eventMessage CONTAINS[c] "failed"'
(The [c] modifier makes the CONTAINS search case-insensitive).
Step 4: Decoding Privacy Redactions (<private>)
When you finally find the log you need, you will often encounter a massive frustration. The log line will look like this:
Connected to Wi-Fi network <private> with IP address <private>
To comply with strict privacy regulations, Apple purposefully hardcoded the ULS to redact any dynamic variables (like IP addresses, usernames, or filenames) and replace them with the string <private>.
If you are an administrator and you desperately need to see this data to fix the computer, you cannot un-redact historical logs (they are permanently censored). However, you can deploy a hidden configuration profile to force the Mac to stop redacting future logs.
You must use an MDM solution (like Jamf or Intune) to push a configuration profile to the Mac containing the Enable-Private-Data key set to True within the com.apple.system.logging payload. Once applied, all future logs will display the raw, unredacted IP addresses and filenames.
Step 5: Exporting for Offline Analysis (log collect)
If a remote employee’s Mac is acting erratically, but they are about to board an airplane, you do not have time to sit on a Zoom call running log show commands.
You can instruct the Mac to bundle the entire binary logging database into a single, compressed .logarchive file.
sudo log collect --last 2d --output ~/Desktop/MacLogs.logarchive
The employee can email you this file. You can then open this .logarchive file on your own Mac using the graphical Console application, or you can run log show commands against the offline file by appending the --archive flag:
log show --archive ~/Desktop/MacLogs.logarchive --predicate 'process == "Microsoft Word"'
Conclusion
The macOS Unified Logging System is a radical departure from traditional UNIX plaintext files. By mastering the log show and log stream commands, and writing precise NSPredicate filters, Mac administrators can slice through gigabytes of volatile, binary system data to forensically pinpoint the exact cause of application crashes and network failures.