Mac Logging and the log Command: A Guide for Apple Admins
As an IT admin, you’ve almost certainly had to check some form of log when investigating a problem. Logs tell the story of what’s happening on a system, so they can be enormously helpful in both troubleshooting issues and in learning why the system is behaving the way that it is.
In this guide, we’ll cover some of the basics of Apple’s unified logging system, go over how to read the logs using the log
command, and provide some practical examples of how to filter log messages to find the ones that are most important to you.
When unified logging was first introduced at WWDC 2016, it was a pretty radical and bold change. Until then, most—if not all—logs on Apple platforms were recorded using standard Unix logging systems, usually writing to flat files on disk.
But as Apple’s platforms became more and more complex over the years, the volume of logs they generated increased as well. When Apple introduced unified logging, it dubbed it “logging for the future.” It set out to create a common logging system for all of its platforms with the following goals:
- Provide a single efficient logging mechanism for both user and kernel mode.
- Maximize information collection with minimum observer effect. (In other words, collect as much data as possible while compromising performance as little as possible. Among other things, that meant compressing log data and providing robust ways to manage log message lifecycles.)
- Keep as much logging on as much of the time as possible.
- Design privacy into the system.
Many admins might still think of looking for log messages in the common Unix flat files in /var/log/
. And it’s true, there are still some flat log files written there; for example, /var/log/install.log
contains useful information about the macOS installation process and is easy to parse with command-line tools.
But such flat log files often don’t provide the whole story, and messages logged to them are usually recorded in the unified logging system as well. For a complete picture of what’s happening on a system, you should use the log
command to explore the unified log.
(While we won’t cover it in this guide specifically, it’s worth mentioning that the Console application (in the /Applications/Utilities folder) can also be useful for examining logs if you prefer a graphical interface; however, the log
command is much more flexible and useful in practice. Apple Configurator 2 from the Mac App Store is also useful for streaming the live system log of a connected iOS device, which can be useful for troubleshooting issues as they happen on iOS; Xcode can also be used for that purpose.)
The log Command
The log
command is built into macOS at /usr/bin/log
. For full details on how to use it, type man log
in Terminal to read the man(ual) page for the command. (Press q
to exit.) In this section, we’ll cover the basics to get you started.
Let’s say you want to see all of the “default” logs on your system for the last minute (excluding extra informational or debug-level messages). To do that, you can run the command:
sudo log show --last 1m
You’ll likely be surprised at the sheer number of messages that appear on your screen just from the last minute. That’s because of Apple’s stated goal of doing as much logging as much of the time as possible. As we’ll explain shortly, you can filter messages, but for now let’s look at some of the common options for the log
command.
In the above example, we used log show
. What this does is straightforward: it’s simply showing the logs on the system. We time-limited the list by using --last 1m
(with m
standing for "minute"). You can pass different time modifiers into the --last
option: --last 1h
(the last hour) or --last 1d
(the last day), for example. With the --start
and --end
options plus specific timestamps—in the formats YYYY-MM-DD
, YYYY-MM-DD HH:MM:SS
, or YYYY-MM-DD HH:MM:SSZZZZZ
—you can very narrowly filter the list of messages based on timestamp.
The log show
command shows the logs of the Mac on which you’re running it. You can also combine show
with the --archive
option for passing in the path to a system log archive generated using the command log collect
. The collect
option is useful for collecting logs from any system—your own or another—for analysis later; they can be stored, moved around, and analyzed at any point in time.
The sysdiagnose
tool, which runs automatically when you file feedback with Apple, even automatically generates a system log archive for Apple engineers to analyze (named system_logs.logarchive
in the root of the sysdiagnose
folder). You can view more details on the collect
option in the man page for log
.
To see how these building blocks can fit together, consider this example for collecting all of the default level logs on your system for the last 20 minutes:
sudo log collect --output ~/Desktop/SystemLogs.logarchive --last 20m
This will place a log archive file on your desktop named SystemLogs.logarchive
. To view the logs from the archive, you could run:
sudo log show --archive ~/Desktop/SystemLogs.logarchive
While log show
is useful for looking back in time, log stream
displays logs in real-time. This can be useful for observing logs while an issue is happening or while you’re performing an action on the system and you simply want to watch and learn what’s happening.
For example, to see all of the default logs on your system as they’re happening, use the command:
sudo log stream
(To end the stream, press Ctrl+C
.) Streaming all logs in real-time is not very useful in practice, due to the sheer volume of messages that are generated. Paring down the logs, either when looking back in time with log show
(including with archives) or in real-time using log stream
can be accomplished using predicate filtering.
Predicate Filtering
Apple’s goal to have as much logging on as much of the time as possible is great for admins, because more logging often means more insight that can be used to solve problems or to learn. But it can also make it difficult to find the signal in all the noise. This is where predicate filtering becomes enormously useful.
Apple has a full guide to predicate filtering on its website, and the topic is covered in the man page for the log
command as well. But here’s an example to help get you started:
sudo log stream --debug --predicate 'subsystem=="com.apple.sharing" and category=="AirDrop"'
First, note that we’re streaming the logs (log stream
) and that we’ve also passed in the --debug
option to include more detailed debug logging in the output.
Next, note the --predicate
option. This tells the log command that we want to filter the log messages; what we include between the next set of single quotes becomes the filter. In this example, we’re looking for logs generated by the com.apple.sharing
subsystem that also match the AirDrop
category. This relatively short predicate filter is a great one to keep in your toolbox for looking at AirDrop logs.
Apple defines subsystems as “a major functional area” of an app—or, in this case, the operating system. A category is defined as something that “segregates specific areas within a subsystem”. When you're first starting out filtering logs, it can be difficult to know what criteria to specify in a predicate filter. For example, how did we know that AirDrop uses that particular subsystem and category?
Software vendors can help; they can provide you with the appropriate filters to look for logs generated by their product(s). For example, the Kandji Agent on macOS generates its logs with a subsystem of io.kandji.KandjiAgent
and various categories.
One other way to identify common subsystems and categories is simply to look at the output from log stream
and log show
. Consider a log entry like this:
mdmclient: [com.apple.ManagedClient:OSUpdate] Mapped status SU: [phase: downloading; progress: 0] to MDM: [ProductKey: MSU_UPDATE_21E258_patch_12.3.1; Status: Downloading; IsDownloaded: 0; DownloadPercentComplete: 0]
In this case, com.apple.ManagedClient
is the subsystem, OSUpdate
is the category, and mdmclient
is the process. (Filtering by process is another useful option in predicate filtering.)
The actual log message (eventMessage
) is really useful, too. Based on the example above, if you wanted to filter for just logs that came from the mdmclient
process, were logged with the com.apple.ManagedClient
subsystem with the OSUpdate
category, and contained the string MSU_UPDATE_21E258_patch_12.3.1
in the messages, you could use the following filter:
process=="mdmclient" and subsystem=="com.apple.ManagedClient" and category=="OSUpdate" and eventMessage contains "MSU_UPDATE_21E258_patch_12.3.1"
Using this predicate would output logs showing the status of a software update to macOS 12.3.1 initiated by an MDM solution. Note that we used contains
; other options for string comparison include: beginswith
, endswith
, and matches
, among others. String comparisons with predicate filters are case and accent (diacritic) sensitive by default.
A few useful processes, subsystems, and categories for Apple admins are listed below. This is by no means a fully inclusive list; note also that Apple may at its discretion change these at any time.
Description | Filter parameters |
AirDrop | subsystem: com.apple.sharing category: AirDrop |
Apple Push Notification Service (APNs) | process: apsd subsystem: com.apple.apsd |
Apple Watch unlock | subsystem: com.apple.sharing category: AutoUnlock |
Content caching | subsystem: com.apple.AssetCache |
Gatekeeper | process: syspolicyd subsystem: com.apple.syspolicy.exec |
macOS Installer and Software Update | process: softwareupdated subsystems: com.apple.mac.install , com.apple.SoftwareUpdate , com.apple.SoftwareUpdateMacController , com.apple.mobileassetd |
MDM | process: mdmclient subsystem: com.apple.ManagedClient |
Mobile Activation (Activation Lock, DEP Enrollment, etc.) | process: mobileactivationd subsystem: com.apple.MobileActivation |
Networking | subsystem: com.apple.network categories: connection, boringssl |
OCSP (Certificate validity) | subsystem: com.apple.securityd category: ocsp |
Open Directory | process: opendirectoryd subsystems: com.apple.opendirectoryd , com.apple.AccountPolicy |
User login | process: loginwindow subsystem: com.apple.login |
XProtect | subsystem: com.apple.xprotect |
Private Data
When reviewing logs, you may see entries that contain the string <private>
, sometimes accompanied by a unique identifier (or UUID). When you see this, something on the system has tried to log data that could potentially identify a user, the network, or another piece of dynamic information that could be considered private in some way. By default, these types of entries are masked by the unified logging system; this ties back to Apple’s goal of making privacy a core pillar of unified logging.
Take this example from Open Directory. This log indicates a successful authentication event, such as when successfully unlocking a preference pane in System Preferences:
opendirectoryd: (PlistFile) [com.apple.opendirectoryd:auth] Authentication succeeded for <private> (1B0820C7-05D9-4DEA-BF67-370FAB16E41C): ODNoError
By default, the user name of the user is masked as <private>
. Sometimes when troubleshooting, however, it can be useful to expose data typically marked as private. You can do this with a configuration profile, optionally delivered by an MDM solution, either for specific subsystems or for the system as a whole. (See the Enable_Private_Data profile examples on the Kandji support GitHub repository.)
Here is the same log entry, but with private data logging enabled for the com.apple.opendirectoryd
subsystem, using the Open Directory private data profile:
opendirectoryd: (PlistFile) [com.apple.opendirectoryd:auth] Authentication succeeded for ladmin (1B0820C7-05D9-4DEA-BF67-370FAB16E41C): ODNoError
Note that this time the username ladmin
was logged.
We recommend enabling private data logging only for specific subsystems, and only when absolutely necessary. To resume hiding private data, simply remove the configuration profile.
With the log
command and predicate filtering, the possibilities for viewing, streaming, collecting, and filtering your logs to find the information you need are vast.
The commands above are just the start of what the log command can do to tell the story of what’s happening on a system. Once you spend some time viewing and reviewing logs, you can start to identify common “rhythms” or patterns, which then make it easier to spot anomalies. The more you learn about them, the more useful logs become for both troubleshooting and for discovering how and why things happen on a system—and that makes the log
command an essential tool for any Apple admin.
About Kandji
The Kandji team is constantly working on solutions to help you deliver great experiences to your users. With powerful and time-saving features such as zero-touch deployment, one-click compliance templates, and plenty more, Kandji has everything you need to manage your Apple fleet in the modern workplace.
See Kandji in Action
Experience Apple device management and security that actually gives you back your time.
See Kandji in Action
Experience Apple device management and security that actually gives you back your time.