Crashlytics iOS - Log Caught Exception

Crashlytics iOS - log caught exception

Mike from Crashlytics and Fabric here.

You can now capture logged NSErrors in your iOS, tvOS, or OS X app. You want to use:

[CrashlyticsKit recordError:error];

or

Crashlytics.sharedInstance().recordError(error)

This will let you capture a fair number of logged NSErrors per user session. These are only sent on app relaunch. Logged errors errors are grouped by the error domain and code. This means error issues can span many different call sites.

See Documentation

Flutter Crashlytics log caught exception

Short answer, yes.

Crashlytics.instance.recordError() is the equivalent of Crashlytics.logException()

If you dig into the Flutter firebase_crashlytics source code, you can actually see what Android APIs are involved.

Flutter’s recordError() invokes the method Crashlytics#onError in the Android library.

And tracing Crashlytics#onError, you’ll see that it goes to Crashlytics.logException(exception);

Additional note, you’ll also notice why Crashlytics.instance.log() ”will only add logs to the next crash report”. These logs are added to a ListQueue<String> _logs which is then packaged into the next call of recordError()

A snippet of Flutter’s invocation of Crashlytics.logException():

_recordError(...) {
...
final String result = await channel
.invokeMethod<String>('Crashlytics#onError', <String, dynamic>{
'exception': "${exception.toString()}",
'context': '$context',
'information': _information,
'stackTraceElements': stackTraceElements,
'logs': _logs.toList(),
'keys': _prepareKeys(),
});
}

And some reference notes for Crashlytics.logException():

To reduce your users’ network traffic, Crashlytics batches logged
exceptions together and sends them the next time the app launches.

For any individual app session, only the most recent 8 logged
exceptions are stored.

Does firebase_crashlytics work when using try / catch in flutter?

I think solution are

  • Crashlytics.instance.log for log Single message, string.
  • Crashlytics.instance.recordError for log message error with stackTrace.
  • Crashlytics.instance.recordFlutterError for log message is generated by flutter framework

How to find the exact exception that's being occured or the root cause from the crash logs ios

Unrelated, but in Swift, there is no need for ; at the end of the lines.

Let's read the crash log:

2   watch Extension                 0x04488074 closure #1 in OtpView.fetchProfile() + 1232 (OtpView.swift:203)
3 watch Extension 0x0443c47c specialized closure #1 in closure #1 in useInteceptor(urlString:method:requestBody:completionHandler:) + 1120 (Inteceptor.swift:0)
4 watch Extension 0x0443dc80 partial apply for specialized closure #1 in closure #1 in useInteceptor(urlString:method:requestBody:completionHandler:) + 72 (<compiler-generated>:0)

That's the interesting part (the top ones with names of methods), you read them from the bottom.

So in Interceptor.swift, method useInteceptor(urlString:method:requestBody:completionHandler:) is called at some point.

In this one, there is a closure (or multiple ones), but at least, in the first one (closure #1), which is completionHandler, that you call in fetchProfile of OptView class in OptView.swift file.

And there, in line 203, it's the line causing the crash.

Let's analyze the culprit:

let profile = try! JSONDecoder().decode(ProfileResponse.self, from: data)

Here, the possible crash is because of try!.

Why did you use try! instead of writing a do/try/catch? Do you know why you used a force unwrap ! here? What it means?

It means that if an error is thrown, just make the app crash.

So if there is a crash, it's expected behavior, since you explicitly wrote "crash here if there is thrown error".

So, now, why would decode(_:from:) crash?

I don't know what's ProfileResponse, but that method could throw an error because you didn't specify to it that a value in the JSON can be nul, a value in the JSON can be omitted, because there is another issue with the received JSON, or JSON is invalid.

Or, because your API is giving a bad value. It's sometimes the cases when API encounters an error, they could responds: {"error": "some reason why it failed"}. It's a valid JSON, but I don't think that ProfileResponse expect to be like that.

Now, as why it giving bad response, it's up to your Web API, check the doc, check the API developers for possible responses: Did you use bad parameters, are you falling into the one case not handled by back-end?

So when you wrote that line with the try!, you decided to tell: "Don't worry about the response, if there is a response, I'm sure of it that it can be decoded into a ProfileResponse object. Trust me, I know what I'm doing, I guarantee it will be always valid, and if that's not the case, just crash, that would prove me wrong, but rest assured, I'm sure of myself". Yes, that what meant try!.

If you don't want to crash, don't use !, and write a property do/try/catch.

do {
let profile = try JSONDecoder().decode(ProfileResponse.self, from: data)
if let ratePlanDetails = profile.response?.detail {
self.navigateToNext.toggle()
}
} catch {
print("Oops, there was an error while decoding ProfileResponse: \(error)")
print("And the API response was: \(String(data: data, encoding: .utf8) ?? "unknown data")")
}

Now, as to why you have an invalid response, that's up to your debugging: trying to reproduce it, with specific params, specific case, etc.). We can't guess what's wrong, we can't guess what's returning the API.
Once you know what's the real response sent back by your API, and don't know how to handle it, you can ask a new question on SO and we might help you, but at this point, we can't do anything more about your issue.



Related Topics



Leave a reply



Submit