原文:OSLog and Unified logging as recommended by Apple

OSLog 作为 printNSLog 的代替计划,是苹果公司引荐的日志记载方法。它有点难写,但与它更知名的朋友相比,它有一些很好的优势。

经过编写一个小的扩展,你能够相当简单地替换你的打印句子。将 Console.app 与你的日志结合起来运用能够协助你以更有效的方法调试问题。OSLog 具有较低的功能开销,并在设备上归档,以便今后检索。这是运用 OSLog 而不是 print 句子的两个长处

初始化 OSLog

OSLog 使日志分类成为或许,这能够用来运用 Console.app 过滤日志。经过定义一个小的扩展,你能够轻松地选用多个类别。

注意:假如你运用的是 iOS 14 及以上版别,有新的 API 可用,在这篇文章的后边有解释。

import os.log
extension OSLog {
    private static var subsystem = Bundle.main.bundleIdentifier!
    /// 记载视图生命周期,如 viewDidLoad。
    static let viewCycle = OSLog(subsystem: subsystem, category: "viewcycle")
}

这个扩展运用使用程序的 Bundle 标识符,为每个类别创建一个静态实例。在这种情况下,咱们有一个视图周期类别,咱们能够用它来登录咱们的使用程序:

override func viewDidLoad() {
    super.viewDidLoad()
    os_log("View did load!", log: OSLog.viewCycle, type: .info)
}

日志等级

OSLog API 要求传入一个 OSLogType,能够用来自动发送恰当等级的音讯。日志类型控制了一个音讯应该被记载的条件,是 Console.app 中另一种过滤方法。

  • default(notice)。默许的日志等级,这其实并不能阐明任何关于日志记载的问题。最好是经过运用其他的日志等级来具体阐明。
  • info(信息)。调用这个函数来捕获或许有协助的信息,但不是有必要的,用于毛病排除。
  • debug(调试)。调试等级的信息是为了在开发环境中活跃调试时运用。
  • error(过错)。过错级信息用于报告关键过错和毛病。
  • fault(毛病)。毛病级音讯仅用于捕获体系级或多进程过错。

你能够传入一个日志等级作为类型参数:

/// We're logging an .error type here as data failed to load.
os_log("Failed loading the data", log: OSLog.data, type: .error)

日志参数

根据日志的隐私等级,能够用两种方法记载参数。私家数据能够用 %{private}@ 来记载,公共数据用 %{public}@ 来记载。

鄙人面的例子中,咱们用公共和私家两种方法来记载用户名,以显现其区别:

override func viewDidLoad() {
    super.viewDidLoad()
    os_log("User %{public}@ logged in", log: OSLog.userFlow, type: .info, username)
    os_log("User %{private}@ logged in", log: OSLog.userFlow, type: .info, username)
}

在衔接调试器时,Xcode 控制台和 Console.app 将正常显现数据:

LogExample[7784:105423] [viewcycle] User Antoine logged in
LogExample[7784:105423] [viewcycle] User Antoine logged in

但是,在没有衔接调试器的情况下翻开使用程序,将在 Console.app 中显现以下输出:

debug   18:58:40.532132 +0100   LogExample  User Antoine logged in
debug   18:58:40.532201 +0100   LogExample  User <private> logged in

用户名被记载为 <private>,而这能够防止你的数据被任何人在日志中读取。

经过 Console.app 读取日志

建议将 Console.app 与 OSLog 结合运用,以取得这种记载方法的最大作用。

首先,在设备菜单的左边挑选你的设备。模拟器和衔接的设备会在这个列表中显现出来。

Apple引荐的OSLog和共同日志体系

Console.app 中的设备菜单

挑选你的设备后,你能够开端在查找字段中输入一个关键词,然后在一个下拉菜单中出现一个选项。 这是你能够对你的类别进行过滤的地方。

Apple引荐的OSLog和共同日志体系

假如这还不够过滤,咱们还能够进一步经过子体系来进行过滤。

Apple引荐的OSLog和共同日志体系

保证勾选包含 info 和 debug 信息,从 Action 菜单中启用它们,这样你的一切信息都会显现出来。

Apple引荐的OSLog和共同日志体系

这应该足以让你开端在 Console.app 内阅览日志:

Apple引荐的OSLog和共同日志体系

保存查找形式

为了使你的作业流程更快,你能够保存你最常用的查找形式。它们终究会出现在副标题中,以便快速过滤掉日志,并有效地开端调试。

Apple引荐的OSLog和共同日志体系

在 iOS 14 及以上版别中改善了 API

WWDC 2020 引入了改善的 API,使其更简单与 OSLog 一起作业。这些 API 看起来与CocoaLumberjack 等盛行结构愈加类似,并与其他 Swift API 更好地保持共同。

本博文中一切以前触及的解释依然适用,代码示例依然在 iOS 14 上作业。但是,假如你支撑iOS 14及以上版别,你或许想运用改善后的API,由于它们看起来更美丽,并带有一些新功能。

运用 Logger 实例

其间一个区别是运用新引入的 Logger 实例。初始化器与 OSLog 中的初始化器共同:

extension Logger {
    private static var subsystem = Bundle.main.bundleIdentifier!
    /// Logs the view cycles like viewDidLoad.
    static let viewCycle = Logger(subsystem: subsystem, category: "viewcycle")
}

在尝试记载信息时,差异是可见的,由于你现在有必要运用 info(_:)debug(_:) 这样的方法:

Logger.viewCycle.info("View did load!")

删除了对静态字符串的约束

一个很大的改善是对字符串插值和字符串字面量的支撑。在旧的 API 中,不或许运用字符串插值,这使得记载数值愈加困难。运用新的API,你能够像你习惯的 print(_:) 句子那样记载:

Logger.viewCycle.debug("User (username) logged in")

设置正确的隐私等级

当我运用旧的 API 时,经常发生我忘记了 %{public}@ 的语法。事实上,我经常用大写的 PUBLIC 写错,比如说。 在新的 API 中,咱们能够利用一个更好的可发现的枚举来设置正确的隐私等级:

Logger.viewCycle.debug("User (username, privacy: .private) logged in")

字符串插值支撑在这里十分有用,由于咱们能够决议每个记载值的隐私等级。

新的对齐 API

在某些情况下,你或许想调整一下你的日志的对齐方法以提高可读性。特别是当你在一行中记载多个值时,使用某些表格格局是很有用的。

例如,下面的日志句子假如在没有任何格局化的情况下打印出来,就不会有很好的对齐方法:

func log(_ person: Person) {
    Logger.statistics.debug("(person.index) (person.name) (person.identifier) (person.age)")
}
/// [statistics] 14 Antoine 8DA690DD-5D97-4B53-897A-C2D98BA0440D 17.442274
/// [statistics] 54 Jaap 31C442DC-BA95-49D3-BB38-E1DD4483E124 99.916344
/// [statistics] 35 Lady 879378DB-FF29-460A-8CA4-B927233A3AA9 93.896309
/// [statistics] 97 Maaike E0A5396E-2B82-4487-86D5-597A108AE36A 9.242964
/// [statistics] 96 Jacobien BC19603E-B078-4DFB-AE36-FD7592FB2E49 59.958466

你能够看到,标识符被直接摆放在名字之后,假如名字的长度不一样,就会导致跳跃式摆放。

咱们能够用 Swift 的新对齐 API 来处理这个问题:

func log(_ person: Person) {
    Logger.statistics.debug("(person.index) (person.name, align: .left(columns: Person.maxNameLength)) (person.identifier)")
}
/// [statistics] 42 Antoine    71C6B472-6D90-45D2-A7B4-AA3B5A0FE10F 17.442274
/// [statistics] 55 Jaap       6991D0A2-D755-4527-9512-EDE0D431F460 99.916344
/// [statistics] 35 Lady       66129DE6-E874-4854-B2E0-00BBDB2A5FBB 93.896309
/// [statistics] 62 Maaike     D1984459-B67A-44BE-AC83-A43E6460C1E1 9.242964
/// [statistics] 83 Jacobien   24CD3087-91C2-4229-A337-B190D69461BA 59.958466

这提高了可读性,能够协助你更简单消化大量的日志。

最后,咱们能够经过运用新的格局化字符串插值方法将年龄格局化为只显现两位小数:

func log(_ person: Person) {
    Logger.statistics.debug("(person.index) (person.name, align: .left(columns: Person.maxNameLength)) (person.identifier) (person.age, format: .fixed(precision: 2))")
}
/// [statistics] 95 Antoine    F205DD9C-C92A-4B48-B27A-CF19C6081EB3 85.33
/// [statistics] 84 Jaap       C55C3F42-5C02-43E0-B416-2E0B7356A964 88.70
/// [statistics] 58 Lady       FD25FB54-51CA-4D6D-805E-547D29D5AE34 38.30
/// [statistics] 69 Maaike     4FDE8D73-ECBF-4015-AE5F-2AED7295D6B2 9.72
/// [statistics] 86 Jacobien   E200351B-920F-4351-9752-212912B42ECB 69.23

更多阅览

WWDC 通常包含专门的日志会议,包含功能日志 API。你能够在这里观看这些会议:

关于更深化的文档,请检查苹果公司关于日志记载的文档

总结

OSLog 是 Swift 中日志记载的未来。它是常用的打印句子的一个很好的代替品,并且有几个长处,比如从控制台使用中读出日志和低功能开销。

假如你想了解更多关于调试的技巧,请检查调试分类页面。假如你有任何其他提示或反馈,请随时联络我或在Twitter上给我发推特。

谢谢!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。