How can I save the fatalError message to the iOS crash log?
Asked Answered
C

3

28

I have an iOS application written in Swift 2 in Xcode 8.2.1, that's built for iOS 10.2.

I've had a number of crash reports from TestFlight and despite symbolication, none of the crash logs show any program state besides the stack-traces (no argument values, no locals, no heap objects, etc).

...but inside those functions I can see code which is likely to fail (e.g. a forced unwrap) but the crash log isn't telling me where or why it's failing.

When debugging in Xcode, I can use fatalError(message: String) where I can put my own message like "functionFoo returned nil" or "variable bar == \"" + bar + "\"", except when deployed using TestFlight or the App Store the fatalError will be hit and the program terminates, but the message value is not saved to the crash log, making it pointless.

In other environments, like C#/.NET and Java I can simply throw new SomeExceptionType("my message") and all information is available in whatever global catch(Exception) handler I have.

How can I achieve the same goal in iOS / Swift?

Committal answered 20/2, 2017 at 4:28 Comment(3)
Did you ever find a way?Wentworth
About 3 years later still the same problem and no solution :-( Seems like we need to use 3rd party error reporting solutionsBacillus
Good question, but no answer to it? :)Landside
C
-1

Maybe this can help you

import os

let osLogger = Logger(subsystem: yourBundleIdentifier, category: yourCategory)
osLogger.log(level: .debug, "\(yourCategoryName): \(message)")
Carnify answered 6/3 at 10:35 Comment(0)
P
-1

I can suggest two approaches:

  1. Use a third party SDK for tracking crashes, such as Crashlytics (Firebase) or Sentry. You can also send a custom error to these platforms. Also they provide great statistics for all crashes/errors inside your app.

  2. This one is more for a debug configuration (suitable for QA testing). Write a class for logging your event into a file inside of your documents directory. Create a simple ViewController that can open/export this file (DEBUG mode only). Cover all essential places in your code with logs and deliver the build to your QA, so they can attach a detailed steps for reproducing error.

Pinette answered 10/6 at 11:47 Comment(4)
...how do either of these suggestions help me to get the fatalError argument string?Committal
You don't need the fatalError at all, I am suggesting you a better approachPinette
Then your answer isn't helpful because it doesn't actually answer my question. With respect, you don't know that I don't need the fatalError message or not.Committal
You won't be able to get crash report with fatalError for your TestFlight builds. That's how crash report works in iOS. You mentioned an example in C#, that will work in Swift if your function marked as 'throwable' and exception is not handled. Perhaps, if you can share a code sample, i would be able to find more suitable solution.Pinette
W
-3

Swift does support error handling. You can create your own error type by confirming to Error protocol or use existing error types and then throw an error by invoking throw error.

But Swift forces you add error handling to any code that can throw an error. There are multiple way you can handle error in swift.

  1. Apply throws keyword to your function, this indicates that the function can throw an error when invoked and the error should be handled by the caller.

    func canThrowErrors() throws -> String
    
  2. When invoking methods with throws keyword you have to add try keyword at the beginning of the invocation. All these try invocations should be handled either by applying throws to method to just propagate the errors or wrapping inside a do-catch block:

    do {
        try canThrowErrors()
        try canThrowOtherErrors()
    } catch is SpecificError {
        // handling only specific error type
    } catch let error as SpecificError {
        // catches only specific error for type
    } catch {
        // catches all errors
    }
    
  3. Additionally you can use try? and try! for throwing function invocation to disable error propagation and retrieve optional result that returns nil in case of error and runtime assertions respectively.

By forcing you to handle all the errors at compile time swift avoids any undefined runtime behavior and debugging nightmare.

I would suggest to use fatalError or any other runtime assertion only if scenarios when there is no way to recover from a state without crashing the app. Unfortunately, there is no way to handle errors from fatalError as its use is only reserved for such scenarios only. Also, in your crashlog you will only get the line number that caused the crash to get additional info for the cause of crash I would suggest to use custom logging or analytics.

Wiggly answered 15/9, 2022 at 8:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.