Xcode 日志存储在扩展名为.xcactivitylog
。 文件内容是经过一种 SLF
的编码格式进行压缩过的。可以通过gzip -cd 展开。在Logs/Build下有一个LogStoreManifest.plist文件,终端plutil -p 打开,里面会有很多字段,其中timeStartedRecording 655351382.847489 需要使用timeIntervalSinceReferenceDate方法还原时间戳
SLF 格式
SLF文档的头部以SLF0开始。在header之后,文档有一组编码过的值。SLF编码格式支持以下类型:
- Integer
- Double
- String
- Array
- Class names
- Class instances
- Null
编码的值由 3 部分组成:
- 左侧值(可选)
- 字符类型分隔符
- 右侧值(可选)
Integer
- 字符类型分隔符:
#
- 例子:
200#
- 左侧值:一个无符号的 64 位整数。
Double
- 字符类型分隔符:
^
- 例子:
afd021ebae48c141^
- 左侧值:以十六进制编码的小端浮点数。
可以使用以下bitPattern
属性将其转换为 Swift Double Double
:
guard let value = UInt64(input, radix: 16) else {
return nil
}
let double = Double(bitPattern: value.byteSwapped)
在xcactivitylog
的文件中,这种类型的值用于编码时间戳。因此,double 表示使用 的timeInterval
值timeIntervalSinceReferenceDate
。
Null
- 字符类型分隔符:
-
- 没有左边,也没有右边的值
String
- 字符类型分隔符:
"
- 例子:
5"Hello
- 左侧值:一个Integer,表示字符串的长度
- 右侧值:
String
字符的数量在NSString中有效,但在String中无效,因为它计算字符串的UTF-16表示中的16 bit单元,而不是像在Swift的String中那样计算字符串中的Unicode扩展字符集群的数量。
所以使用 UTF-8 对SLF格式进行字符串加载会记数不匹配,可以通过加载为 ASCII 字符串避免该问题:
let content = String(data: unzippedXcactivitylog, encoding: .ascii)
其他示例: 6"Hello--9#
在这种情况下,有三个编码值:
- 字符串“Hello-”
- Null
- 整数 9。
Array
- 字符类型分隔符:
(
- 例子:
22(
- 左侧值:一个表示数组的元素数量的整数
Array
的节点是Class instances
Class name
- 字符类型分隔符:
%
- 例子:
21%IDEActivityLogSection
- 左侧值:类名字符个数的整数
- 右侧值:
Class name
它遵循与String
相同的规则。
一个给定Class name
只出现一次:在它的第一个Class instance
. 在日志中存储Class名称的顺序很重要,因为Class instance使用该索引
Class instance
- 字符类型分隔符:
@
- 例子:
2@
- 左侧值:具有类实例类型的类名索引的整数。
在上述的2@
情况下,意味着Class instance的类型是在SLF文档中第3个位置找到的Class name。
Tokenizing .xcactivitylog
使用这些规则,可以解码日志并将其标记化。例如:
SLF010#21%IDEActivityLogSection1@0#39"Xcode.IDEActivityLogDomainType.BuildLog20"Build XCLogParserApp20"Build XCLogParserApp0074f8eaae48c141^8f19bcf4ae48c141^12(1@1#50"Xcode.IDEActivityLogDomainType.XCBuild.Preparation13"Prepare build13"Prepare build
可以获得这些token:
[type: "int", value: 10],
[type: "className", name: "IDEActivityLogSection"],
[type: "classInstance", className: "IDEActivityLogSection"],
[type: "int", value: 0],
[type: "string", value: "Xcode.IDEActivityLogDomainType.BuildLog"],
[type: "string", value: "Build XCLogParserApp"],
[type: "string", value: "Build XCLogParserApp"],
[type: "double", value: 580158292.767495],
[type: "double", value: 580158295.086277],
[type: "array", count: 12],
[type: "classInstance", className: "IDEActivityLogSection"],
[type: "string", value: "Xcode.IDEActivityLogDomainType.XCBuild.Preparation"],
[type: "string", value: "Prepare build"],
[type: "string", value: "Prepare build"],
第一个整数是所用SLF
格式的版本。在 Xcode 10.x 和 11 Beta 中,version 为 10。version 后面的值是日志的实际内容。