Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash Reports for different build configurations #600

Open
angelinec opened this issue Jan 21, 2025 · 9 comments
Open

Crash Reports for different build configurations #600

angelinec opened this issue Jan 21, 2025 · 9 comments
Labels

Comments

@angelinec
Copy link

Describe the bug

Hi,

So far, KSCrash has been working perfectly fine when using Release build configuration in my app's scheme.

Issue
I'm having an issue in retrieving crash reports when using TestFlight as the build configuration. My TestFlight testers are having crash issues and our testers are unable to view the diagnosis in app.

Note: We extract crash diagnosis from the report and display it as a brief error log in our app. The error was not shown in our error log.

Question
Correct me if I'm wrong but I believe there isn't a way to set app's build configuration in KSCrash. So, is there any way for my app to capture crash reports when using TestFlight build configuration?

Steps to reproduce

  1. Choose TestFlight as the build configuration in the app's scheme
  2. Simulate any app crash
  3. Take note whether or not crash report is being captured

Crash report or stack trace

KSCrash version

2.0.0-rc.8

Operating System

iOS

OS version

iOS 16 and above

Device model

No response

Xcode version

16.1

Additional context

No response

@angelinec angelinec added the bug label Jan 21, 2025
@GLinnik21
Copy link
Collaborator

Hi,
Thanks for the report. I believe the distribution method (TestFlight in this case) should not directly affect KSCrash’s ability to capture crash reports. The issue is more likely related to the build configuration (Debug/Release) and potential manipulations performed on the binary, such as symbol stripping or other optimizations during the build process.

It would also be helpful to understand how KSCrash is integrated into your app. Could you provide more details about your integration setup? Additionally, knowing what type of crash isn’t being captured (e.g., uncaught exceptions, signals, etc.) might help in diagnosing the issue further.

@angelinec
Copy link
Author

Info update: Sorry for the confusion. App was built and archived with a build configuration named Testflight (custom scheme) which I'm not sure if it was duplicated from either Debug or Release scheme.

Say, if the custom scheme was duplicated from Debug scheme, how does it affect the crash reporting? Is there any configuration that I need to enable?

AppDelegate.swift

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        /* Crash Reporting Installation */
        let config = KSCrashConfiguration()
        config.deadlockWatchdogInterval = 0
        config.reportStoreConfiguration.maxReportCount = 5
        config.monitors = .all
        
        do {
            try KSCrash.shared.install(with: config)
        }
        catch {
           /*code*/
        }
        return true
    }

FileA.swift

fileprivate func detectCrashInfo() {
        var crashInfo = String()
        var appVersion = String()
        var buildVersion = String()
        var allCrashReports = [CrashReportDictionary]()
        let kCrashInstallation = KSCrash.shared
        let crashReportFilterJSONEncode = CrashReportFilterJSONEncode()
        
        let crashReportFilterDoctor = CrashReportFilterDoctor()
        
        if let unsentReports = kCrashInstallation.reportStore?.reportIDs {
            if unsentReports.count > 0 {
                for reportID in unsentReports {
                    if let dictionaryReport = kCrashInstallation.reportStore?.report(for: reportID.int64Value) {
                        allCrashReports.append(dictionaryReport)
                    }
                }
            }
            
            crashReportFilterDoctor.filterReports(allCrashReports) { filteredReports, error in
                if filteredReports != nil {
                    for case let (index, report as CrashReportDictionary) in filteredReports!.enumerated() {
                        do {
                            if let crashObject = report.value[CrashField.crash.rawValue] as? NSDictionary {
                                if let diagnosis = crashObject[CrashField.diagnosis.rawValue] {
                                    crashInfo = "\(diagnosis)\n"
                                }
                                else {
                                    if let exceptionName = (crashObject as NSDictionary).value(forKeyPath: "error.mach.exception_name"){
                                       crashInfo = "Exception name - \(exceptionName)\n"
                                    }

                                    if let exceptionReason = (crashObject as NSDictionary).value(forKeyPath: "error.reason") {
                                        crashInfo += "Reason - \(exceptionReason)\n"
                                    }
                                }
                            }
                            
                            if let systemObject = report.value[CrashField.system.rawValue] as? NSDictionary {
                                appVersion = "App Version \(systemObject[CrashField.bundleShortVersion.rawValue] ?? "UNAVAILABLE")(\(systemObject[CrashField.bundleVersion.rawValue] ?? "UNAVAILABLE")) \n"
                                buildVersion += "OS \(systemObject[CrashField.systemVersion.rawValue] ?? "UNAVAILABLE")"
                            }

                            let transaction = Transaction()
                            transaction.perform {
                                try PerformedJournalManager.defaults.insertPerformedJournal(transaction: transaction, action: .crash(errorMessage: "\(crashInfo)\(appVersion)\(buildVersion)"))
                            } completion: { ok in
                                if ok {
                                    kCrashInstallation.reportStore?.deleteReport(with: unsentReports[index].int64Value)
                                }
                            }
                        }
                    }
                }
            }
        }
    }

@GLinnik21
Copy link
Collaborator

The code looks fine, especially since crash reports work in other configurations. The issue likely lies in the custom TestFlight configuration. Check for differences in build settings, such as debug symbols, optimization levels, or compiler flags.

Are all crash reports not being collected, or is it only specific types? What kind of crash was used for testing (e.g., unhandled exceptions, signals like SIGSEGV)?

@ergunkocak
Copy link

@angelinec did you find the issue? I am kinda having a similar issue :)
Same code base, same crash point. Debug build gives mangled symbols but in release i have nothing to demangle :(
I have dwarf with dSYMs and all other settings (i guess :) )
While i am not an expert in crash reporting every feedback is very valuable to me.
Best

@ergunkocak
Copy link

I fixed on my side by :

  • Disable "Strip Linked Product"
  • Disable "Dead code stripping"
    in build settings for release.

I hope it helps another newbie like me :)

PS : Thanks for beautiful library ❤️

@GLinnik21
Copy link
Collaborator

Hi, @ergunkocak!
You’re absolutely right. However, I wouldn’t call this a fix, as developers typically remove debug symbols (which KSCrash uses for internal symbolication) to reduce binary size. Even Apple’s crash reports are originally desymbolicated.

I’d recommend setting up a system to collect shipping crash reports and implementing a pipeline to symbolicate them, following Apple’s guide: Adding Identifiable Symbol Names to a Crash Report. KSCrash’s format largely aligns with Apple’s crash report format.

@ergunkocak
Copy link

Hi @GLinnik21 ,

Thanks for fast reply and insight. I will try disabling internal symbolication and symbolicate on server side.

Thank you, have a lovely day :)

@ergunkocak
Copy link

Not to mislead anyone :) There is no disabling on device symbolication (afais).
But i realised that i need to use the addresses to symbolicate the traces on my server side with correct dSYM files.

@GLinnik21
Copy link
Collaborator

Glad you figured it out! For future questions like this, you might consider posting in the Discussions section (Q&A). It’s currently not very active, but it’s a great place for these kinds of topics and could help keep issues more focused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants