KSCrash

Run Unit Tests CocoaPods Lint

终极崩溃报告器

又一个崩溃报告器?为什么?

因为现有的崩溃报告器虽然可以报告崩溃,但它们本可以做得更多。以下是 KSCrash 的一些关键特性:

KSCrash 处理以下类型的崩溃:

以下是一些它可以生成的报告示例。

请求帮助!

在过去几年里,我的生活发生了很大的变化,我无法继续给予 KSCrash 所需的关爱。

I want you

我正在寻找有人帮助我维护这个软件包,确保问题得到处理,合并得到适当的审查,并保持代码质量。请亲自联系我(kstenerud at my gmail address)或在#313中发表评论

如何安装 KSCrash

Swift Package Manager (SPM)

选项 1:使用 Xcode UI

  1. 在 Xcode 中,转到 File > Add Packages...
  2. 输入:https://github.com/kstenerud/KSCrash.git
  3. 选择所需的版本/分支
  4. 选择你的目标
  5. 点击“Add Package”

选项 2:使用 Package.swift

将以下内容添加到你的 Package.swift 文件中

dependencies: [
    .package(url: "https://github.com/kstenerud/KSCrash.git", .upToNextMajor(from: "2.0.0-rc.8"))
]

然后,将 "Installations" 作为目标的依赖项包含进去

targets: [
    .target(
        name: "YourTarget",
        dependencies: [
            .product(name: "Installations", package: "KSCrash"),
        ]),
]

CocoaPods

  1. 添加到你的 Podfile

    pod 'KSCrash', '~> 2.0.0-rc.8'
  2. 运行

    $ pod install
    
  3. 使用生成的 .xcworkspace 文件。

安装后设置

将以下内容添加到你的 AppDelegate.swift 文件中

导入 KSCrash

对于 Swift Package Manager

import KSCrashInstallations

对于 CocoaPods

import KSCrash

配置 AppDelegate

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        let installation = CrashInstallationStandard.shared
        installation.url = URL(string: "http://put.your.url.here")!

        // Install the crash reporting system
        let config = KSCrashConfiguration()
        config.monitors = [.machException, .signal]
        installation.install(with: config) // set `nil` for default config

        // Optional: Add an alert confirmation (recommended for email installation)
        installation.addConditionalAlert(
            withTitle: "Crash Detected",
            message: "The app crashed last time it was launched. Send a crash report?",
            yesAnswer: "Sure!",
            noAnswer: "No thanks"
        )

        return true
    }
}

其他安装类型

邮件安装
let installation = CrashInstallationEmail.shared
installation.recipients = ["some@email.address"] // Specify recipients for email reports
// Optional: Send Apple-style reports instead of JSON
installation.setReportStyle(.apple, useDefaultFilenameFormat: true)
控制台安装
let installation = CrashInstallationConsole.shared
installation.printAppleFormat = true // Print crash reports in Apple format for testing

发送报告

要发送任何未发送的崩溃报告,请调用

installation.sendAllReports { reports, completed, error in
    // Stuff to do when report sending is complete
}

可选监视器

KSCrash 包含两个可选的监视器模块:BootTimeMonitorDiscSpaceMonitor。默认情况下不包含这些模块,如果需要,必须显式添加。它们包含与隐私相关的 API,需要在使用此信息发送到设备之前向用户显示崩溃报告。

要包含这些模块

如果链接了这些模块,它们会自动运行,无需额外设置。库用户有责任为用户同意实现必要的 UI。

有关更多信息,请参阅 Apple 关于 磁盘空间 API系统启动时间 API 的文档。

可选反符号化

KSCrash 有一个可选模块,它提供 C++ 和 Swift 符号的反符号化:DemangleFilter。此模块包含一个 KSCrash 过滤器 (CrashReportFilterDemangle),可用于在 sendAllReports 调用期间反符号化崩溃报告中的符号(如果此过滤器已添加到过滤器管道中)

如果您使用 Installations API,则会自动使用此模块。 如果您想避免反符号化,可以在 CrashInstallation 实例中将 isDemangleEnabled 设置为 false

如果您不使用 Installations API,您可以手动包含此模块

如果您需要反符号化 C++ 或 Swift 符号,CrashReportFilterDemangle 类也有一个静态 API 供您自己使用。

有什么新东西?

内存溢出崩溃检测

KSCrash 现在包含高级内存跟踪功能,以帮助检测和防止内存溢出崩溃。新的 KSCrashAppMemoryTracker 允许您实时监控应用程序的内存使用情况、压力和状态转换。 此功能可以实现主动内存管理,帮助您避免因过度使用内存而导致的系统启动终止。 有关如何在您的应用中实现此功能的更多详细信息,请查看“高级用法”部分。

C++ 异常处理

没错!通常,如果您的应用程序因未捕获的 C++ 异常而终止,您只会得到这个

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libsystem_kernel.dylib          0x9750ea6a 0x974fa000 + 84586 (__pthread_kill + 10)
1   libsystem_sim_c.dylib           0x04d56578 0x4d0f000 + 292216 (abort + 137)
2   libc++abi.dylib                 0x04ed6f78 0x4ed4000 + 12152 (abort_message + 102)
3   libc++abi.dylib                 0x04ed4a20 0x4ed4000 + 2592 (_ZL17default_terminatev + 29)
4   libobjc.A.dylib                 0x013110d0 0x130b000 + 24784 (_ZL15_objc_terminatev + 109)
5   libc++abi.dylib                 0x04ed4a60 0x4ed4000 + 2656 (_ZL19safe_handler_callerPFvvE + 8)
6   libc++abi.dylib                 0x04ed4ac8 0x4ed4000 + 2760 (_ZSt9terminatev + 18)
7   libc++abi.dylib                 0x04ed5c48 0x4ed4000 + 7240 (__cxa_rethrow + 77)
8   libobjc.A.dylib                 0x01310fb8 0x130b000 + 24504 (objc_exception_rethrow + 42)
9   CoreFoundation                  0x01f2af98 0x1ef9000 + 204696 (CFRunLoopRunSpecific + 360)
...

无法跟踪异常是什么或从哪里抛出的!

现在,使用 KSCrash,您可以获得未捕获的异常类型、描述以及它的抛出位置

Application Specific Information:
*** Terminating app due to uncaught exception 'MyException', reason: 'Something bad happened...'

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   Crash-Tester                    0x0000ad80 0x1000 + 40320 (-[Crasher throwUncaughtCPPException] + 0)
1   Crash-Tester                    0x0000842e 0x1000 + 29742 (__32-[AppDelegate(UI) crashCommands]_block_invoke343 + 78)
2   Crash-Tester                    0x00009523 0x1000 + 34083 (-[CommandEntry executeWithViewController:] + 67)
3   Crash-Tester                    0x00009c0a 0x1000 + 35850 (-[CommandTVC tableView:didSelectRowAtIndexPath:] + 154)
4   UIKit                           0x0016f285 0xb4000 + 766597 (-[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1194)
5   UIKit                           0x0016f4ed 0xb4000 + 767213 (-[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 201)
6   Foundation                      0x00b795b3 0xb6e000 + 46515 (__NSFireDelayedPerform + 380)
7   CoreFoundation                  0x01f45376 0x1efa000 + 308086 (__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22)
8   CoreFoundation                  0x01f44e06 0x1efa000 + 306694 (__CFRunLoopDoTimer + 534)
9   CoreFoundation                  0x01f2ca82 0x1efa000 + 207490 (__CFRunLoopRun + 1810)
10  CoreFoundation                  0x01f2bf44 0x1efa000 + 204612 (CFRunLoopRunSpecific + 276)
...

自定义崩溃 & 堆栈跟踪

您现在可以报告您自己的自定义崩溃和堆栈跟踪(想想脚本语言)

- (void) reportUserException:(NSString*) name
                      reason:(NSString*) reason
                  lineOfCode:(NSString*) lineOfCode
                  stackTrace:(NSArray*) stackTrace
            terminateProgram:(BOOL) terminateProgram;

有关详细信息,请参阅 KSCrash.h。

不稳定功能

以下功能应被视为“不稳定”并且默认禁用

推荐阅读

如果可能,您应该阅读以下头文件,以充分了解 KSCrash 具有哪些功能以及如何使用它们

了解 KSCrash 代码库

KSCrash 被构建成几个模块,分为公共和私有 API

公共 API 模块

  1. 记录: KSCrashRecording - 处理崩溃事件记录。
  2. 报告:
    • 过滤器: KSCrashFilters - 处理崩溃报告。
    • 接收器: KSCrashSinks - 管理报告目的地。
    • 安装: KSCrashInstallations - 为不同的报告场景提供易于使用的设置。

可选模块

私有 API 模块

用户应该与公共 API 模块交互,而私有模块处理内部操作。 可以根据需要包含可选模块以获得额外的功能。

另请参见此处的快速代码之旅 here

高级用法

启用设备端符号化

设备端符号化要求最终版本中存在基本符号。 要启用此功能,请转到您的应用程序的构建设置,并将Strip Style设置为Debugging Symbols。 这样做会使您的最终二进制文件大小增加大约 5%,但您会获得设备端符号化。

启用高级功能

KSCrash 具有高级功能,在检查实际崩溃报告时非常有用。 有些涉及较小的权衡,因此默认情况下禁用大多数这些功能。

自定义用户数据(KSCrash.h 中的 userInfo)

您可以通过设置 KSCrash.h 中的 userInfo 属性来将自定义用户数据存储到下一个崩溃报告中。

僵尸对象跟踪(KSCrashMonitorType.h 中的 KSCrashMonitorTypeZombie)

KSCrash 能够检测僵尸实例(指向已释放对象的悬空指针)。 它通过记录任何被释放的对象的地址和类来实现这一点。 它将这些值存储在缓存中,并以已释放对象的地址为键。 这意味着您设置的缓存大小越小,发生哈希冲突的可能性就越大,并且您会丢失有关先前已释放对象的信息。

启用僵尸对象跟踪后,KSCrash 还会检测到丢失的 NSException 并打印其内容。 某些类型的内存损坏或堆栈损坏崩溃可能会导致异常过早释放,从而进一步阻碍调试应用程序的工作,因此此功能有时会非常方便。

权衡:以在对象释放中增加非常小的开销以及保留一些内存为代价来跟踪僵尸对象。

死锁检测(KSCrashMonitorType.h 中的 KSCrashMonitorTypeMainThreadDeadlock)

警告 警告 警告 警告 警告 警告 警告

此功能不稳定!它可能会误报并使您的应用程序崩溃!

如果您的主线程死锁,您的用户界面将变得无响应,并且用户将不得不手动关闭应用程序(这将没有崩溃报告)。 启用死锁检测后,将设置一个看门狗定时器。 如果有任何东西将主线程保持的时间超过看门狗定时器持续时间,KSCrash 将关闭该应用程序,并为您提供一个堆栈跟踪,显示当时主线程正在做什么。

这很棒,但您必须小心:App 初始化通常发生在主线程上。如果您的初始化代码花费的时间超过了看门狗定时器,您的应用将在启动期间被强制关闭! 如果您启用此功能,您必须确保您的任何正常运行代码都不会占用主线程的时间超过看门狗的值! 同时,您需要将定时器设置为足够低的值,以防止用户变得不耐烦并在看门狗触发之前手动关闭应用!

权衡:死锁检测,但您必须更加小心在主线程上运行的内容!

内存自省(introspectMemory 在 KSCrash.h 中)

当应用程序崩溃时,内存中通常存在被堆栈、寄存器甚至异常消息引用的对象和字符串。 启用后,KSCrash 将自省这些内存区域,并将它们的内容存储在崩溃报告中。

您还可以通过在 KSCrash 中设置 doNotIntrospectClasses 属性来指定不应自省的类列表。

自定义崩溃处理代码(onCrash 在 KSCrash.h 中)

如果您想在发生崩溃后进行一些额外的处理(可能向报告添加更多上下文数据),您可以这样做。

但是,您必须确保仅使用异步安全的代码,并且最重要的是永远不要从该方法中调用 Objective-C 代码! 在许多情况下,您可以侥幸这样做,但对于某些类型的崩溃,无视此警告的处理程序代码将导致崩溃处理程序崩溃! 请注意,如果发生这种情况,KSCrash 将检测到它并写入一份完整的报告,但您的自定义处理程序代码可能无法完全运行。

权衡:自定义崩溃处理代码,但您必须小心放入其中的内容!

KSCrash 日志重定向

这会将 KSCrash 本来要打印到控制台的内容,转而写入文件。 我主要使用它来调试 KSCrash 本身,但它可能对其他目的有用,因此我公开了一个 API 用于此目的。

内存不足崩溃检测 (KSCrashAppMemoryTracker)

KSCrash 现在包含了高级内存跟踪功能,以帮助检测和防止内存不足崩溃。KSCrashAppMemoryTracker 类监控您 App 的内存使用情况、压力和状态转换。它提供了内存状况的实时更新,允许您动态地响应不同的内存状态(正常、警告、紧急、关键、终端)。通过实现 KSCrashAppMemoryTrackerDelegate 协议,您可以接收关于内存变化的通知,并采取适当的措施来减少内存使用,从而有可能避免系统因内存压力而发起的终止。

使用此功能

let memoryTracker = AppMemoryTracker()
memoryTracker.delegate = self
memoryTracker.start()

在你的代理方法中

func appMemoryTracker(_ tracker: AppMemoryTracker, memory: AppMemory, changed changes: AppMemoryTrackerChangeType) {
    if changes.contains(.level) {
        // Respond to memory level changes
    }
}

此功能帮助你在你的应用中实现主动的内存管理策略。

许可

版权所有 (c) 2012 Karl Stenerud

特此授予任何获得本软件及其相关文档文件(“软件”)副本的人员免费许可,以不受限制地处理本软件,包括但不限于使用、复制、修改、合并、出版、分发、再许可和/或销售软件副本的权利,并允许向其提供本软件的人员这样做,但须符合以下条件

上述版权声明和本许可声明应包含在任何重新分发模板文件本身的文件中(但不包含在使用模板构建的项目中)。

本软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于适销性、特定用途适用性和不侵权的保证。 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是在合同、侵权行为或其他方面,由软件或软件的使用或其他处理引起的或与之相关的。