统一日志记录和活动跟踪

去年,苹果对所有更新平台(iOS 10,watchOS 3,tvOS 10,macOS 10.12)的日志记录系统进行了重大更改:现在,将旧的ASL和Syslog API重定向到了新的统一日志记录,从而大大改善了活动跟踪。 这是一个关于我如何采用它们来调试用Swift3编写的极其异步的watchOS3 / iOS10应用程序的故事。

为什么要进行统一日志记录?

认识Fox:具有watchOS3扩展功能的iOS10应用。 Fox正在通过Apple Watch的加速度计跟踪用户的运动活动,将原始数据传输到手机,然后传输到服务器以进行进一步的大数据分析。 棘手的事情是:用户参加医学研究并且他的生活非常艰苦,因此Fox不应在白天打扰他,它应该在后台运行并以静默方式收集数据。

至于watchOS3,watchapps主要被视为前台应用程序,后台执行仅用于更新UI。 对于Dock中的应用程序,每小时可以获得一次后台执行时间;对于在当前表盘上拥有活动Complication的应用程序,则可以获得每小时两次的后台执行时间。

在每个后台任务中,Fox应该从运动传感器请求加速度计数据(这是异步完成的),将其写入文件,放置到传输队列中,等到将其传输到iPhone并获得传输成功无误的响应。 另外,我们希望通过在N个并发操作中运行此请求数据文件传输响应来提高性能。 我们希望日志能够调试整个事情。

像大多数iOS项目一样,第一动力是使用像Crashlytics或Cocoalumberjack这样的流行的第三方框架。

令人失望的是:Crashlytics仍然缺乏watchOS支持,并且想像一下我在Cocoalumberjack的普通文本日志中看到的一团糟,当时四个线程和许多回调开始同时将消息推送到文件末尾。

另一个问题是观察者效应 :通过Cocoalumberjack编写的每条消息都占用了CPU时间,更改了整个算法的时间,并且在后台任务期间处理的数据量更少。 watchOS3具有斯巴达式的限制:如果您的上一个后台任务花费的时间太长或占用了过多的CPU,则OS不会为您提供后台执行时间。 这种伐木造成的危害大于利润。

因此,我需要快速的日志记录系统,适合异步代码,并具有不受欢迎的Apple平台支持。 我已经决定从根本上尝试原生的统一日志记录和活动跟踪。

记录中

功能,如WWDC会话721中所述:

  1. 分类和过滤 :每条消息都有子系统,类别,四个级别之一(默认,信息,调试,故障,错误),已启用标志和目标(磁盘或内存)。
  2. 隐私 :通过用字替换动态字符串,集合和数组,防止将个人身份信息意外泄漏到存储的日志中。 可以在每个参数的基础上覆盖此行为。
  3. 可用性 :日志记录系统为您收集呼叫者信息,内置类型说明符可简化消息准备。
  4. 性能 :观察者影响最小。 数据存储在/ var / db / diagnostics /中的二进制.tracev3文件中,并以.logarchive文件传输(两种文件格式都可以使用macOS Sierra中更新的Console.app打开)。 整个系统的日志被写入一个位置。

尽管在WWDC会话幻灯片中描述了许多C函数,但在Swift中的用法却非常简单:一个os_log函数以静态字符串 (在编译时称为)接受消息,并带有占位符作为参数,参数本身, OSLog(如果要使用非参数) -default子系统和类别,以及用于日志级别的枚举 。 仅消息字符串是必需的:

  func os_log(_消息:StaticString, 
dso:UnsafeRawPointer? = #dsohandle,
日志:OSLog =默认值,
类型:OSLogType =默认值,
_ args:CVarArg…)

除了通常的格式说明符(Objective-C开发人员熟悉)之外,消息的StaticString可以包括其他格式设置

隐私是逐个参数地处理的:标量和静态字符串被假定为公共,而动态字符串,集合和对象被假定为私有。 可以按每个参数覆盖此行为:

  “%{public} @”或“%{private} d”或“%{public,uuid_t} .16P” 

例:

屏幕的上半部分显示“ 活动”树-将所有已执行的代码组合在一起,而不管在什么队列和什么进程上。 活动具有树状层次结构。

例如,在上面的Fox的日志屏幕截图中,您可以看到:

  1. 处理任务活动(在watchapp获得后台任务执行机会时开始)
  2. 这将启动“ 重新安排”活动(安排下一个后台任务)
  3. 谁开始并发执行四个任务 (谁定义了他们要从运动传感器获取的数据参数)
  4. 每个启动Get Data活动(异步地从CoreMotion请求数据并等待回调
  5. 如果成功发送消息以唤醒iOS对应应用程序,则获取回调
  6. 然后在文件中发送数据并在到达时获取回调

异步。 码。 用。 打。 的。 回调。

屏幕底部显示了选定活动内的所有日志消息。 请注意,不仅显示了Fox的消息,而且还显示了从我的代码调用的所有Apple框架( FoundationWatchKit等)以及工作中涉及的所有其他过程( locationCarousel等)。

凉? 这个系统让我着迷。 可悲的是,Swift3(截至2017年1月)没有集成活动跟踪,因此您必须使用包装器。 感谢Zach Waldowski,我们提供了一个轻巧且易于使用的工具:

使用Zach Waldowski的Swift3包装器进行分层活动的活动跟踪示例

如何分析

可以使用新的Console.app(在macOS Sierra中更新)打开统一日志的日志,因为它们是以二进制格式编写的。 如果将iPhone连接到Mac并运行控制台,则可以看到整个系统的实时控制台输出,包括所有已配对和已连接的手表。

为了从Apple Watch或iPhone中注销,您应该使用Apple的sysdiagnose工具。 它在“个人档案和日志”页面上有很好的说明。 长话短说:您必须在要从中获取日志的所有设备上安装特殊配置文件,重现问题,通过按和弦来触发系统诊断,将设备与计算机同步以及在特殊文件夹中找到整个系统诊断报告。 据我了解,日志不再可以从代码中读取。