Skip to content

macOS Unified Logs Forensics: A Practical Guide

What macOS Unified Logs record, where tracev3, uuidtext and timesync live, what they can and cannot prove, and a workflow to read them for an investigation.

Published on 4 min read

TL;DR. Unified Logs are the most detailed timeline a Mac keeps: authentication, sudo, privacy (TCC) decisions, Gatekeeper, launch agents, remote access and disk mounts, each with a process, a subsystem and a microsecond timestamp. The catch is that an entry is split across three kinds of files — .tracev3, uuidtext/dsc and timesync — and you need all of them. This guide explains what is where and how to work through it; the Unified Log Parser reads the lot in your browser.

What the Unified Logging system is

Since macOS 10.12 Sierra, Apple routes almost all logging through one system. The kernel, Apple's daemons and any third-party code calling os_log send entries to logd, which writes them to compressed binary files. Syslog-style text files under /var/log still exist, but most of what matters in an investigation lives in the unified store.

Each entry carries:

  • the time, microsecond precision once converted;
  • the process (image path and PID), thread and user ID;
  • the sender image: the library or framework that logged (often not the process itself);
  • a subsystem and category in reverse-DNS style, for example com.apple.TCC / access;
  • a type: Default, Info, Debug, Error or Fault for log messages, plus activities, signposts and state dumps;
  • the message, rendered from a format string and the values recorded with the entry.

Where the files live

PathContent
/private/var/db/diagnostics/Persist/Main store of .tracev3 files
/private/var/db/diagnostics/Special/Entries with their own time-to-live (often older than Persist)
/private/var/db/diagnostics/Signpost/Performance signposts
/private/var/db/diagnostics/HighVolume/High-volume data, usually empty
/private/var/db/diagnostics/timesync/Boot and clock correlation records
/private/var/db/uuidtext/XX/…Format strings, one file per binary UUID
/private/var/db/uuidtext/dsc/…Strings of the dyld shared cache

A .logarchive produced by log collect or sysdiagnose holds the same folders plus logdata.LiveData.tracev3, the in-memory buffer at collection time. The tracev3 format article goes through the binary layout.

Why you always need three kinds of files

A .tracev3 entry does not store its text. It stores a reference to a format string (an offset into a uuidtext file or into the shared-cache dsc file) and the raw argument values. Without the string files, a parser can only show numbers and fragments; entries are "unresolved". Times are stored as boot-relative Mach continuous time, converted to wall-clock time with the timesync records; without them, times are approximate at best.

So the rule for collection is simple: take diagnostics and uuidtext, or a .logarchive, which has both.

What Unified Logs can prove

  • Authentication and privilege use: sudo commands with the target user and the full command line, failed passwords, su, authorization rights granted by authd, local account changes.
  • Remote access: SSH (sshd, sshd-session) and Screen Sharing sessions, with the remote address when logged.
  • Privacy decisions: TCC prompts and results — for example Full Disk Access granted to Terminal — under subsystem com.apple.TCC.
  • Execution context: Gatekeeper assessments and overrides by syspolicyd, XProtect and XProtect Remediator activity, quarantine attributes, LaunchServices application launches.
  • Persistence: launch agents and daemons being loaded, Background Task Management registering login items.
  • Devices: volumes mounted and ejected by diskarbitrationd, USB devices attaching.

The triage queries article lists concrete searches for each.

What they cannot prove

  • Absence. A missing entry can mean the store rotated, the level was never persisted (most Info and Debug entries live only in memory), the value was redacted, or Apple changed the wording in that release.
  • Redacted values. <private> means the value was hidden when it was logged. No parser can recover it; the format string still shows what kind of event it was.
  • Exact wording across versions. Messages are not an API. A search tuned on one macOS release can miss events on another; prefer subsystem, category and process filters, and read around each hit.

A workflow that holds up

  1. Collect early, with uuidtext and timesync, and hash what you collected.
  2. Record coverage: the first and last entry per boot session, and any gap, before you say "nothing happened".
  3. Narrow by time around known events (a malicious download, a login), then widen.
  4. Filter by process and subsystem rather than by message text alone.
  5. Read around every hit: the entries from the same PID a few seconds before and after usually explain it.
  6. Confirm key entries with log show on a Mac for anything that goes into a report, and note the parser and version you used.

Doing it in the browser

The Unified Log Parser decodes tracev3 files from a .logarchive, a copied /private/var/db tree or a UAC / Velociraptor collection, and also opens log show exports. It gives you a time range with a density strip, filters by type, process, subsystem and PID, curated DFIR presets, and exports to CSV, NDJSON and Timesketch. Everything runs locally with WebAssembly; the walkthrough uses the synthetic FIN-MBP-03 sample.

Further reading: Mandiant's macos-UnifiedLogs project and the libyal Apple Unified Logging format notes document the formats in depth.

Related articles

Step by step: open a macOS .logarchive, diagnostics folder or log show export in the free Unified Log Parser, triage findings, set a time range and export.
Collect macOS Unified Logs with log collect, a raw copy of diagnostics and uuidtext, UAC, Velociraptor or mac_apt, and avoid the gaps that break parsing.
Export macOS Unified Logs with log show (ndjson, json, text styles), avoid time-zone traps, compare parsers and build CSV or Timesketch timelines.