Logging
有效地将日志消息捕获到内存和磁盘。管理日志行为和持久性。
Framework
- os
On This Page
- Overview
- Topics
- See Also
Overview
统一日志系统提供了一个单一的、高效的、高性能的API,用于捕获跨系统所有级别的消息传递。这个统一的系统将日志数据集中存储在内存和磁盘上的数据存储中。系统实现控制日志行为和持久性的全局设置,同时通过日志命令行工具和使用定制日志配置文件在调试期间提供细粒度控制。使用/Applications/Utilities/中的控制台应用程序和Log命令行工具可以查看日志消息。集成了日志记录和活动跟踪,使问题诊断更容易。如果在日志记录时使用活动跟踪,则会自动关联相关消息。
Important
统一日志可以在iOS 10.0及以后版本、macOS 10.12及以后版本、tvOS 10.0及以后版本、watchOS 3.0及以后版本中使用,并取代了ASL (Apple System Logger)和Syslog api。以前,日志消息被写到磁盘上的特定位置,比如/etc/system.log。统一日志系统将消息存储在内存和数据存储中,而不是写入基于文本的日志文件。
Log Levels
统一日志系统使用了几个日志级别,它们对应于应用程序可能需要捕获的不同类型的消息,并定义消息何时保存到数据存储中,以及消息保存多长时间。系统为每个级别实现标准行为。可以使用日志命令行工具或自定义配置文件覆盖此行为(请参阅调试时自定义日志行为)。
default
默认级别的消息最初存储在内存缓冲区中。在不更改配置的情况下,它们将被压缩并随着内存缓冲区的填充移动到数据存储区。它们会一直保留到超过存储配额,此时,最古老的消息将被清除。使用此级别捕获可能导致失败的信息。
info
信息级消息最初存储在内存缓冲区中。如果不进行配置更改,则不会将它们移动到数据存储区,并在内存缓冲区填充时清除它们。但是,当发生错误或错误时,它们会在数据存储中捕获。当信息级别的消息被添加到数据存储中时,它们将一直保留在那里,直到超过存储配额,此时,最古老的消息将被清除。使用此级别捕获对故障排除可能有帮助但不是必需的信息。
debug
调试级别的消息只在通过配置更改启用调试日志记录时在内存中捕获。根据配置的持久性设置清除它们。此级别记录的消息包含在开发期间或排除特定问题时可能有用的信息。调试日志记录用于开发环境,而不是发布软件。
error
错误级别的消息总是保存在数据存储中。它们会一直保留到超过存储配额,此时,最古老的消息将被清除。错误级消息用于报告流程级错误。如果存在活动对象,则此级别的日志记录将捕获整个流程链的信息。
fault
故障级消息总是保存在数据存储中。它们会一直保留到超过存储配额,此时,最古老的消息将被清除。故障级消息仅用于捕获系统级或多进程错误。如果存在活动对象,则此级别的日志记录将捕获整个流程链的信息。
Performing Logging
要向日志系统发送消息,请调用os_log函数,并可以选择传递一个日志对象和一个日志级别。提供一个日志对象(默认常量或自定义OSLog对象)和一个表示消息的常量字符串或格式字符串。默认常量导致日志记录按照系统的标准行为进行。自定义日志对象根据特定子系统的日志概要文件中包含的设置导致日志记录的发生。
Listing 1
Logging a default-level message
代码语言:javascript复制os_log("This is a log message.")
Listing 2
Logging an info-level message
代码语言:javascript复制os_log("This is additional info that may be helpful for troubleshooting.", log: OSLog.default, type: .info)
Listing 3
Logging a debug-level message for a specific subsystem
代码语言:javascript复制let customLog = OSLog(subsystem: "com.your_company.your_subsystem_name.plist", category: "your_category_name")
os_log("This is info that may be helpful during development or debugging.", log: customLog, type: .debug)
Important
大于系统最大消息长度的日志消息行在日志系统存储时将被截断。当使用log命令行工具查看活动的实时流时,完整的消息是可见的。但是请记住,流日志数据是一项昂贵的活动。
Privacy
统一日志系统认为动态字符串和复杂的动态对象是私有的,不会自动收集它们。为了确保用户的隐私,建议日志消息严格由静态字符串和数字组成。在需要捕获动态字符串的情况下,可以使用关键字public显式地声明字符串public。例如,%{public}s
.
Formatting Log Messages
要格式化日志消息,请使用标准的NSString或printf格式字符串,如清单4所示。有关格式化规则,请参阅字符串格式说明符。
Listing 4
Logging a message using a format string
代码语言:javascript复制os_log(OS_LOG_DEFAULT, "Downloaded a file. Size: %zd", fileSize);
除了标准格式字符串说明符(如%@和%d)之外,日志系统还支持通过以%{value_type}d格式内联表示值类型来对值进行自定义解码。此外,说明符%。*P可以用来解码任意二进制数据。系统包括许多内置的值类型解码器,如表1所示
Table 1
Builtin value type decoders
Value type | Custom specifier | Example output |
---|---|---|
time_t | %{time_t}d | 2016-01-12 19:41:37 |
timeval | %{timeval}.*P | 2016-01-12 19:41:37.774236 |
timespec | %{timespec}.*P | 2016-01-12 19:41:37.2382382823 |
errno | %{errno}d | Broken pipe |
iec-bytes | %{iec-bytes}d | 2.64 MiB |
bitrate | %{bitrate}d | 123 kbps |
iec-bitrate | %{iec-bitrate}d | 118 Kibps |
uuid_t | %{uuid_t}.*16P %{uuid_t}.*P | 10742E39-0657-41F8-AB99-878C5EC2DCAA |
Viewing Log Messages
使用控制台应用程序或日志命令行工具查看和筛选日志消息。
Customizing Logging Behavior While Debugging
日志记录行为通常由系统控制。但是,在macOS中调试时,可以使用log命令行工具的configargument在以root身份登录时为子系统启用不同的日志级别。参见清单5,它显示了如何为子系统启用调试级日志记录。
Listing 5
Enabling debug-level logging for a subsystem
代码语言:javascript复制$ sudo log config --mode "level:debug" --subsystem com.your_company.your_subsystem_name
使用日志工具的状态参数检查子系统的当前日志级别。参见清单6。
Listing 6
Checking the log level of a subsystem
代码语言:javascript复制$ sudo log config --status --subsystem com.your_company.your_subsystem_name
Mode for 'com.your_company.your_subsystem_name' DEBUG
您还可以通过在/Library/Preferences/ logging /子系统/目录中创建和安装日志配置文件属性列表文件来覆盖特定子系统的日志行为。使用表示子系统的标识符字符串(反向DNS表示法)命名文件。例如,com.your_company.your_subsystem_name.plist。接下来,将一个或多个设置字典添加到文件的顶层。默认选项设置字典为整个子系统定义全局行为设置。类别设置字典为子系统中特定类别的消息定义行为。参见清单7所示。
Listing 7
Top level structure of a logging profile
代码语言:javascript复制<dict>
<key>DEFAULT-OPTIONS</key>
<dict>
<!-- GLOBAL SUBSYSTEM OR PROCESS SETTINGS -->
</dict>
<key>CategoryName</key>
<dict>
<!-- CATEGORY SETTINGS -->
</dict>
</dict>
日志配置文件中的每个设置字典都包含一个Level子字典,其中包含以下设置键:
Key | Description |
---|---|
Enable | Enables a specific log level. |
Persist | Controls whether messages are stored in memory and then saved to the data store, or stored in memory only. |
Enable键和Persist键都接受以下字符串值:
Value | Description |
---|---|
Inherit | Explicitly states that the subsystem or category inherits the behavior of its parent. In the case of a category, the parent is the subsystem. In the case of a subsystem, the parent is the system. |
Default | Only default-level messages are captured. |
Info | Default-level and info-level messages are captured. |
Debug | Default-level, info-level, and debug-level messages are captured. |
清单8显示了一个级别子字典的示例,它支持继承子系统或系统持久性行为的信息级别日志记录。
Listing 8
日志配置文件设置字典中级别子字典的示例
代码语言:javascript复制<key>Level</key>
<dict>
<key>Enable</key>
<string>Info</string>
<key>Persist</key>
<string>Inherit</string>
</dict>
清单9显示了一个完整日志概要文件的示例,它配置了一个子系统来执行信息级日志记录,并在子系统中配置了一个服务器连接类别来执行调试级日志记录。
Listing 9
Example of a complete logging profile
代码语言:javascript复制<dict>
<key>DEFAULT-OPTIONS</key>
<dict>
<key>Level</key>
<dict>
<key>Enable</key>
<string>Info</string>
<key>Persist</key>
<string>Inherit</string>
</dict>
</dict>
<key>server-connections</key>
<dict>
<key>Level</key>
<dict>
<key>Enable</key>
<string>Debug</string>
<key>Persist</key>
<string>Inherit</string>
</dict>
</dict>
</dict>
Note
子系统继承系统的日志记录行为,而类别继承它们所在子系统的行为。因此,只有当设置与继承行为不同时,才需要指定设置。
Logging Best Practices
遵循这些指导原则可以生成有用且有效的日志消息。
尽可能使用格式字符串和说明符自动生成用户友好的日志消息,而不是试图编写自定义格式代码。参见格式化日志消息。
不要在消息中包含符号信息或源文件行号。系统自动捕获这些信息。