Reading view

There are new articles available, click to refresh the page.

Inside the Unified Log 7: Claude diagnoses the log

Diagnosing problems using the Unified log is a complicated business that requires understanding, insight, experience and a systematic approach. As few of us feel competent to wade through thousands of log entries trying to spot where things go wrong, this might seem an ideal opportunity for the use of AI. I’m very grateful to one of our regular readers for the opportunity to demonstrate how Claude coped with diagnosing a troublesome problem they’ve been having with the Clock app in Tahoe.

Signs and symptoms

When you’re diagnosing any problem, you should start with a clear account of its signs and symptoms before even thinking of resorting to the log. A good physician may take an hour or more obtaining a full history and examining a patient before they start thinking about performing any special investigations. Even though signs and symptoms may not lead you to a diagnosis, they should help you direct your investigations to best effect.

In this case, although the Clock app is launching, when displaying some views the content is missing. We therefore agreed to capture the log from the moment of launch from the Finder until one of the problematic views displayed. That’s easy to achieve by double-clicking the app when the menu bar clock has just turned to display 00 seconds, then checking the time again when the view has been displayed. Add a couple of seconds to the latter to determine the period to view in LogUI.

What’s normal?

Recognising what’s abnormal in the log is only possible if you know what the normal looks like. It’s often perfectly normal to see error messages, but knowing which are relevant is more difficult. In this case, I cheated and obtained a matching log extract from launching the Clock app on another Mac running the same version of Tahoe, making it simple to compare the two.

An interesting exercise for the reader is to submit a perfectly normal log extract to AI, with a vague description like “problems starting the app”, and seeing if it reports that as being normal. I doubt that it would.

Preparing a log extract for submission to AI

LogUI can provide log extracts saved to Rich Text Format, preserving the entry fields, although I doubt whether any AI will be able to interpret those correctly. Perhaps the best route is to save the extract in RTF, and save that in turn as plain text. A longer way round is to:

  • Save the whole extract as a JSON file, to preserve the whole record.
  • Use the Search tool to display the entries you want to submit for analysis.
  • Click on the Reduce tool to remove the unwanted entries.
  • Save the remaining entries in Rich Text, then save that in plain text format.

That also allows you to submit a shorter extract.

Claude’s report

AIs like Claude are thoroughly professional in their reporting, even when they’re utterly incorrect. In this case, Claude’s report is headed Complete Analysis of the Problem, and appears a confident and detailed assessment presented logically. It first establishes:

  • The App DOES Launch Successfully
  • Main Issue: Continuous Assertion Invalidation
  • Infinite State Loop
  • Critical Errors Identified

supporting those with digested “quotations” from the log, although in fact most of them are rendered in Claude’s words, not those in the log entries themselves.

It then leaps on to give the Final Diagnosis that the Clock app:

  • Launches
  • Creates its scenes and interfaces
  • Registers functionalities (alarm, stopwatch, timer)
  • Fails to maintain the assertions necessary to remain active
  • The system continuously invalidates its resource requests.

Those are embellished with appropriate ✅ and ❌ emoji.

Following those conclusions, it cites what it terms Key Log Evidence in support of that diagnosis. Among those are the following.

Critical Error at Launch

For this, it quotes part of the message from
00.968273 error com.apple.runningboard [app[application.com.apple.clock.1152921500311884024.1152921500311884029(501)]:1921] Memorystatus failed with unexpected error: Invalid argument (22)
and a similar entry.

However, it doesn’t point out that those are rapidly followed by
00.969966 com.apple.runningboard [app[application.com.apple.clock.1152921500311884024.1152921500311884029(501)]:1921] set Memory Limits to Soft Inactive (800)
00.970684 com.apple.launchservices LAUNCH: Successful launched 0x0-0x3b03b pid=1921 com.apple.clock '[private]'

which would appear to contradict this being a “critical error”.

Kernel Warning

Claude’s report next misquotes one of the log entries as reporting
Clock[19237] triggered unmask of range (1 of 16384:0000->0x1ce000000 of DVLD shared region in VM map 0x5c946dd8d4c72dbbf
when in fact the full entry reads
10.891949 kernel Clock[19237] triggered unnest of range 0x1e8000000->0x1ea000000 of DYLD shared region in VM map 0x5c946da0d472dbbf. While not abnormal for debuggers, this increases system memory footprint until the target exits.
It gives no reason for changing unnest to unmask, DYLD (which makes sense) to DVLD (which is nonsense), or changing the range given.

For interest, I used LogUI’s Gloss feature to submit that entry to ChatGPT for its explanation:
This log entry is a system notice from the kernel indicating that a portion of the DYLD shared region in the virtual memory (VM) map has been unnested. […] In short: The macOS kernel is reporting that the process Clock caused a part of the shared dynamic library cache to become private memory. This is expected behaviour when certain debugging or memory operations occur, but it will temporarily use more RAM until the process exits.

Continuous Assertion Cycle and Scene Management Loop

Claude then claims that the perfectly normal entries made by RunningBoard and FrontBoard demonstrate a continuous assertion cycle and scene management loop. Anyone who has read my account of RunningBoard would realise that is a misreading of what is both common and normal.

Claude’s Possible Solutions

Nearing the end of the report, Claude recommends four possible solutions:

  • Reset system permissions: sudo tccutil reset All com.apple.clock
  • Rebuild launch services cache: /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user
  • Verify system integrity: sudo /usr/libexec/repair_packages --verify --standard-pkgs
  • If everything fails: This could be a specific bug in macOS Tahoe with the Clock app that requires a system update.

The first is misleading, as TCC has nothing to do with system permissions, but privacy controls. Although Claude has made no comments at all on entries by TCC, I have checked through those thoroughly and there’s no evidence of any problem with that subsystem. The command recommended isn’t likely to do anything useful, either.

Despite Claude having provided no evidence of any problem with LaunchServices, its second solution is to perform a full reset of the LaunchServices registry (not cache), although I’m not sure the command given is correct for that. This used to be a popular panacea in the past, but is now more trouble than it’s likely to be worth. The last time I reviewed this for Sequoia, I wrote:
“Running either of those in recent versions of macOS including Sequoia is likely to wreak havoc, though. While this appears to be effective with the Open With… list, its effects on System Settings can be catastrophic. This can remove its entire contents, and even blow the wallpaper away. Normal function should start to return after restarting the Mac, but even then problems can persist.”

Yet Claude gives no warnings of any adverse effects.

The third solution given is the most puzzling. repair_packages was used to repair System permissions in versions of macOS up to El Capitan. It hasn’t been used since, makes no sense at all in Tahoe with SIP and the SSV, and that command no longer exists anyway. I find it surprising that Claude should be recommending a course of action from ten years ago.

The final recommendation is manifestly ineffective, as this problem has persisted across updates from 26.0 to 26.0.1 and now 26.1.

Nowhere does Claude recommend the obvious course of action to contact Apple Support.

Claude’s Summary

The slick summary rounding off Claude’s Complete Analysis of the Problem states confidently that its root cause “appears to be either:”

  1. “A system-level bug in macOS Tahoe’s memory status handling for this specific app”
  2. “Corruption in the app’s entitlements or sandbox configuration”
  3. “A conflict between the app’s resource requirements and what the system is willing to grant”

with the parting comment:
The error code 22 (EINVAL – Invalid argument) in the memorystatus call suggests the app is requesting memory limits or priority settings that the kernel considers invalid for its configuration.

None of those comments is supported in reality, nor by the evidence in the log extract.

My final test was to compare the log entries that Claude singled out as being diagnostic of the problem it has ‘completely analysed’, with those from my Mac mini M4 Pro, whose Clock app works perfectly. You won’t be surprised to learn that, in those respects at least, the two logs are identical. For the avoidance of doubt, that includes the “Kernel Warning” and “Critical Error at Launch” entries that Claude considered diagnostic.

My Summary

When presented with a log extract, Claude misidentified and misread log entries, and introduced errors in reporting what it claimed were the most important diagnostic entries. Its recommended solutions were ineffective, unwise, or a decade out of date. Neither did it give any warnings for their adverse effects, or recommend contacting Apple Support.

This doesn’t say that AI can’t help interpret macOS Unified log entries, and can’t do better in the future. But I hope it demonstrates the reality of what it will do today.

Postscript

Following up on Claude’s suggested solutions, I can confirm that the suggested tccutil command is ineffective, and that Tahoe has removed the -kill option from lsregister “because it was dangerous and no longer useful”. As the third solution was removed years ago, that leaves only the last of its suggestions that is valid.

LogUI build 77 improves readability of log entries

As I explained a couple of weeks ago, log entries come in four flavours: regular, activity, boundary and signpost. These types have previously been distinguished by a single digit in the entry. Although the latter two aren’t commonly used, boundaries because they’re uncommon, and signposts because they’re seldom useful, activities do need to be distinguished from regular entries. This new build of LogUI uses emoji to do that, and brings improvements in exported entries.

Log list

Rather than display a single digit for the type of each log entry, LogUI now uses an emoji:

  1. regular entries are marked with a ▶ right-pointing triangle,
  2. activities with a 🥎 softball,
  3. boundaries with a 🎬 clapper board,
  4. signposts with a 📍 round pushpin.

Those make it much easier to scroll down through entries looking for activities, for example.

Rich Text export

Those are also shown in extracts exported to Rich Text Format files. Those exports have been improved to more closely reflect entries as they’re displayed in LogUI’s window, including the new type emoji, with the addition of extra fields for signposts.

Copy

The other form of exported entries are those copied from the list, by selecting them in the window and using the Copy command. Rather than trying to copy the full text contents of all the fields, this has previously brought a selection separated using tabs. In this version, the fields are expanded and use a vertical bar | as a separator, to provide
date | level | category | sender | process | subsystem | message or signpostName

Where an entry has no data for that field, it’s left empty. As signpost entries don’t have message fields, and the other three types don’t have signpostNames, the last of those depends on the entry type. This should make copied signposts more meaningful.

For example, a short regular entry might provide
2025-10-19 14:48:00.385306+0100 | info | SDNearbyAgentCore | CoreUtils | sharingd | com.apple.sharing | Checking active FT call count: 0
an activity
2025-10-19 14:48:00.902644+0100 | | | RunningBoard | runningboardd | | state update
and a signpost
2025-10-19 14:48:00.435671+0100 | | tracing | SkyLight | WindowServer | com.apple.SkyLight | FrameLifetime

LogUI 1.0 build 77 for macOS 14.6 and later is now available from here: logui177
from Downloads above, and from its Product Page.

Enjoy!

Inside the Unified Log 6: Difficult times

Time is central to any log, and with the high performance of the Unified log it’s fundamental. It’s also one of its most confusing aspects, particularly when you add time zones, seasonal clock changes, and clock synchronisation.

Clock ticks

I believe each log entry includes the Mach absolute time (MAT) when that entry was made, and those form the log’s internal timebase. However, Apple doesn’t document that, there are alternatives such as Mach continuous time, and times exposed in the public OSLog API are limited to opaque Date structures rather than MAT. In contrast, the log show command can return a numeric field named machTimestamp that does appear to contain the MAT of that log entry.

The first complication with time is that MAT differs between Intel and Apple silicon Macs. While each increment in MAT represents one nanosecond in Intel Macs, in Apple silicon chips MAT ticks occur three times every 125 nanoseconds, or once every 41.67 ns. These are monotonic, in that they always move forward, so every subsequent tick count is greater than (or equal to) the previous ones, unlike wallclock time.

I have looked in detail at how this is reflected in times shown in the log when accessed by different methods, including that now used by LogUI. In practice, this means that the finest resolution of time in LogUI is 1 microsecond, which should suffice for almost every purpose.

Wallclock time

While MAT can be useful for measuring differences in time with great precision, it doesn’t tell you the time in terms of real-world clocks, or wallclock time. Conversion between those relies on data stored in opaque timesync files stored alongside log files. Those are used to provide a wallclock time for each log entry when it’s obtained either through the log show command, or the opaque Date structure in the OSLog API that LogUI relies on. It’s here we encounter all the complexities of the wallclock, such as time zones, seasonal time corrections, and corrections to synchronise with global time references.

Times shown in log entries also need to match those set in the log browser. In practice that leaves two options for times shown in log entries: express them in the local time when they were saved to the log, or in the local time when they’re extracted from the log. By default, the log show command adopts the former, as does Ulbow because it gets its log entries using that command tool, but LogUI converts all times to local time when the log extract is obtained. log show does have an option --timezone local to synchronise entries to current local time, but that’s seldom used.

Wallclock adjustment

The only time measure that remains unaffected by system wallclock time adjustments is MAT. No matter how a wallclock time is expressed, though, there will always be a hiatus and the risk of duplicate times being given, for example with consecutive entries of
08:26:16.140474+0100
08:26:10.043353+0100 === system wallclock time adjusted
08:26:10.044335+0100

If you’re using the log to measure time, and those measurements span a wallclock adjustment, you will need to make a manual adjustment to allow for that.

Time zone and season

When times of log entries are expressed using the local time applicable when those entries were written, changes in time zone and seasonal adjustments become confusing. For example, these entries were written when the wallclock was advanced by one hour in accordance with the start of British Summer Time:
2020-03-29 01:09:22.489149+0000 361080253974026
2020-03-29 01:09:22.489160+0000 361080253985232
2020-03-29 02:09:22.522734+0100 361080253990360 === system wallclock time adjusted
2020-03-29 02:09:22.522749+0100 361080254005593
2020-03-29 02:09:22.522913+0100 361080254170158

In each case, the wallclock date and time are given first, followed by the MAT (from an Intel Mac), demonstrating that the hiatus of one hour doesn’t affect the latter.

bst03

According to convention, Summer time adjustments across Europe are made at 01:00:00 +0000 (UTC). So in the Spring, clocks are put forward from 01:00:00 regular time to 02:00:00 Summer time. In North America, changes are made at 02:00:00 local, and usually on different days. Because of the way that macOS manages time, changes to the system clock will inevitably occur shortly after the officially set time, in that case nearly ten minutes later.

To avoid this confusion, LogUI expresses wallclock and control times using local time when those entries are extracted from the log. In that case, you’d see
2020-03-29 02:09:22.489149+0100
2020-03-29 02:09:22.489160+0100
2020-03-29 02:09:22.522734+0100 === system wallclock time adjusted
2020-03-29 02:09:22.522749+0100
2020-03-29 02:09:22.522913+0100

as you would obtain that log extract when British Summer Time was already in force.

Converting from Date values stored in log files to strings expressed in local time isn’t something an app would want to repeat constantly, for example on the fly when scrolling through a list of 50,000 entries. LogUI therefore converts each time into text when it fetches those log entries. If you then save the log extract in JSON format, those times remain in that local form, and aren’t converted again if you open that file in a different time zone or seasonal time correction. If you want to retain times in their original format, so they’ll be converted into a later time zone, for example, save the log as a logarchive, to ensure that each time will be converted into text using the local time applicable when the extract is fetched from that logarchive. That should affect few users, and only in unusual situations.

Key points

  • The Unified log appears to record times in Mach absolute time, and convert those to wallclock format when accessed.
  • By default, the log show command, and apps like Ulbow that use it, give the wallclock time adjusted to local time when each log entry is written. That can result in confusing time sequences.
  • LogUI expresses all times in local time when log entries are extracted from the log. That makes its handling of time independent of seasonal changes, and more consistent.
  • Periodic wallclock adjustments affect all wallclock times, and may need to be allowed for when measuring times from log entries.

Inside the Unified Log 5: Navigation

The greatest challenge in using the Unified log is how to navigate its many thousands of entries, to find those you want to read. Success depends on the combination of two aids: time and waypoints (or landmarks).

Time

No matter how you obtain log extracts, you need to know when to look for those entries. The more precisely you can work out the time of interest, the quicker and easier it will be to locate the entries you’re interested in. While the log command offers alternatives, LogUI works throughout using the local time applicable when you access the log, allowing for your current time zone and any seasonal adjustment to it, when accessing the live log in that Mac.

However, the underlying times given in log extracts are those recorded by the Mac or device whose log you’re accessing. If its system clock was five minutes slow when those entries were written to its log, then you need to allow for that. For example, when I first started my Mac yesterday its clock might have been 1 minute slow. An event that occurred at 10:56 yesterday by the room clock would therefore appear in the log entries for 10:55.

One important time you can discover is the boot time of the Mac. Mints offers a Boot button to retrieve boot times over the last 24 hours. If the logs were written by a different Mac or device, then you’ll need to search for the time of that last boot. Fortunately the first two log entries are easily recognised:
11:41:37.562774+0100 === system boot: D3CEA9B4-F045-434D-8D12-C6E794A02F14
11:41:42.758780+0100 kprintf initialized

The long gap between the first two entries is accounted for by the firmware phase of the boot process. If necessary you can search for a message containing === (three equals signs). Mints provides the time of the first of those for each boot, and its UUID.

There are two occasions when time can become confusing, when clock corrections are applied, and when clocks are moved forward or back to add or remove summer or seasonal time changes. Fortunately the latter only change twice each year, although when they do, you really don’t want to see what happened in the log, and those changes aren’t even applied at a predictable time.

Clock corrections, like kernel boot, are readily found by the === text in their message. They normally happen in pairs, with the first correction the larger, and the second often far smaller. Here’s an example seen in consecutive log entries:
08:26:16.140474+0100 /usr/libexec/sandboxd[80] ==> com.apple.sandboxd
08:26:10.043353+0100 === system wallclock time adjusted
08:26:10.044335+0100 Sandbox: distnoted(72) deny(1) file-read-metadata /private
08:26:10.044601+0100 2 duplicate reports for Sandbox: distnoted(72) deny(1) file-read-metadata /private
08:26:10.044606+0100 Sandbox: distnoted(72) deny(1) file-read-metadata /Library
08:26:10.089204+0100 === system wallclock time adjusted
08:26:10.091850+0100 started normally

The first adjustment dropped the clock back by 6.1 seconds, from 08:26:16.140474 to 08:26:10.043353. This means that you’ll see times of 08:26:12 both before the correction and afterwards. The second adjustment, from 08:26:10.044606 to 08:26:10.089204, was far smaller at 0.045 seconds, and at least went in the right direction.

The most substantial clock corrections are made shortly after booting. Although macOS does make them later, the size of those should be smaller.

Waypoints

Even working with times resolved to the second, those can still leave you browsing thousands of log entries. To locate more precisely you need details of one or more entries that will be sufficiently distinctive to focus in on a few dozen. These are waypoints for navigation.

LogUI provides three methods for locating these waypoints:

  • using a search predicate to determine which log entries are extracted from the log;
  • applying search text to filter out all entries that don’t contain a term;
  • searching a rich text export of the log extract.
Predicates

These are best used when the time period of your extract needs to be relatively long, so would return a large number of entries. For example, if you can only narrow the time down to several minutes, and are looking for the time that a specific app was launched, you can look for that app’s job description when it’s created and written to the log by RunningBoard.*

Over a period of two minutes, RunningBoard might write thousands of entries in the log, so looking for your app’s job description among them would be time-consuming. Set the start time and period to cover the whole of the time you want to search, then set a predicate for the subsystem com.apple.runningboard.

When LogUI fetches that log extract, there might still be over 2,000 entries, so now is the time to apply search text to filter those further.

Search filter

To filter those 2,000 entries and show only those containing job descriptions created by RunningBoard, enter the text constructed job in LogUI’s search box, with its menu set to Messages, and press Return. You’ll now see that list reduced to just a handful, and looking through them you can discover exactly when your waypoint occurred.

My example for this article starts with a period of just 2 minutes, in which there were more than 100,000 log entries.

Using the com.apple.runningboard predicate whittled those down to 13,443 entries.

Searching within those for constructed job left me with just 8 entries to look through.

Search rich text

Sometimes you can’t devise the right combination of predicate and search filter to discover what you’re looking for, which might be an error reported in a subsystem or a process that you can’t identify. One good way forward is to narrow your log extract as much as you can, then save the extract as Rich Text, open that in a suitable editor, and search through it for the word error. That will discover every log entry containing the word error anywhere, rather than confining it to the message text.

Using time and waypoints

Armed with your waypoint and the exact time of its entry in the log, you can now set that as the start time, set a period of a couple of seconds, and get a full log extract containing all the detail you might need. This should give you further clues to allow you to move through time using predicates and search filters to discover what happened. This is much quicker and less frustrating than trying to scan through thousands of log entries in search of vague clues.

Key points

  • Use time and waypoints to find log entries.
  • Mints’ Boot button gives times of each boot in the last 24 hours.
  • Reduce the number of log entries returned using a predicate.
  • Narrow those down using a search filter.
  • Search all text by exporting the log extract as Rich Text.

* Sadly, the days of being able to access freely RunningBoard’s informative job descriptions in the log are over. As of macOS Tahoe, all you’ll see is the dreaded <private> of censorship. If you want to examine these now, you’ll have to remove log privacy protection first. Thanks, Apple, for providing such useful tools then rendering them next to useless.

Inside the Unified Log 4: Log entries

For many years, I believed what the log command told me, that log entries could contain any of the 26 or more fields available, although they didn’t. It was only as I was developing utilities like LogUI that I discovered that log entries come in (at least) four types, each with its own format and set of fields. This article is a guide to those, and how they are displayed in LogUI.

Entry fields

Those available in the OSLog API are fewer in number than appear in log command output, and include some of limited interest. Those not exposed in LogUI include:

  • store category, which is invariably disk storage here.
  • format string, that used to format the contents of messages. This was introduced following serious security leaks in High Sierra.
  • components, linking in with the format string.

LogUI displays each entry using the same order of fields and colour-coding. Although they can’t all be seen together in any single log entry, the overall sequence is:

Standard levels are given as text, and chosen from one of the following: fault, error, notice, info, debug, undefined. These are only used with Regular log entries, not other types. LogUI always includes debug level entries when they’re available.

The four types of entry are:

  1. Regular
  2. Activity
  3. Boundary
  4. Signpost.

Regular entries

These are normally by far the most common, and are seen throughout the processes and subsystems writing log entries. They normally contain up to the following fields:
datestamp, [1], activity ID, category, level, sender, process, process ID, subsystem, thread ID, message

These examples include:
datestamp, 1, activity ID, category, level, sender, process, process ID, subsystem, thread ID, message
which is fairly normal.

Activities

These mark specific activities, and vary according to the process and subsystem. Some are valuable waypoints, and all are recognisably shorter than most regular entries, containing only the following fields:
datestamp, [2], activity ID, parent activity ID, sender, process, process ID, thread ID, message

These are examples of one of the most valuable activities reported, indicating a mouse-click or tap. They’re also complete, as they consist of:
datestamp, 2, activity ID, parent activity ID, sender, process, process ID, thread ID, message

Boundaries

These are rare but instantly recognisable because of their brevity. They consist of just three fields:
datestamp,[3], message

Two of the most important are the announcement of the start of kernel boot:

and adjustment of the internal clock:

These are also easy to search for, as their message contains the distinctive === string.

Signposts

By default, LogUI extracts omit Signposts, but if you tick the Show Signposts box before loading log entries, they will also be displayed. In parts, they can outnumber regular entries, and are unlikely to provide you with meaningful information unless you know internal details of their process. Each Signpost adds three type-specific fields, shown after the process ID:
datestamp, [4], activity ID, category, sender, process, process ID, signpost ID, signpost name, signpost type, subsystem, thread ID

These examples come from the most prolific user of Signposts, SkyLight for WindowServer, and contain
datestamp, 4, activity ID, category, sender, process, process ID, signpost ID, signpost name, signpost type, subsystem, thread ID
Note there’s no message field, as their meaning is determined by the signpost fields.

Datestamps and times

The OSLog API doesn’t currently give access to Mach times, only to opaque Date variables. From those, LogUI’s datestamps give:
year–month–day hour:minute:second.microsecond+timezone

All times and time zones given are those current when LogUI obtains that extract, not when that entry was written. This can become extremely confusing when clocks change to and from {summer time, daylight time, daylight saving time, daylight savings time, DST}, and when passing through time zones, and great care is required when reading logs containing such corrections. LogUI tries to make this easier, but care is still required.

If you have used the log command, you may be aware that can return Mach times as ticks, offering precision down to the nanosecond. This currently isn’t possible when using the OSLog API, but given the relatively slow clock of Apple silicon Macs, it’s no longer as useful as it used to be with Intel’s nanosecond Mach ticks.

Censorship

By default, all data in message fields is censored to protect the privacy of the user. This replaces chunks of text with the dreaded <private>, and can render many entries devoid of any useful information. In recent versions of macOS log privacy can be removed by installing a profile. However, that doesn’t apply retrospectively, only to log entries collected after the profile has been installed.

Removing privacy also increases the size in storage of log entries, and may reveal sensitive information. As soon as you have completed acquisition of the logs you need with privacy removed, you should therefore remove the profile, to allow normal censorship to resume.

A suitably signed profile is here: enablelogprivatedata

To install the profile, unzip the archive into a convenient folder and double-click it. You’ll be informed by a notification that you need to review the profile to install it. Open System Settings and select Device Management in its View menu, or search for it. Follow the instructions given there to install and activate it.

Sadly, this doesn’t cover all censorship. Some systems require additional configuration changes, for example CFNetwork diagnostic logging. Jeff Johnson explained how to enable that, but Apple has since blocked that, and I don’t know of a practical alternative. In some cases, additional detail can be obtained by adjusting log settings.

Summary

A short practical summary of LogUI’s log entries is provided in its Help book.

LogUI 1.0 build 74 adds a Diagnostics Tool for your logs

As promised earlier this week, I’m delighted to offer a new version of my log browser LogUI that provides a Diagnostics Tool to help you understand log folders and discover any problems with them.

Open its window using the Diagnostics Tool command in the Window menu, and you’re offered four tools at the top.

The first, Get Info, performs a simple analysis on the files in the selected diagnostics folder. By default, that’s your current live log, in the path /private/var/db/diagnostics, in your Data volume. After telling you how many log files there are in each of its three main folders, and the number of timesync files, it reports the date and time of the oldest Persist log file, marking the start of the continuous log record, in this case nearly 4 days ago.

You can use these tools on any diagnostics folder you can access through its dialog. This includes Time Machine backups, external boot disks, and other bootable systems. Don’t click on the Open button, though, until you’ve selected the diagnostics folder in the view above.

Locating the diagnostics folder in a Time Machine backup can be interesting, but once you’ve found it, LogUI will happily check it for you.

The Catalogue tool lists all the tracev3 log files in the folders inside diagnostics, starting with those in Persist. It gives each file’s creation and modification timestamps, indicating the range for log entries within them, their size in bytes, and an estimate of the period that file covers.

The Analyse tool extracts information from each of logd‘s statistics files, with the number of log entries broken down in frequency order. If you tick the CSV checkbox, they will be delivered in CSV format, ready to import into other software such as a spreadsheet.

The last of the tools, Save Text, saves the contents of the window to a text file for your records.

Further information about locations used for log files is in this article.

LogUI 1.0 build 74 is now available from here: logui174
from Downloads above, and from its Product Page.

Enjoy!

Inside the Unified Log 3: Log storage and attrition

By far the most common problem experienced with the Unified log isn’t its large number of entries, but a lack of entries. You go to check your Mac’s security using SilentKnight, or Skint runs its automatic daily check, and they can’t find any log entries recording XProtect Remediator scans. Since those are obtained by analysing the log for the previous 36 hours, when your Mac’s logs only go back 8-12 hours, entries for the last set of scans are likely to be missing. This article looks at why that happens, and how macOS maintains its log.

Traditional Unix-style logs are maintained according to their age. Every 24 hours, routine housekeeping procedures delete log files over a certain age, typically five days, in the process of rolling the log. Because the Unified log could over that five-day period have swallowed many GB of storage, its maintenance service logd deletes log records according to multiple criteria including the space they occupy, their age, and the type of entry. This is considerably more complex, and occurs in three phases, according to where the entry is stored.

Ephemeral entries

Log entries are initially written to memory, before logd writes most of them to permanent storage on disk.

mul102LogdFlow

The first substantial purging of entries thus occurs when logd decides which are ephemeral and won’t be written to disk. This can be seen by following the number of entries in a short period of high activity in the log, over time, and is shown in the chart below for a sample period of 3 seconds.

When fetched from the log within a minute of the entries being written, a total of 22,783 entries were recovered. Five minutes later there were only 82% (18,655) of those remaining. Attrition of entries then continued more slowly, leaving 80% (18,309) after 8 hours. Analysis suggests that over this period in which there were about 6,100 log entries per second written to disk, approximately 1,700 log entries per second were only kept in memory and never written to disk. That suggests about 22% were ephemeral, a proportion that’s likely to vary according to the origin and nature of log entries.

Persist entries

The great majority of log entries that survive to be written to permanent storage are kept in the tracev3 files in /private/var/db/diagnostics/Persist, where logd maintains them according to the total size of that folder, with a target of 520-530 MB. As each tracev3 file is up to 10.5 MB in size, that results in logd retaining about 50 files in that folder, although some are smaller than the maximum.

Two of my apps currently provide the datestamp of the start of the current collection of Persist log files as an indicator of the oldest log entry available from them: XProCheck, and Mints with its Logs button. This is a feature I intend adding shortly to LogUI.

However, not all log entries are stored in those Persist files. Looking back in time at total log entries available for a set ten minute period each day, you might see totals like:

  • 1 day old 33,827 in 10 minutes
  • 2 days old 98,534
  • 3 days old 59,296
  • 4 days old 10
  • 5 days old 1
  • 6 days old 40
  • 7 days old 0
  • 8 days old 358
  • 9 days old 1.

Those for the last 3 days are almost all Persist entries, but older entries are those retained in tracev3 files in the Special folder.

Special entries

Fault and Error log entries are normally written to the tracev3 files in the Special folder, and may contain additional message content kept in the warren of folders and files inside /private/var/db/uuidtext. logd purges entries from Special files separately, and apparently on the basis of their type and content rather than size. As a result, the Special folder can contain many tracev3 files of sizes ranging from over 2 MB to just a few KB, with their size tending to reduce with age. Any log entries recovered from dates before the oldest Persist file thus must have come from Special files.

Although files stored in the uuidtext folder are small, there can be a great many of them, and total size of that folder can exceed 1 GB. Those too are maintained by logd.

Other folders and files

tracev3 files stored in the Signpost folder contain only Signpost log entries used for performance assessment, and are purged at a slower rate than Persist files, but not retained as long as Special files. The High Volume folder appears seldom if ever used. The timesync folder contains time synchronisation data, small files that normally cover the whole period of Special files.

The /private/var/db/diagnostics folder contains several other files, including the logs of logd and logd_helper, and most significantly pairs of statistical summaries written during log maintenance, named logdata.statistics.[n] where n is a number starting from 0, in both .txt and .jsonl (JSON) format.

Each time logd performs maintenance on a tracev3 file, or on associated uuidtext files, it records data about the files in the current logdata.statistics files, both as plain text and in JSON format. The most useful of these records occurs when a Persist tracev3 file is rotated from being the file into which new log entries are written, to being retained without further additions. That entry records:

  • the name of the tracev3 file;
  • the time of rotation, thus the time immediately following the last log entry to be made to that file;
  • the total number of log entries in that file, for example 42,365,476;
  • for the top 20 processes that wrote entries in that period, the number of entries, the percentage of total entries, and the path to the process, listed in order of number of entries.

For example, in that tracev3 file containing a total of 42,365,476 entries, the kernel might have written 13,095,296 entries, 30.9%, and be top of the list, while runningboardd might only have written 1,223,157 or 2.9%. These statistics can be valuable in drawing attention to periods when there were problems, and for discovering which entries are limiting the coverage of Persist files, making it impossible for apps to recover entries for XProtect Remediator scans, for example.

Statistics entries for memory rollovers can also be useful, as are those for Special file rotation, although the latter contain fewer entries than Persist files.

Extending the period of log coverage

Currently, there doesn’t appear to be any way to set logd‘s size allowance for Persist files. When the Unified log was first introduced, it wasn’t unusual for that setting to preserve full log records covering a period of up to 20 days. As more processes now write copious entries in the log, a Mac that’s left awake and running at all times may only retain the last 20 hours of Persist entries, or even less.

Macs that don’t need to be awake and running at all times can extend their log coverage by sleeping or being shut down, when of course no entries can be written. If that isn’t possible, you can write your own XML property lists to /Library/Preferences/Logging to limit the retention of specific categories of entry. However, experience shows that only achieves small extensions to time coverage. It’s also worth bearing in mind that disabling privacy protection in the log will increase the size taken by most log entries, so shortening time covered by the retained logs.

Perhaps the wisest and most effective way to extend the time coverage of logs is to discover the causes of excess entries and address those, although that’s inevitably the most difficult solution.

One little-used technique is to turn log records in backups into logarchives, enabling old log entries to be accessed days or even years after they have been written. As an example of what can be achieved, the log entries below were written eight years ago, on 26 September 2017, saved in a logarchive, and browsed using LogUI on 26 September 2025.

I will explain how to do this in a future article in this series.

Summary

  • Log maintenance is a sophisticated managed process that discards log messages for several reasons, most generally to keep total log file size within limits, rather than removing entries purely on the basis of age.
  • A fifth of log entries are likely to be ephemeral, and lost from the log within the first minutes after they’re written. If you want the fullest entries possible, obtain the log excerpt as soon as possible after its entries have been written.
  • Most retained log entries are written in Persist logs, where tracev3 files are removed by age to keep their total size to just over 500 MB. Those should preserve log entries for hours or days after they’re written.
  • Entries for Faults and Errors are stored in Special logs, where they’re kept for longer, sometimes for weeks.
  • logdata.statistics files provide detailed statistics for log files as they’re rotated, and can tell you which processes wrote most entries.
  • As logs aren’t written during sleep, or when shut down, allowing sleep and shutting down will extend the duration of log records.
  • Time Machine and other backups can be used to recover old logs as logarchives.

Inside the Unified Log 2: Why browse the log?

Following the introduction of the Unified Log, a surprising number of folk you would expect to use it have stopped. Some experienced developers and those providing advice in Apple Support Communities seemingly take pride in their lack of log literacy, claiming that the log is now impossible to use, and only accessible to Apple’s engineers. While it does present obstacles, pretending that the log isn’t a vital tool in diagnosis and understanding is burying your head in the sand. This article shows why.

Why the log?

The log provides support for several purposes. It’s widely used to investigate events such as bugs and unexpected behaviours, to establish their cause before working out how to fix them, in diagnosis and troubleshooting. It’s also used to discover how subsystems within macOS work, and what they do. Examples of those include LaunchServices, DAS-CTS scheduling and dispatching, and RunningBoard, all of which are nearly invisible to other methods, but write copious and explicit entries in the log. With its precise time recording and special Signpost log entries, it’s also invaluable for measuring performance, hence in optimising code.

Concentrating on the log’s use in diagnosis, log entries can be used to answer most of the key questions:

  • What happened?
  • When did it happen?
  • Who made it happen?
  • How did it happen?
  • Why did it happen?
  • What can I do about it?

Diagnose a mystery update

To illustrate those in practice, I’ll use an example that happens to be fresh in my mind, the silent updating of XProtect data last week. The only two clues available outside the log were the fact that XProtect had been updated, and that had occurred at 06:46:43 GMT on the morning of 17 September. There was no record of this event anywhere else that might have given any better information on how it had occurred.

Browsing the log from one second earlier confirmed what and when that had happened. I quickly discovered who made it happen when I found the log entry
2025-09-17 06:46:42.615072 com.apple.duetactivityscheduler REQUESTING START: 0:com.apple.security.syspolicy.xprotect-update:7874AD
revealing that update had been accomplished by a background check scheduled and dispatched by DAS-CTS, and performed by an update service com.apple.security.syspolicy.xprotect-update.

That in turn fired up XProtectUpdateService, which recorded that it promptly completed and activated the update:
2025-09-17 06:46:42.695517 com.apple.xprotect Connecting to XProtectUpdateService
2025-09-17 06:46:42.744182 com.apple.security.XProtectFramework.XProtectUpdateService XProtectUpdateService booting
2025-09-17 06:46:43.157255 com.apple.security.XProtectFramework.XProtectUpdateService Attempting to apply update: [private]
2025-09-17 06:46:43.191178 com.apple.security.XProtectFramework.XProtectUpdateService Update completed. Activated update [private]

XProtectUpdateService initiated a connection to the iCloud service now used to update XProtect in Sequoia and later, but log entries didn’t show the update being downloaded from that source. Instead, there was an error reported in the entry
2025-09-17 06:46:43.193159 com.apple.syspolicy.activities Finished Xprotect update in 496.4100122451782 ms: Error Domain=XProtectUpdateError Code=2 "Activated update LocalUpdate[5315]" UserInfo={NSLocalizedDescription=Activated update LocalUpdate[5315]}

Although the messages in many of these log entries are opaque, that entry makes it clear that XProtectUpdateService hadn’t downloaded the new version from iCloud, but had activated a local update, which we know from experience means the copy already downloaded to the traditional XProtect location had been used to install that update in its new location. That used to be available to the user through the xprotect update command, but is no longer. Thus, the only way that update could have been installed was the result of com.apple.security.syspolicy.xprotect-update being run routinely.

If we can’t intervene and force the update manually, the final piece of information we need is how often com.apple.security.syspolicy.xprotect-update is run, and that’s revealed into a later log entry:
2025-09-17 06:46:43.202474 com.apple.duetactivityscheduler Submitted: 0:com.apple.security.syspolicy.xprotect-update:58B6CE at priority 5 with interval 86400 (Wed Sep 17 22:58:51 2025 - Thu Sep 18 18:58:51 2025)
i.e. every 86,400 seconds, or 24 hours.

Procedure

How difficult was that to discover? Even with minimal prior knowledge, consummately easy, and it only took a couple of minutes.

My starting point was the timestamp reported for the update by xprotect version, of 06:46:43 GMT. I therefore set LogUI to display 5 seconds of log starting from one second before that. In the screenshots below, times are shown in BST, one hour in advance of GMT.

This returned a total of 7,174 log entries, far too many to browse. Knowing that I was looking for entries concerning XProtect, I then typed that into the search box and pressed Return, to display only those entries whose message contained the text xprotect.

That narrowed down the number of entries to just 65, starting with the scoring and dispatch of com.apple.security.syspolicy.xprotect-update by DAS-CTS at 42.608967 seconds, and containing all the entries quoted above. Just to be certain that I hadn’t missed anything relevant, I then cleared the search box and pressed Return to display all log entries again, scrolled down to 42.608967 seconds, and checked through those for the period to 43.19315 seconds, when the update had completed.

Of course, not all log investigations are as simple or successful, but many are just as straightforward. The main limitation isn’t the excessive number of log entries, but those from subsystems that make very few entries, as occurs in Spotlight indexing and search. There’s always a way to filter out unwanted entries, but you can’t magic in entries that were never made in the first place.

Conclusions

Browsing the log might appear daunting, even overwhelming or terrifying at first, but as you become more familiar with it you appreciate the rich information it can provide. Log literacy is one of the basic skills required for anyone who wants or needs to dig deeper into their Mac or Apple device. Without it diagnosis, research and performance measurement are like trying to paint a landscape while wearing a blindfold.

Inside the Unified Log 1: Goals and architecture

The introduction of Mac OS X in 2000-01 brought conventional text-based logging to the Mac, with standard logs including system.log and console.log.

console2005

With the release of macOS 10.12 Sierra in 2016, those were almost completely replaced by the Unified Log, which has continued evolving since. Intended to provide a single efficient logging mechanism for user and kernel modes, its design goals are:

  • to maximise information collection with minimum observer effect;
  • as much logging on as much of the time as possible;
  • compression of log data for efficient use of space;
  • a managed log message lifecycle;
  • designed-in privacy protection;
  • to be common across all Apple’s operating systems;
  • all legacy APIs (NSLog, asl_log_message, syslog, etc.) to be redirected into the single log;
  • to support debugging, but not system administration or audit.

To achieve this, log entries are written using the OSLog API (or Logger from Swift), handled by the logd daemon and compressed into a buffer. From there entries are either retained in memory if intended to be ephemeral, or written out to a file. Log entries are only made from the start of kernel boot; earlier phases of the boot process instead save breadcrumbs that are largely inaccessible and unintelligible.

mul102LogdFlow

Performance of writing log entries is excellent, with a single process able to write sequential entries every 400 ns from a code loop, a rate of 2.5 million entries per second, although that rate is unlikely to be sustainable for long.

Log storage

There are two main groups of files that store log entries: those kept in /var/db/diagnostics/Persist/ in the form of tracev3 files containing regular log entries, and further tracev3 files in /var/db/diagnostics/Special/ containing additional shorter-life entries. Additional and lengthier log data can instead be stored in files named by UUID in /var/db/uuidtext/, and there’s also support for special Signpost entries intended for performance measurement, and scope for high-volume collection.

tracev3 files use a proprietary compressed binary format that remains undocumented to this day, but has been largely reversed. Apple’s APIs don’t give direct access to their contents, only through closed-source utilities such as the log command tool and programmatically through the OSLog API. Where users want a more portable format, Apple recommends conversion to a logarchive package, although that’s also undocumented and only directly accessible using log, the Console app and some third-party utilities. Logarchives still store all log entries in tracev3 files.

Collection and retention of entries from different subsystems is configured in logging profiles, XML property lists stored in /System/Library/Preferences/Logging (read-only, in the System volume) and /Library/Preferences/Logging, which the user controls. You can create your own custom profiles, or modify them on the fly using the log command.

The logd service maintains tracev3 files and their ancillaries, weeding them to remove time-expired entries. It does so to constrain the total size of log files in the system, rather than rolling them to retain all entries for a specified period. Most ephemeral entries are weeded within 5 minutes of being written to the log, leaving persistent entries to remain for the following days, depending on the volume of new entries being written. For example, in a 3 second period of collection, when all entries were obtained within a minute of being written, 22,783 entries were found. Five minutes after they had been written, only 82% of those remained, and over 8 hours later that had fallen to 80%, or 18,309.

Log content

In contrast to traditional text-based logs, entries in the macOS log contain structured data in set fields, such as the datestamp, subsystem and log message. The number of fields available from the log command has risen from 16 to over 25, but entries are constrained in which fields are available, according to their type. Currently there are four types, Regular, Activity, Boundary and Signpost.

Some log entries, notably those written to /var/db/uuidtext/, can have very long message fields, extending to dozens of lines. Among the most verbose is the com.apple.runningboard subsystem, which not infrequently writes the whole of its records for an app into the message field of a single log entry.

Privacy

Privacy protection censors content of log entries when they’re written, replacing sections of the message field with <private> in accordance with the formatting string for that message. This protection can be disabled, but as entries are censored when they’re written, that only affects those written after censorship has been removed, and can’t be applied retrospectively.

One significant change in macOS 26 Tahoe is that the message contents of all log entries written using the old NSLog interface are replaced with <private>, rendering them essentially useless. Since macOS 10.12.4, all access to log entries has required admin privileges.

Access

macOS provides users with two means of accessing entries in the log: the log command tool, and Console app. In common use, log generates text output, so losing the original data fields, one of the major advantages of the Unified Log. Console offers two methods of access: a live stream of entries, or browsing past entries in a saved logarchive.

I have four main tools that provide extensive log access:

  • LogUI, using the OSLog API and displaying entries as formatted SwiftUI Lists;
  • Mints, offering special-purpose browsers for Time Machine, APFS, and other domains;
  • Ulbow, using the log tool and displaying entries as formatted Rich Text using AppKit;
  • Consolation, using the log tool and displaying entries as formatted Rich Text using AppKit.

These are available from their product page, and here for Mints.

预言在应验:五年前所讨论的未来人机交互的新范式_6.ylog

从 2024 年的今天,回望 2019 年的 Apple 和 Ive 团队,我们会发现有些变化和趋势似乎是早已注定的。在过往的观察和分析中,我们所预言的事情正在成为现实和主流。常言道以史为镜可以知兴替,今天再看当时的 Apple 和 Ive 团队,关于产品的演进思路和设计策略的变化都早有端倪,也能预见在 AI 席卷的浪潮下,Apple 将会如何应对。

在这一期,你会听到:

—- 二十年前的专利文件:通体透光的 iPhone

—- 国产厂商和 Apple 在设计上的差异

—- 成功的设计:AirPods 只是剪掉线的 EarPods

—- 塑料手机的设计巅峰:iPhone 5c

—- 刘海与机器视觉:早早布局的 AI 伏笔

—- 未来十年的人机交互:人和人之间怎么交互?

—- 设计策略上的「S型曲线」体现在哪里?

—- 产品路径上迷路的 iPad

—- 光洁的划痕:是矫情还是哲学?

—- 史上最佳手机壳:iPhone 5c 的多彩硅胶壳

—- 拟物化的残党,现在理解扁平化的先进性了吗?

|相关图片|

首款 Unibody 设计于 2008 年 10 月发布
截图来自:Designed by Apple in California

查看更多图片和设计讨论:Mac Pro 2019

|拓展阅读|

如何评价 iPhone X 的工业设计?

交互的王,时代的狂!万字详解灵动岛的今生来世!

十年轮回?经典进化!工业设计师深入解读 iPhone12!

从技术寿命 S 曲线,看阳极氧化铝的设计

抽象的产品,用户「界面」的设计

如何看待 Evans Hankey 从 Apple 设计团队离职?

注定会离职的 Jonathan Ive 和科技产品的设计趋势

|登场人物|

苏志斌:工业设计师,车联网智能硬件产品经理 / 联创,《设以观复》作者

王汉洋:AI 行业从业者,多档播客主播,《拯救东北1910》《山有虎》作者

|相关链接|

若你所使用的播客客户端未能完整显示插图,或遇网络问题未能正常播放,请访问:

荒野楼阁 WildloG 的地址:https://suithink.me/zlink/podcast/

阅读设计相关的各类文章:https://suithink.me/zlink/idea/

|其他社交网络媒体|

苏志斌 @ 知乎|SUiTHiNK @ 即刻 / 微博

苏志斌SUiTHiNK @ Bilibili / YouTube / 小红书

|联络邮箱|

suithink.su@gmail.com

欢迎在 小宇宙、Spotify、YouTube、Apple Podcast 收听本节目,期待你的留言。

❌