构建自定义的Xcode Instruments包,XML反击

他们说:“写不止一个”

不久前,我开始使用自定义Instruments软件包。 去年Apple WWDC 410会议之后,我感到很兴奋,并认为构建某个东西会很棒。 在上一篇文章中,我描述了整体程序包体系结构,开发工作流程中的一些陷阱以及在AppSpector中我们如何构建自定义程序包来跟踪SDK中的流量压缩。 在410会议上,Apple工程师说:在另一张幻灯片上“制造多个仪器”。 所以我想-为什么不呢? Instruments的自定义软件包是实现高度特定的调试流程的理想工具。 每个人都知道一个bug可以忍受多久,因为您不知道发生了什么。 一旦找到“观点”来解决问题,您就快完成了。 解决方法始终是大约10%,而找到正确的视角就是剩下的时间。 在思考软件包的一些想法时,我遇到了CossackLabs [1]的一篇很棒的文章,内容涉及开放跟踪框架及其实现。 可视化应用程序内部连续过程的想法看起来很适合作为一种工具。 这样的过程的完美示例是在不同视图控制器的上下文中执行的任何操作,堆积在队列中的操作或客户端-后端消息交换。 如果我只知道实施将需要32个小时😉

封装架构

让我们从一个基本的方法开始:为了实现类似开放式跟踪的图形,我决定使用看起来最好的图形元素。 开放式跟踪框架处理范围的两个基本概念:正在发生事情的上下文; 范围-范围内的一些活动。 包实现中的作用域具有开始和停止事件,唯一名称以及结果:成功或失败。 与成熟的开放式跟踪框架所建议的相比,此方法大大简化了,但足以用于试验软件包中的图并很有用。 打包方案不是很复杂。 我将不深入介绍第一部分中描述的元素,而我只会讲一些关于图形的特定内容。 您可以在这里浏览:

https://github.com/appspector/Tracer/blob/master/TracerPackage/TracerPackage.instrpkg

我在周末构建原始实现时遇到的第一个问题是,仅在发送stop事件后,图形通道才出现在UI中。 我想从开始事件开始显示它,并用不同的颜色突出显示当前正在运行的跨度。 多亏了参加410次会议的Apple工程师Kacper,我才发现仪器具有一种特殊的结构,称为“开放间隔模板”。 它是一种结构,用于定义开始和结束事件之间包可使用的字段。

图本身用“图”节点描述,其中包含诸如标题和对表的引用之类的字段,以从中获取数据; “ plot-template”结构描述了显示的图形通道。 下面的示例意味着我们将为每个唯一的作用域都有一个单独的通道,它将从作用域名称变量中获取其名称。 “ plot-template”下的最后两个标签描述了车道内的线,颜色将来自“ status-color”,标签来自“ span-name”。

另一个有趣的事情是,“ open-interval-template”只能操作出现在开始模式中的变量。 这完全有道理,因为当您显示开始但未结束的事件时,您的代码无法使用结束模式中的数据。 同样,在表的最后两列中,我们计算行和状态标签的颜色,为此,我们需要知道事件的状态-它是正在运行还是已经完成? 我看到解决此问题的唯一方法是仅检查结束模式中存在的变量。 这就是为什么您在开始和结束模式中看到“ span-name-started”和“ span-name-stopped”变量的原因。 第一个用于在行上绘制跨度名称,第二个用于区分正在运行的跨度和结束跨度。 这是关于自定义程序包的丑陋事情之一,感觉它应该有另一个更优雅的解决方案。

第一次尝试

我很高兴在真实代码上尝试使用示踪剂,因此我开始寻找一个很好的例子。 第一次尝试是AppSpector SDK和消息处理模块。 每条消息的传入和传出都需要经过两个步骤:序列化,打包,压缩和最终发送。 有时,由于诸如网络故障等各种原因,消息可能会在队列中等待。这看起来很合适,因此我插入了示踪剂调用并开始记录期望的图像,就像在开放的示踪手册中有很多重叠的通道一样。 但是实际结果有些不同:

跨度持续时间很重要。 不幸的是,如果您的持续时间跨度为毫秒,并且它们之间的间隔为秒,Instruments会缩放图表,您看到的只是一些绿色的点。 仅缩放允许查看实际跨度:

具有使时间轴非线性的能力绝对是很棒的,因此在跟踪事件之间传递的秒数将比毫秒长的动作占用更少的空间。

运作方式

寻找下一个示例,我决定尝试不久前写的BitBot CI客户端BitBot [2]。 它具有许多用于同步,观察和加载文件的NSOperation。 因此,可视化操作可能会很有趣,再加上队列,它们是范围和跨度的理想选择。 另外,操作可能会正常完成或可以取消,因此跨度状态可能很有用。 问题在于将跟踪器调用放在操作的开始和结束上,我不想手动执行,并且代码混乱,并且很多调试只需要调试。 幸运的是,objective-c是一个非常动态的生态系统,在这里我们需要像KVO这样的运行时和功能。 在使用NSOperation玩了一段时间之后,我最终想到了下一种方法:在队列上旋转“ addOperation”,在NSOperation上“启动”,订阅“​​ isExecuting”和“ isFinished”关键路径,并跟踪操作的开始和停止事件适当的KVO通话。 这次的结果更接近我的预期:

这看起来更有用和方便,尤其是在您的应用程序中有很多操作的情况下。 您所需要做的就是在git repo [3]和通过CocoaPods上可用的package和tracer代码。 只需调用一次“ startTracingOperations”,您就准备就绪。

结论

因此,现在我已经构建了两个软件包,就像苹果公司的建议一样。 您可能会询问是否有任何更改。 并不是的。 我仍然认为自定义包对于构建高度专业的调试工具非常有用,仅在您的项目内部使用。 这样可以节省您大量的时间,对其他人几乎毫无用处。🙂如果您从事中等规模的项目,则可能已经有了一套这样的工具。 乐器包装可以完全适合那里。 另一方面,开发工具仍然是一个难题:几乎没有文档,没有Apple的代码示例,需要手动编写XML(在2019年?),没有人(除Apple以外的人)可以为您提供帮助。 如果这种妥协对您有用,那就去吧。 我正在考虑使用自定义数据建模器构建某些东西,或者甚至使用会话410中未涵盖的功能。但是就目前而言,这个想法看起来很可怕,几乎像是一项反向工程任务。

链接

  1. https://www.cossacklabs.com/blog/how-to-implement-distributed-tracing.html
  2. https://github.com/deszip/BitBot
  3. https://github.com/appspector/Tracer