Using os_log and log streaming on iOS
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. |
os_log 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 received 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.