作为一名程序,最头疼的莫过于项目上线后收到程序崩溃的通知,若能够在手头重现出该问题,那相对来说项目能够及时的修复并更新;如果无法重现外网崩溃的问题,那就十分的"头疼"了。要是能够实时的采集到项目的崩溃信息,那该多好啊!这并不是一种什么奢望,目前就有现成的技术解决方案。这段时间,我一直在帮项目开发程序崩溃的采集功能,其中用到的技术方案就是 Google 开发的 Breakpad。
Google Breakpad 是 Google 开发的一个跨平台的崩溃采集库。利用这个库可以在 Windows, Mac, Linux, iOS 和 Android 平台上对程序的崩溃进行捕获,并生成 dump 文件供后期分析。也是目前最成熟运用最广的开源库,并且这个库现在依然在更新和维护。
它主要包括三个部分:
image
在默认情况下,当程序崩溃时 breakpad 会生成一个 minidump 文件,它在不同平台上的实现机制不一样,解释如下:
Breakpad 在所有的平台上都使用 minidump 文件格式,minidump 文件格式是由微软开发的用于崩溃上传,它包括:
在 Github 上将 Breakpad 源码下载到本地:https://github.com/google/breakpad。
打开终端,cd 到源码路径,编译源码:
./configure && make
编译之前请先在电脑上通过homebrew安装cmake工具,否则会报错。
找到路径 /breakpad-main/src/tools/mac/dump_syms/dump_syms.xcodeproj,然后通过 Xcode 编译生成 dump_syms。
本文通过在 iOS 平台上集成 Breakpad 来演示崩溃采集,所以这里我们只会去编译供 iOS 应用使用的 .a 库。
找到路径 /breakpad-main/src/client/ios/Breakpad.xcodeproj,然后通过 Xcode 打开它,然后编译成 libBreakpad.a。
好了,到这里我们的准备工作就做好了,接下来就来看看如何去解析崩溃吧!
首先创建一个 iOS App 的测试工程,然后在工程中依赖我们上面编译生成的 libBreakpad.a 库。
然后在 didFinishLaunchingWithOptions 方法里加入
[[BreakpadController sharedInstance] start: YES];
在 applicationWillTerminate 方法时加入
[[BreakpadController sharedInstance] stop];
代码如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[[BreakpadController sharedInstance] start:YES];
return YES;
}
- (void)applicationWillTerminate:(UIApplication *)application{
[[BreakpadController sharedInstance] stop];
}
除了依赖库之外,我们还得在工程中加入一些配置,这也是 Breakpad 所要求的,否则 Breakpad 在初始化的时候就会初始化失败。
打开我们的测试工程的 plist,然后为其加上以下内容:
<key>BreakpadProduct</key>
<string>Google_Notifier_Mac</string>
<key>BreakpadProductDisplay</key>
<string>${PRODUCT_NAME}</string>
<key>BreakpadURL</key>
<string>这里请填入您自己要上传的服务器地址</string>
<key>BreakpadReportInterval</key>
<string>30</string>
这些配置做完了以后,接下来我们就要来模拟一次崩溃啦!这还不容易吗?直接写一个数组越界的逻辑就可以模拟 Crash 啦!
代码如下:
- (IBAction)Triger:(id)sender {
NSArray *array = [[NSArray alloc] initWithObjects:@"1", @"2", @"3", nil];
NSString *value = [array objectAtIndex:8];
}
当我们点击这个按钮事件的时候,就会触发这次崩溃。
Breakpad 在捕获到这次崩溃时,会在我们 App 的 Library/Caches 路径下创建 Breakpad 文件夹,并将生成的 dmp 文件保存在里面,如图:
image
现在有了 dmp 文件,我们暂时还无法去解析它,为什么?因为我们还缺少符号文件去符号化这个 dmp。
那我们去哪里找这个符号文件呢?打包时,iOS App 的符号文件默认情况下都存放在 xcarchive 文件中。
打开 Xcode 的 Window -> Organizer, 然后找到对应的 archive 包,右键 Show in Finder, 文件夹 dSYMs 里即为我们的符号文件。
image
在上面我们已经编译好了 dump_syms 和 minidump_stackwalk ,接下来用这两个工具生成 symbols 文件和堆栈文件。
在你合适的目录中新建一个文件夹,名称按照个人喜好即可,然后将 dump_syms,minidump_stackwalk,dmp 和 .dSYM 文件拖进来。
cd 到该目录,执行如下命令:
$ ./dump_syms -a arm64 TTTT.app.dSYM > TTTT.sym
❝解释下,命令中的架构可以是 armv7, armv7s 等等,主要还是看你的应用是支持的什么架构,像我的这个测试工程,它就只支持 arm64,所以我这边就只生成 arm64 的 Symbols 文件。另外,TTTT.app.dSYM 是我这边打包生成的,需要替换你自己的 .dSYM 文件,然后生成的 .sym 文件,文件名必须与之前的 TTTT 保持一致,否则 dmp 文件就不能符号化。 ❞
查看 TTTT.sym 文件内容,执行如下:
head -n1 TTTT.sym
头部会有
MODULE mac arm64 6DD6178D3EF53F21A61BE8B5D9E294D00 TTTT
这样的字符串。
继续执行命令
mkdir -p symbols/TTTT/6DD6178D3EF53F21A61BE8B5D9E294D00 /
mv TTTT.sym symbols/TTTT/6DD6178D3EF53F21A61BE8B5D9E294D00 /
./minidump_stackwalk xxxx-xxxx-xxxx-xxx.dmp symbols > crashed.log
这样我们就把 dmp 给分析出来了,符号化的数据都保存在 crashed.log 中。
image
根据图上的内容,我们可以发现程序的崩溃发生在 ViewController.m 的第24行。回到我们的测试工程中,发现确实在 24 行,这里发生了数组越界。
image
由此说明,Breakpad 帮助我们找到了程序崩溃的地方,本次实验就成功啦!
好了,本篇教程到此就结束了。总体来说 Breakpad 使用起来并不麻烦,崩溃采集的结果也很准确,相信对很多想把产品做好的公司来说是一把利器。本篇仅是简单的讲解了一下 Google Breakpad 的使用以及 dump 解析,如果真正想把这一块做好的话还需要下一点功夫,譬如说崩溃文件压缩上传,以及服务器崩溃日志解析等工作都需要自动化完成,本篇就不再赘述了,如果你有什么好的 idea,欢迎与我交流。
本文分享自 HelloWorld杰少 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!