This may be an old question, and there may be recommendations against rolling your own solution, but for those who prefer to write their own solution, I wanted to share mine.
To write your own crash reporter you need to capture signals and exceptions. To capture signals, use a handler in this format:
signal(SIGINT) { _ in
var threadStackTrace = ""
_ = Thread.callStackSymbols.map({ threadStackTrace.append("\($0)\n") })
}
This will build a string representing the lines of a stack trace. SIGINT
is just one of the signals that you need to capture. There are 14 other signals that I capture in my crash reporter. You'll need a separate handler for each signal. Here are a few other signals I capture: EXC_BREAKPOINT, EXC_CRASH, EXC_BAD_ACCESS, EXC_BAD_INSTRUCTION, SIGABRT, SIGKILL, SIGTRAP, SIGBUS, SIGSEGV, SIGHUP, SIGTERM, SIGILL, SIGFPE, SIGPIPE
. There may be others that should be handled. In Xcode, 'Jump to Definition' to see other signals.
You also need to capture uncaught exceptions. You can do that with:
NSSetUncaughtExceptionHandler { (exception: NSException) in
var exceptionStackTrace = ""
exceptionStackTrace.append("\(exception.name)")
exceptionStackTrace.append("\n\n")
exceptionStackTrace.append("\(exception.reason ?? "")")
exceptionStackTrace.append("\n\n")
_ = exception.callStackSymbols.map({ exceptionStackTrace.append("\($0)\n") })
}
The exception.name
will give you a name such as NSInvalidArgumentException
. The exception.reason
will explain the error. Then, exception.callStackSymbols
is a collection of stack lines. Unlike with signals, you only need one uncaught exception handler.
Then, you can transport your signal or uncaught exception error string via HTTP to your web server:
let request = NSMutableURLRequest(url: ENDPOINT!)
request.httpMethod = "POST"
let body = parameters.data(using: String.Encoding.utf8)
request.httpBody = body
let task = URLSession.shared.dataTask(with: request as URLRequest)
task.resume()
RunLoop.current.run(until: Date.init(timeIntervalSinceNow: 3))
Finally, encapsulate all the signal handlers and uncaught exception handler in a class and call it once at didFinishLaunchingWithOptions
.
The crash report you receive may contain lines that are unsymbolicated and unreadable. Other solutions in the market will upload the .dSYM file so that the crash report can be symbolicated on the server and method names will appear in the crash report. I don't currently have my own solution for this but often the crash report received can contain usual information, enough to identify the problem. I keep my solution as a Swift Package on GitHub at https://github.com/MerchV/iOSCrashReporter