How to Configure Apple Unified Logs (log show) for Advanced Threat Hunting via Terminal

Since the introduction of macOS Sierra, Apple has fundamentally overhauled how system logs are managed, transitioning away from traditional flat-text files (like /var/log/system.log) to the Unified Logging System (ULS). The ULS is a highly compressed, binary-format datastore managed by the logd daemon, offering incredible performance and privacy protections.

For macOS administrators and security analysts, traditional utilities like grep or tail are no longer sufficient for parsing system events. To hunt for advanced threats, track application executions, or debug system crashes, you must master the log command-line utility. This guide explains how to leverage the log show command with advanced predicates to extract actionable telemetry from macOS.

The Architecture of Unified Logging

The Unified Logging System organizes data into a highly structured format. Every log entry contains rich metadata, including:

  • Subsystem: The specific component generating the log (e.g., com.apple.TCC for privacy controls).
  • Category: A functional grouping within the subsystem (e.g., access or auth).
  • Process ID (PID): The specific process that generated the event.
  • Log Type: The severity of the log (e.g., Default, Info, Debug, Error, Fault).

Because the logs are stored in a binary format, they can only be read using the macOS Console.app or the log Terminal command.

Step 1: Basic Usage of log show

The log show command dumps historical logs from the binary datastore. By default, running log show without arguments will attempt to dump millions of lines of text to your terminal, which is entirely unmanageable.

You must restrict the output using timeframes and limits. For example, to view logs generated only within the last 10 minutes:

log show --last 10m

To view logs from a specific date and time range:

log show --start "2024-10-25 09:00:00" --end "2024-10-25 09:15:00"

Step 2: Using Predicates for Advanced Filtering

The true power of the log command lies in the --predicate flag. Predicates use the NSPredicate syntax (borrowed from Objective-C) to perform highly specific SQL-like queries against the log metadata.

Hunting for Application Executions

If you want to track which applications have been launched by the user (a common requirement for threat hunting), you can filter for logs generated by the LaunchServices subsystem.

log show --predicate 'subsystem == "com.apple.launchservices" AND category == "application"' --last 1h

Hunting for Privilege Escalation (sudo usage)

To audit when administrators are elevating privileges via the sudo command, you can filter by the specific process name.

log show --predicate 'process == "sudo"' --last 24h

Hunting for Privacy Prompt Approvals (TCC)

Transparency, Consent, and Control (TCC) manages access to the microphone, camera, and Full Disk Access. Malware often attempts to bypass or manipulate these prompts. You can query the TCC subsystem to review all privacy-related events:

log show --predicate 'subsystem == "com.apple.TCC"' --last 1h

Step 3: Extracting Logs for External SIEM Analysis

If you are aggregating logs into a centralized Security Information and Event Management (SIEM) platform (like Splunk or Elastic), reading the default text output is inefficient. The log command allows you to output the data in structured JSON format, which is easily ingested by log forwarders.

log show --predicate 'process == "sudo"' --last 1h --style json > sudo_logs.json

The resulting sudo_logs.json file will contain deeply nested JSON objects, exposing every attribute of the log event, including thread IDs, Mach continuous time, and the exact executable path.

Step 4: Real-Time Log Streaming

While log show is used for historical querying, the log stream command is used for live, real-time debugging. This replaces the legacy tail -f /var/log/system.log workflow.

For example, if you are developing an application or deploying an MDM profile and want to see the immediate result of an MDM command, you can stream the MDM client logs in real-time:

log stream --predicate 'subsystem == "com.apple.ManagedClient"'

The terminal will remain open, printing new log entries exactly as they are generated by the MDM daemon.

Step 5: Managing Privacy and <private> Tags

By default, Apple redacts sensitive information (like filenames, IP addresses, or usernames) in the Unified Logging System to protect user privacy. Redacted fields appear in the output as <private>.

During active incident response or debugging, this redaction can hide critical indicators of compromise (IoCs). To reveal these private strings, you must install a specific configuration profile to disable log redaction, which requires MDM deployment or SIP disabling (which is not recommended). Alternatively, you can use the sudo command when running log collect to gather a comprehensive sysdiagnose archive, which often contains less-redacted historical data when opened in Console.app on the same machine.

Conclusion

The macOS Unified Logging System is a massively powerful, highly structured forensic datastore. By abandoning legacy text-parsing tools and embracing NSPredicate syntax via the log show and log stream commands, security analysts can perform surgical threat hunting and extract rich, actionable telemetry from macOS endpoints.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.