Normal view

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

A primer on predicates for LogUI

By: hoakley
3 April 2025 at 14:30

All good log browsers provide tools to narrow down the log entries they display. Without those, it would be easy to waste all day wandering through tens of thousands of entries. One common tool provided by macOS, directly and in the log command tool, is filtering using predicates. Although LogUI provides easy access to simple predicates, to get the best from them, it’s worth digging a little deeper, as I do here.

Instant predicates

LogUI’s instant predicates filter log entries according to any of four basic predicate types:

  • subsystem, such as com.apple.sharing, the field shown in yellow in log extracts;
  • eventMessage, the text message listed in white/black at the end of each entry;
  • processImagePath, such as mediaanalysisd, shown in blue, the name of the process making that entry;
  • senderImagePath, such as libxpc.dylib, shown in red, the name of the process sending that entry.

These are quick to enter in the text box to the right of the popup menu in the window’s toolbar, but in many circumstances can prove too broad, and need narrowing down further. In other situations, you want to browse entries from two subsystems, or using a combination of criteria. The best way to do that is to write a short predicate. For single use, you can do that in the one-off predicate editor using the Set button.

When you want to reuse that, you can add it to the predicate popup menu using Settings Predicate (currently a bit kludgy).

Predicates

macOS can use predicates in other situations, most commonly for Spotlight search. If you’re interested in those, see Apple’s Predicate Programming Guide. Here I’ll describe predicates as they’re more commonly used to filter log entries, as they’re usually much simpler.

Each simple predicate consist of three parts:

  • the name of one of the fields in a log entry, such as subsystem or eventMessage. This sets where the filter looks in each entry;
  • an operator, which might be == for ‘equals’ exactly, or for text is commonly CONTAINS[c] for case-insensitive contains;
  • text or a numeric value to look for, such as “error” or 513. Only those entries equalling or containing (or whatever the operator means) this in the specified field will then be returned from the log and displayed.

Here are some basic examples.

eventMessage CONTAINS[c] "error"
entries will only be those with the text error in their message field.

subsystem == "com.apple.duetactivityscheduler"
entries will all have that text, ignoring case, but only that text, as the name of their subsystem.

subsystem CONTAINS[c] "com.apple.xpc"
entries will have any subsystem containing that text, which also includes com.apple.xpc.activity.

Fields

Although you can use any of the fields shown in LogUI (and some that aren’t), the most commonly used are, in order as they are shown in LogUI’s window:

  • eventType (red) – matches the type of event, such as logEvent (1024), traceEvent (768), activityCreateEvent (513), or activityTransitionEvent (514). Can be given as characters (case-sensitive) without quotation marks, or using the digits given in parentheses. Use these only with the operators == or !=, as they are treated as numbers rather than text.
  • category (green) – this matches the category, and varies according to subsystem. This is given as text in quotation marks, and is normally lower-case.
  • messageType (white/black) – matches the type of message for logEvent and traceEvent, and includes default (0), release (0), info (1), debug (2), error (16), and fault (17). Can be given as characters (case-sensitive) without quotation marks, or digits as shown in parentheses. Use these only with the operators == or !=, as they are treated as numbers rather than text.
  • senderImagePath (red) – this matches the text pattern in the name of the sender, which might be the name of a library, extension, or executable.
  • processImagePath (blue) – this matches the text pattern in the name of the process that originated the event.
  • subsystem (yellow) – this matches the subsystem specifier, e.g. com.apple.TimeMachine, given as text in quotation marks. You may find it best to use CONTAINS[c] rather than ==, to allow for differences in case and extended subsystem specifiers.
  • eventMessage (white/black) – for this, you specify a text pattern, or text, within the message, given as text in quotation marks.

Operators

The following comparisons and other operators are available:

  • == (two equals signs) for equality
  • != or <> for inequality
  • >= or => for greater than or equal to
  • <= or =< for less than or equal to
  • > for greater than
  • < for less than
  • AND or && for logical and
  • OR or || for logical or
  • NOT or ! for logical not
  • BEGINSWITH, CONTAINS, ENDSWITH, LIKE, MATCHES for string comparisons, using regex expressions when desired; strings can be compared with case insensitivity and diacritic insensitivity by appending [cd] to the operator, e.g. CONTAINS[c] means case-insensitive comparison
  • FALSE, TRUE, NULL have their expected literal meanings.

There are others as well, but you’ll seldom use them to filter log entries.

Building complex predicates

To see the scheduling and dispatch of background activities by DAS-CTS, you need to look at log extracts showing both their entries. Use the predicate
subsystem == "com.apple.duetactivityscheduler" OR subsystem CONTAINS "com.apple.xpc"
to do that. The first part of it includes those entries from DAS, and the second includes those for XPC and its relatives that run CTS. Using an OR between the two parts combines both sets of entries in the one extract.

To see the reports posted by XProtect Remediator, you need to look at those entries made by its subsystem that have the right category, using the predicate
subsystem == "com.apple.XProtectFramework.PluginAPI" AND category == "XPEvent.structured"
Using the AND operator ensures that the only entries shown come from that one subsystem, and they are given just that category.

Time Machine involves a combination of different subsystems and messages. To get a good overview of relevant entries, you can use
subsystem == "com.apple.TimeMachine" OR
(subsystem == "com.apple.duetactivityscheduler" AND eventMessage CONTAINS[c] "Rescoring all") OR
(subsystem == "com.apple.xpc.activity" AND eventMessage CONTAINS[c] "com.apple.backupd-auto") OR
eventMessage CONTAINS[c] "backup" OR
eventMessage CONTAINS[c] "Time Machine" OR eventMessage CONTAINS[c] "TimeMachine"

I’ve broken this down into separate lines, but you shouldn’t do that in the predicate. Taking it line by line it becomes simpler to understand. Use parentheses () to group each part of the predicate carefully as shown.

You can see other examples in the Help book for my free utility Mints: the Further Information pages towards the end give each of the predicates that Mints uses for its log extracts.

Quick summary

  • [field name] [operator] [text or numeric value]
  • common field names: senderImagePath, processImagePath, subsystem, eventMessage
  • common operators: ==, CONTAINS[c]
  • filter info: “text”
  • combine filters using AND, OR.

LogUI build 37 now has more power for browsing the log

By: hoakley
1 April 2025 at 14:30

By anyone’s standards, the macOS log contains a great many entries, and being able to filter out the noise is essential. This is accomplished by applying predicates to determine which entries are extracted and shown in a log browser like LogUI. However, using predicates requires knowledge about the log and its entries, and forms the greatest barrier for most users. This new version of LogUI improves features to help you use predicates to make the log more accessible.

This all happens in the toolbar of its browser window.

The section at the left of the lower row of tools now provides two methods to apply your own predicates: a one-off predicate editor, and an editor for custom entries in its popup menu.

One-off predicates

Click on the Set button to open the one-off predicate editor.

Here you can compose and paste in your own custom predicates that will extract only the log entries that you’re interested in. In this example, only entries whose subsystem is com.apple.duetactivityscheduler, or contains com.apple.xpc, will be gathered and displayed. Those tell you what’s going on with DAS and CTS scheduling and dispatch of background activities.

LogUI keeps that one-off predicate, even after a restart, as it’s automatically written to its preference file.

Once you’ve clicked Save, selecting the [ … ] item in the predicate menu will apply that predicate to each log extract you obtain.

There’s also an additional standard predicate using the senderImagePath.

Custom menu predicates

Predicates listed in that menu below blowhole are custom predicates saved to LogUI’s preferences using its new Predicate tab in its Settings. This editor is very basic at the moment, and its use a little awkward. This is because SwiftUI much prefers menu contents to be static, so adding items to the predicate menu doesn’t go down too well. This editor allows you to add one predicate at a time, in plain text format.

Click on the Append button here and there’ll be a new predicate named XProtect Remediator with the predicate shown. You can only add one new predicate, then need to quit the app before adding another. I’m sorry that’s so laborious, but once you have set up your custom predicates you can return to using LogUI fully.

The Settings General pane now contains a button to Reset Predicates back to their defaults.

Predicates

A basic predicate is composed of a log field name, like subsystem, followed by an operator such as == (equals) or CONTAINS[c] (case-insensitive contains), and a filter term, usually a string like "com.apple.xpc". So the predicate
subsystem CONTAINS[c] "com.apple.xpc"
will return all log entries with their subsystem containing the text com.apple.xpc. You can combine those basic elements into a more selective predicate using combinators such as AND and OR, so
subsystem == "com.apple.duetactivityscheduler" OR subsystem CONTAINS|c] "com.apple.xpc"
returns entries with a subsystem of precisely com.apple.duetactivityscheduler together with those whose subsystem contains the text com.apple.xpc.

Some years ago I wrote a primer here, and you’ll find some useful predicates in the Further Information section in the Help book for Mints. I’ll be writing more here to help you get the best out of LogUI.

There are a couple of oddities with predicates. SwiftUI tends to like using typographic double-quotation marks, but the macOS predicate builder doesn’t accept them as a substitute for straight marks. So LogUI changes all styled marks to straight ones automatically for you, to ensure those shouldn’t cause a problem. However, when it encounters errors it can behave erratically; while I’m trying to make this more robust, I apologise in advance if using a broken predicate upsets LogUI. It’s worth being careful to check your predicates before trying to use them.

LogUI version 1.0 build 37 is now available from here: logui137

My next task is to improve editing and saving predicates to its preferences, to make them accessible as menu customisations.

LogUI log browser build 31 has better filters

By: hoakley
20 March 2025 at 15:30

This week’s new features in my lightweight log browser LogUI tackle two important areas: initial checks to confirm that the app can access the log, and improving the filtering of log entries using predicates.

LogUI has three key requirements:

  • that the Mac is running macOS 14.6 or later, as enforced by macOS;
  • that it’s run from an admin account, as that has the privileges required to access the log;
  • that there are log records it can access in the path /var/db/diagnostics, as without those it hasn’t got anything to work with.

LogUI 1.0 build 31 now contains code to check the latter two, run soon after launch. If either fails, you’ll see an informative alert, and the app will quit when you click to dismiss that.

LogUI now has internal features to support a wide range of filters that can be applied when fetching log entries. These are an essential means of reducing the number of entries displayed, and of focussing your attention on what’s important.

This is reflected in its Settings, which now refer to Text rather than a Subsystem. The window toolbar now has a Predicate popup menu, and its text box is labelled text rather than Subsystem.

This menu offers the following options:

  • none, which applies no filtering and displays all log entries;
  • subsystem, which uses the text entered as the name of the subsystem whose entries are to be displayed, as in the previous builds;
  • eventMessage, which shows only those log entries whose message contains the text entered;
  • processImagePath, which shows only entries whose process name (or path) contains the text entered;
  • [Edit], which in future will open an on-the-fly predicate editor, but currently doesn’t filter;
  • TimeMachineBasic to blowhole, which use set predicates to display log entries for those features. The first two are different levels of detail for Time Machine backups, error finds entries with that word in their message, kernel finds entries with the kernel as their process, and blowhole finds entries made by my command tool for writing entries in the log.

Text entered is not case-sensitive.

Although it’s currently possible to change and extend those, that involves delicate surgery to LogUI’s preferences Property List, and I don’t intend you to hack that just yet. The next features will provide a proper editor in LogUI’s Settings, and the on-the-fly editor accessed through this menu.

Otherwise LogUI should work just the same as the last build. These new features are documented in its Help book, a separate copy of which is supplied in its Zip archive.

LogUI 1.0 build 31 is now available from here: logui131
and I will shortly be giving it an entry in my log browser Product Page, to make it easier to access. I’m also looking at building an auto-update mechanism into it.

Please let me know how you get on with this, and whether it proves useful to you. Enjoy!

Browse your Mac’s log with LogUI

By: hoakley
14 March 2025 at 15:30

If you ever need to understand what’s going on in your Mac, reading its log is essential. However much you might stare at Activity Monitor, read source code or disassemble components of macOS, what you can see in the log tells you what has really happened. Whether it’s a bug or an unexpected event, it’s the only way to look back and discover what went on.

For most, Console isn’t the right tool. It only offers the options of viewing its live stream, or making an archive of the whole log and wading through that when you need to look at an event in the past. Although my log browser Ulbow gives much better access, for many it’s still a daunting task. I’ve now switched almost entirely to using my new lightweight log browser, LogUI, and here explain how you can use it. Although it’s currently an early release with limited features, you should find it ideal for getting started.

LogUI 1.0 build 27 is available from here: logui127

This comes as a Zip archive, so unZip it, and move the LogUI app to another folder before running it for the first time; your main Applications folder is fine, and almost anywhere will do nicely. Alongside it is a copy of the PDF Help file that’s also inside the app, so you can refer to it when you’re not running LogUI. As the two are identical, you can trash the separate copy if you’re happy to use that inside the app.

Before opening LogUI, generate an event that you can examine in the log. One starter might be launching an app. Try to do this when your Mac is otherwise quiet and unoccupied: if Activity Monitor shows it’s busy with lots of background tasks, then the log could be filling with noise, when what you want most is peace. For the sake of simplicity, time this on an even minute, and make a mental note of that time to the second.

As soon as you’ve done that, open LogUI and you’ll be greeted by its window, with its toolbar ready for you to set up and get your first log extract. That should be set as follows:

  • Start to the current date, hour and minutes. As those are set to the time you open the window, they should already be close to the time of the event. Just after the stepper control is the seconds setting. If the event occurred a moment after the seconds changed to 00, that makes a convenient time to start your log extract.
  • Period set to around 5 seconds. This value can be floating point decimal, so might be 2.5 seconds for a smaller log extract.
  • Max entries set to 1000 to start with.
  • Show Signposts not ticked.
  • Full Fields ticked.
  • Subsystem empty.

Then click on Get Log to see the log extract for that period.

In my case, a five second period overfilled the 1000 I had set in Max entries. Scrolling to the foot of the extract showed that had been reached in less than two seconds, so I increased Max entries to 10000 and clicked Get Log again.

There are now over 5,000 entries in the extract, but they scroll smoothly enough to let me look around them.

The best way of reducing the number of entries to make them more understandable is to add a Subsystem as a filter. In this case, as I’ve launched an app, I can get most useful information from LaunchServices, by entering
com.apple.launchservices
into Subsystem. I also reduce the number of fields shown by unticking the Full Fields box, letting me concentrate on the messages. You can toggle Full Fields without having to get log entries again, as it only affects the fields within those entries that are shown in the window. Then click on Get Log again.

Scrolling down through the 358 entries remaining, I quickly reach one with a message field reading
LAUNCH: translocate to <private> from <private>
Although we could do without the privacy censorship here, it’s easy to work out that the app I just launched underwent app translocation, and that’s confirmed a little further down when LaunchServices gives its full path.

If you want a copy of the text from one or more selected entries, use the Copy command (Command-C), then paste it into any text editor. That doesn’t copy all the fields, only those you’re most likely to need elsewhere. For a full copy of that log extract, with colours indicating the fields, click on the Save as RTF button. As with LogUI’s window title, saved files are given default file names containing the start time of that log extract to help you keep them in good order.

This is the same log extract seen in my rich text editor DelightEd.

Finally, open LogUI’s Settings to enter the defaults you want its windows to open with. These match controls in its toolbar. The last of those, Light Mode, enables you to run the whole app in Light Mode if you prefer. For that to work, your Mac will also need to be in Light Mode, and you should tick that box, close the Settings window and quit the app. When you next open it, it should operate in Light Mode. Other changes made to Settings don’t need you to quit the app for them to take effect.

Enjoy!

❌
❌