Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Unified Logging System

macOS 10.12 (Sierra) introduced Unified Logging, replacing the traditional Unix syslog system. All system and application logs now flow through a single, efficient logging mechanism. Understanding this system is essential for troubleshooting macOS issues.

Unified Logging vs Traditional Syslog

Traditional Unix logging had limitations:

AspectTraditional SyslogUnified Logging
StoragePlain text filesCompressed binary database
PerformanceDisk I/O intensiveMemory-buffered, compressed
Querygrep through filesStructured queries
MetadataLimitedRich (subsystem, category, type)
PrivacyNoneBuilt-in privacy controls
Location/var/log//var/db/diagnostics/
# Old way (some logs still here)
$ ls /var/log/
asl/
com.apple.xpc.launchd/
install.log
system.log
wifi.log

# New way
$ ls /var/db/diagnostics/
Persist/
Special/
timesync/

The log Command

The primary tool for unified logging is the log command:

# Basic usage
$ log show                    # Show recent logs
$ log stream                  # Follow logs in real-time
$ log collect                 # Gather logs for analysis

Real-Time Log Streaming

# Stream all logs (very verbose)
$ log stream
Timestamp                       Thread     Type        Activity             PID    TTL
2024-01-15 10:00:00.123456-0800 0x1234     Default     0x0                  123    0    kernel: (AppleUSBXHCI) ...
2024-01-15 10:00:00.234567-0800 0x2345     Info        0x0                  456    0    mds: (Spotlight) ...
...

# Stream with level filter
$ log stream --level error

# Stream for specific process
$ log stream --process Safari

# Stream for specific subsystem
$ log stream --predicate 'subsystem == "com.apple.network"'

# Stream with debug messages (normally hidden)
$ log stream --level debug

# Stream with info level and above
$ log stream --level info

Viewing Historical Logs

# Show logs from last hour
$ log show --last 1h

# Show logs from last 30 minutes
$ log show --last 30m

# Show logs from specific time range
$ log show --start "2024-01-15 09:00:00" --end "2024-01-15 10:00:00"

# Show logs from today
$ log show --start "$(date '+%Y-%m-%d') 00:00:00"

# Show logs since boot
$ log show --start "$(sysctl -n kern.boottime | awk '{print $4}' | tr -d ',')"

Filtering with Predicates

Predicates are the key to finding relevant logs. They use NSPredicate syntax:

Basic Predicate Examples

# Filter by process name
$ log show --predicate 'process == "Safari"' --last 1h

# Filter by subsystem
$ log show --predicate 'subsystem == "com.apple.wifi"' --last 1h

# Filter by category
$ log show --predicate 'category == "connection"' --last 1h

# Filter by message content
$ log show --predicate 'eventMessage contains "error"' --last 1h

# Case-insensitive search
$ log show --predicate 'eventMessage contains[c] "ERROR"' --last 1h

# Filter by log type/level
$ log show --predicate 'messageType == error' --last 1h
$ log show --predicate 'messageType == fault' --last 1h

Combining Predicates

# AND condition
$ log show --predicate 'process == "kernel" AND eventMessage contains "USB"' --last 1h

# OR condition
$ log show --predicate 'process == "Safari" OR process == "WebKit"' --last 1h

# Complex combinations
$ log show --predicate '(subsystem == "com.apple.network" OR subsystem == "com.apple.wifi") AND messageType == error' --last 1h

# NOT condition
$ log show --predicate 'NOT process == "kernel"' --last 1h

# Multiple conditions
$ log show --predicate 'subsystem BEGINSWITH "com.apple" AND category == "default" AND eventMessage contains[c] "fail"' --last 1h

Predicate Operators

OperatorMeaning
==Equals
!=Not equals
<, >, <=, >=Comparisons
containsString contains
BEGINSWITHString starts with
ENDSWITHString ends with
MATCHESRegular expression
AND, OR, NOTLogical operators
[c]Case-insensitive modifier

Available Predicate Fields

FieldDescription
processProcess name
processIDProcess ID (PID)
subsystemLogging subsystem
categoryLog category
eventMessageThe log message
messageTypeLog level (default, info, debug, error, fault)
senderImagePathPath to the binary that logged
eventTypeactivityCreateEvent, logEvent, etc.

Log Levels and Types

Unified logging has five log types:

TypeDescriptionWhen to Use
DefaultStandard messagesGeneral information
InfoInformationalHelpful but verbose
DebugDebuggingDevelopment only
ErrorErrorsSomething went wrong
FaultCriticalSystem/app failure
# Show only errors and faults
$ log show --predicate 'messageType == error OR messageType == fault' --last 1h

# Show debug messages (normally hidden, requires debug profile)
$ log show --level debug --predicate 'process == "myapp"' --last 1h

By default, Debug and Info messages may be hidden. Enable them:

# Enable debug logging for a subsystem (persistent)
$ sudo log config --mode "persist:debug" --subsystem com.example.myapp

# Enable for current boot only
$ sudo log config --mode "level:debug" --subsystem com.example.myapp

# Reset to default
$ sudo log config --mode "persist:default" --subsystem com.example.myapp

# Check current configuration
$ sudo log config --status --subsystem com.example.myapp

Practical Examples

Troubleshooting Wi-Fi

# Stream Wi-Fi logs
$ log stream --predicate 'subsystem == "com.apple.wifi"' --level debug

# Show recent Wi-Fi errors
$ log show --predicate 'subsystem == "com.apple.wifi" AND messageType >= error' --last 1h

# Find Wi-Fi disconnection reasons
$ log show --predicate 'subsystem == "com.apple.wifi" AND eventMessage contains "disconnect"' --last 4h

Investigating Crashes

# Find crash logs
$ log show --predicate 'eventMessage contains "crash" OR process == "ReportCrash"' --last 1h

# Application-specific crashes
$ log show --predicate 'process == "Safari" AND (eventMessage contains "crash" OR messageType == fault)' --last 1h

# Kernel panics
$ log show --predicate 'process == "kernel" AND messageType == fault' --last 24h

Login/Authentication Issues

# Authentication logs
$ log show --predicate 'subsystem == "com.apple.opendirectoryd" OR subsystem == "com.apple.securityd"' --last 1h

# Login events
$ log show --predicate 'eventMessage contains "login" OR eventMessage contains "authentication"' --last 1h

# SSH connections
$ log show --predicate 'process == "sshd"' --last 1h

Disk and Storage

# Disk-related messages
$ log show --predicate 'subsystem contains "disk" OR process == "diskutil" OR process == "fsck"' --last 1h

# APFS operations
$ log show --predicate 'subsystem == "com.apple.apfs"' --last 1h

# Time Machine
$ log show --predicate 'subsystem == "com.apple.TimeMachine"' --last 4h

Network Issues

# Network subsystem
$ log show --predicate 'subsystem == "com.apple.network"' --last 30m

# DNS issues
$ log show --predicate 'eventMessage contains "DNS" OR process == "mDNSResponder"' --last 1h

# VPN connections
$ log show --predicate 'subsystem == "com.apple.networkextension"' --last 1h

Application Debugging

# Specific application
$ log show --predicate 'process == "MyApp"' --last 1h

# Application launch issues
$ log show --predicate 'eventMessage contains "MyApp" AND (eventMessage contains "launch" OR eventMessage contains "terminate")' --last 1h

# launchd service issues
$ log show --predicate 'subsystem == "com.apple.launchd" AND eventMessage contains "com.example"' --last 1h

Output Formatting

Format Options

# Default format
$ log show --last 5m

# JSON format (for scripting)
$ log show --last 5m --style json

# Compact format
$ log show --last 5m --style compact

# Syslog-like format
$ log show --last 5m --style syslog

# Include more information
$ log show --last 5m --info --debug

JSON Output for Scripting

# Get JSON output
$ log show --predicate 'process == "Safari"' --last 5m --style json

# Parse with jq
$ log show --predicate 'messageType == error' --last 1h --style json | jq '.[].eventMessage'

# Count errors by process
$ log show --predicate 'messageType == error' --last 1h --style json | jq 'group_by(.processImagePath) | map({process: .[0].processImagePath, count: length}) | sort_by(.count) | reverse'

Collecting Logs

For support or analysis, collect logs into a file:

# Collect logs to archive
$ sudo log collect --last 1d --output ~/Desktop/logs.logarchive

# Collect with specific time range
$ sudo log collect --start "2024-01-15 09:00:00" --end "2024-01-15 12:00:00" --output ~/Desktop/incident.logarchive

# Open in Console.app
$ open ~/Desktop/logs.logarchive

The .logarchive format can be opened in Console.app or queried with log show:

# Query collected logs
$ log show --archive ~/Desktop/logs.logarchive --predicate 'messageType == error'

Legacy Log Files

Some traditional log files still exist:

# Install log
$ cat /var/log/install.log

# System log (limited)
$ cat /var/log/system.log

# Wi-Fi log
$ cat /var/log/wifi.log

# Apache (if enabled)
$ cat /var/log/apache2/error_log

# Application-specific
$ cat ~/Library/Logs/DiagnosticReports/*.crash

Console.app

Console.app provides a GUI for unified logging:

# Open Console
$ open -a Console

# Open with specific log archive
$ open ~/Desktop/logs.logarchive

Console.app features:

  • Real-time streaming
  • Predicate builder
  • Log favorites
  • Device logs (iOS devices connected)

Common Subsystems Reference

SubsystemDescription
com.apple.wifiWi-Fi
com.apple.networkNetworking
com.apple.networkextensionVPN, network extensions
com.apple.apfsAPFS filesystem
com.apple.launchdlaunchd services
com.apple.securitydSecurity daemon
com.apple.opendirectorydDirectory services
com.apple.TimeMachineTime Machine
com.apple.SpotlightSpotlight indexing
com.apple.xpcXPC services
com.apple.coredataCore Data
com.apple.bluetoothBluetooth
com.apple.audioAudio
com.apple.powerdPower management

Performance Considerations

Unified logging is designed for efficiency, but verbose queries can impact performance:

# Expensive: search all logs
$ log show --last 24h  # Can be slow

# Better: use predicates to filter
$ log show --predicate 'process == "Safari"' --last 24h

# Best: combine specific predicates
$ log show --predicate 'process == "Safari" AND messageType == error' --last 24h

Summary

Unified logging replaces traditional syslog with a modern, efficient system:

TaskCommand
Stream live logslog stream
Show historical logslog show --last 1h
Filter by process--predicate 'process == "name"'
Filter by subsystem--predicate 'subsystem == "com.apple.x"'
Filter by message--predicate 'eventMessage contains "text"'
Show only errors--predicate 'messageType == error'
Collect logssudo log collect --output file.logarchive
JSON output--style json

Key predicates to remember:

# Process-based
process == "ProcessName"

# Subsystem-based
subsystem == "com.apple.something"

# Message content
eventMessage contains "search term"
eventMessage contains[c] "case insensitive"

# Log level
messageType == error
messageType == fault

# Combined
process == "Safari" AND messageType == error

Master the log command, and you’ll be able to diagnose almost any macOS issue from the command line.