Guide to os_log and log streaming

Terminology

Term Description
Log Level A log level is essentially a "score" or "severity" for the message that is being generated. Log levels enable filtering by severity, and come with some special consideration for os_log that helps with performance. In general, you can simply use the log levels as they appear to make sense and you'll likely get very performant behavior.
Log Subsystem A subsystem is an identifier for a specific area of your app, and can be configured as is reasonable to your particular architecture. These should be specified in reverse DNS notation, following your apps bundle identifier as an example. For example, if my bundle identifier was com.example.my-cool-app then a log subsystem for my networking requests might be named com.example.networking .
Log Category Within a subsystem, log categories provide additional granularity and filtering. Following our previous example, some categories we might choose for networking could be: Internal and External , or something that further categorizes a subset of behavior.

Log Level Hierarchy

Each level includes the levels below itself, so setting "debug" will include all logs, while "default" would only include itself, error and fault levels.

debug
info
default - When no settings are changed, only these and below show up outside of Xcode
error
fault

Examples of each of these levels in our networking example could be:

Level Examples
Debug Connection information, Configuration Output, Etc.
Info Request/Response timing
Default A request started, a request finished
Error An error response was receieved from the server
Fault A malformed response was received, or JSON decoding failed and the app may be about to crash

Debugging errors by log level

To catch calls to error or fault login and open the debugger, set a symbolic breakpoint on these symbols:

_os_log_fault_impl _os_log_error_impl

Getting the current logging configuration

# For the whole logging system
xcrun simctl spawn booted log config --status

# For a specific subsystem
xcrun simctl spawn booted log config --status --subsystem net.davelyon.oslog

# For a specific subsystem and category
xcrun simctl spawn booted log config --status --subsystem net.davelyon.oslog --category network

Setting the logging configuration

"Level" is the level that is enabled and stored in memory "Persist" is the level of logs that are both stored in memory and forwarded to the file backed store

# Set the level for the whole logging system

xcrun simctl spawn booted log config --mode "level:debug" 
xcrun simctl spawn booted log config --mode "persist:debug"

# Set the level for a specific subsystem
xcrun simctl spawn booted log config --mode "level:debug" --subsystem net.davelyon.oslog
xcrun simctl spawn booted log config --mode "persist:debug" --subsystem net.davelyon.oslog

# Set the level for a specific subsystem and category
xcrun simctl spawn booted log config --mode "level:debug" --subsystem net.davelyon.oslog --category network
xcrun simctl spawn booted log config --mode "persist:debug" --subsystem net.davelyon.oslog --category network

Viewing logs in Xcode

By default, when the debugger is attached all logs are streamed within Xcode.

Viewing logs in Console.app

If you open Console.app, you should see your simulator(s) in the list of sources. You can then apply filtering to focus on the specific subsystems you want to see.

If you don't see info level logs, check the Action menu, and make sure Include Info Messages is enabled.

If you don't see debug level logs, that's because the "system" log level is set to info and can't be changed, so you're only able to see them by specifically using log stream.

Streaming logs from the simulator to Terminal

You can manage the log level, as well as use the log command line tool within the simulator, including streaming logs from any running simulator, filtering for any specific subsystem you might want to focus on.

To stream logs for a specific subsystem you've created within your app, you can use log as follows:

xcrun simctl spawn booted log stream\
 --level debug\
 --style syslog\
 --color none\
 --predicate 'subsystem contains "net.davelyon"'

Replace "net.davelyon" with your own log subsystem name. Note that it's not the entire name, which does a partial match and lets other similarly named subsystems come through as well. You can be more specific if you only want one of your own subsystems.

See man log for more options on how to filter with predicates.


There's more to read!

Did this help solve your problem? If so, consider letting us know on Twitter. You should follow us for all the latest articles and updates:


Have you seen our latest project on Github?.

Sign up for our newsletter

Get an email when new content comes out! Emails are not sold and are used only for announcing updates to the site. Expect ~1-2 emails per month. Unsubscribe any time.