How to add new events on the existing app for Answers(Fabric)
I did manage to add in the code part, but its not reflecting the Fabric dashboard.
if you want to throw a fatal exception then use this.
public static void throwFatalException(Throwable throwable) {
if (Fabric.isInitialized()) {
Crashlytics.logException(throwable);
}
}
call method
throwFatalException(new Throwable(" My Message " + e));
Note: FatalException will not appear in the Dashboard instantly. it will take some time.
Related
I want to save the logs generated by my application locally on the android device and view them in an instance of a crash.
Using the "Take Bug Report" under the developer options gives the entire system logs which are irrelevant to me. I am looking only for those logs created by my application when it runs.
Is there any application that does this? Or are there any libraries I could include in my application code to satisfy my requirement?
You may just add firebase to your project, and everything will be done automatically.
Or if need it to be "locally", can use the Thread.UncaughtExceptionHandler to save crash log. Register it when your application onCreate.
private static UncaughtExceptionHandler mDefaultUncaughtExceptionHandler;
public static void registerUncaughtExceptionHandler() {
mDefaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable ex) {
// Save Log
saveLog(ex);
// Throw system
mDefaultUncaughtExceptionHandler.uncaughtException(thread, ex);
}
});
}
private static void saveLog(Throwable exception) {
try {
String stackTrace = Log.getStackTraceString(exception);
// Save it to SharedPreferences or DB as you like
} catch (Exception e) {
}
}
Then can extract the last crash log, submit to your server or display in logcat when app starts.
It is much better to use Third Party libraries such as Firebase Crashlytics or Sentry Crash Report or AppMetrica for crash reports.
just add these libraries and make an account on one of these sites, then you can have a full report of crashes if happen.
but if you want to save the logs on the device, you can refer to this question :
Saving Logcat to a text file in Android Device
You can try this
fun writeLog(context: Context) {
try {
val path = File(context.filesDir, "log_files")
if (!path.exists()) {
path.mkdir()
}
val fileName = "your_filename.txt"
Runtime.getRuntime().exec("logcat -v time -f $fileName")
} catch (e: IOException) {
}
}
Or you can change logcat command based on your requirements: refer to this https://developer.android.com/studio/command-line/logcat
You can check it at data/data/{applicationId}/files/log_files/
We are using Crashlytics in our app as the crash reporting tool.
For Android native crashes, it's working fine and grouping the crashes correctly.
Our app also has few components in react-native. For the crashes which occur in these components, we catch them and then log them to Crashlytics as non-fatal exceptions.
public class PlatformNativeModuleCallExceptionhandler implements
NativeModuleCallExceptionHandler {
#Override
public void handleException(Exception e) {
try {
.
.
.
Crashlytics.logException(new Exception(exceptionString));
} catch (Exception ex) {}
}
Crashes are getting logged in Crashlytics dashboard, but it's showing all the crashes inside a single tab. These might be different crashes of the same or different react-native components.
Due to this we are not able to find out the instances of a particular crash. Need to manually go through each instance of the crash.
I guess it takes the name of the class where exception gets created, in this case PlatformNativeModuleCallExceptionHandler.
I tried creating my own custom exception class but that also did not help.
Does anybody know how we can group the non fatal exceptions better here?
All the similar crashes should be grouped together with their total instances.
Crashlytics uses the method and crash line number to group crashes, so if you have an exception handler method for all of your non-fatals, they'll be grouped together. There isn't currently a workaround for this.
Best way I've found to do this is to manually chop the shared parts of the stacktrace off:
private fun buildCrashlyticsSyntheticException(message: String): Exception {
val stackTrace = Thread.currentThread().stackTrace
val numToRemove = 8
val lastToRemove = stackTrace[numToRemove - 1]
// This ensures that if the stacktrace format changes, we get notified immediately by the app
// crashing (as opposed to silently mis-grouping crashes for an entire release).
check(lastToRemove.className == "timber.log.Timber" && lastToRemove.methodName == "e",
{ "Got unexpected stacktrace: $stackTrace" })
val abbreviatedStackTrace = stackTrace.takeLast(stackTrace.size - numToRemove).toTypedArray()
return SyntheticException("Synthetic Exception: $message", abbreviatedStackTrace)
}
class SyntheticException(
message: String,
private val abbreviatedStackTrace: Array<StackTraceElement>
) : Exception(message) {
override fun getStackTrace(): Array<StackTraceElement> {
return abbreviatedStackTrace
}
}
This way the message can be parameterized Timber.e("Got a weird error $error while eating a taco") and all of that line's calls will be grouped together.
Obviously, numToRemove will need to change depending on your exact mechanism for triggering nonfatals.
I resolved this by setting a custom stack trace to the exception. A new Exception(exceptionMessage) will create the exception there itself, what we did was to throw an exception which in catch called my counterpart of handleException() with the actual stack trace furnished in the exceptionMessage. Some parsing and the exceptionMessage can be used to set the stack trace on the newly created exception using exception.setStackTrace(). Actually, this was required in my project only because it is cross-language, for regular projects, simply passing the exception thrown and caught at the place of interest should work.
Crashlytics groups by the line number that the exception was generated on and labels it with the exception type. If you know all the types of the exceptions you can generate each one on a different line. And you could also map your strings to custom Exception types to make it more easy to identify them in Crashlytics.
Here's an example:
public void crashlyticsIsGarbage(String exceptionString) {
Exception exception = null;
switch(exceptionString) {
case "string1": exception = new String1Exception(exceptionString);
case "string2": exception = new String2Exception(exceptionString);
case "string3": exception = new String3Exception(exceptionString);
case "string4": exception = new String4Exception(exceptionString);
default: exception = new Exception(exceptionString);
}
Crashlytics.logException(exception);
}
class String1Exception extends Exception { String1Exception(String exceptionString) { super(exceptionString); } }
class String2Exception extends Exception { String2Exception(String exceptionString) { super(exceptionString); } }
class String3Exception extends Exception { String3Exception(String exceptionString) { super(exceptionString); } }
class String4Exception extends Exception { String4Exception(String exceptionString) { super(exceptionString); } }
BTW, Crashlytics will ignore the message string in the Exception.
I was looking into this just now, because the documentation says:
Logged Exceptions are grouped by Exception type and message.
Warning:
Developers should avoid using unique values, such as user ID, product ID, and timestamps, in the Exception message field. Using unique values in these fields will cause a high cardinality of issues to be created. In this case, Crashlytics will limit the reporting of logged errors in your app. Unique values should instead be added to Logs and Custom Keys.
But my experience was different. From what I found out, what Alexizamerican said in his answer is true, with a small caveat:
Issues are grouped by the method and line where the exception was created, with the caveat that it is the root cause of the exception that is being taken into account here.
By root cause I mean this:
public static Throwable getRootCause(Throwable throwable) {
Throwable cause = throwable;
while (cause.getCause() != null) {
cause = cause.getCause();
}
return cause;
}
Therefore, if you did:
#Override
public void handleException(Exception e) {
// ...
Crashlytics.logException(e);
}
That should correctly group the exceptions together.
Furthermore, if you did:
#Override
public void handleException(Exception e) {
// ...
Crashlytics.logException(new Exception(exceptionString, e));
}
That would also correctly group the exceptions, because it would look at e or its cause, or the cause of that, and so on, until it reaches an exception that doesn't have any other cause, and look at the stack trace where it was created.
Finally, unlike what miguel said, exception type or message doesn't affect grouping at all in my experience. If you have FooException("foo") at some particular line in a particular method, and you replace it with BarException("bar"), the two will be grouped together, because the line and method didn't change.
I'm implementing Google Smart Lock into an app, and I was having no trouble with the Api Client building before. In fact, I was finalizing some syntax changes and cleaning up the code (didn't even touch the code that initializes the Api Client), and my app now dies when build() is called on the Api Client builder, due to abstract method zza. Here is the error being displayed:
java.lang.AbstractMethodError: abstract method "com.google.android.gms.common.api.Api$zze com.google.android.gms.common.api.Api$zza.zza(android.content.Context, android.os.Looper, com.google.android.gms.common.internal.zzq, java.lang.Object, com.google.android.gms.common.api.GoogleApiClient$ConnectionCallbacks, com.google.android.gms.common.api.GoogleApiClient$OnConnectionFailedListener)"
at com.google.android.gms.common.api.GoogleApiClient$Builder.build(Unknown Source)
I have no clue why it suddenly started failing, and I couldn't find any changes I made that would have caused this error. Why isn't that abstract method being overridden? It's nested deep inside the library so I don't understand how I could have affected it.
I wrapped the Google Api Client calls in a manager I named CredentialManager. Here is the code I used to initialize the client:
public CredentialManager(ContextProvider contextProvider) {
mContextProvider = contextProvider;
mCredentialsApiClient = new GoogleApiClient.Builder(mContextProvider.getContext())
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(CredentialManager.TAG, "Api connected");
}
#Override
public void onConnectionSuspended(int i) {
Log.i(CredentialManager.TAG, "Connection suspended with status " + i);
}
})
.enableAutoManage(mContextProvider.getContext(), connectionFailedResult -> {
if (connectionFailedResult.hasResolution()) {
try {
connectionFailedResult.startResolutionForResult(
mContextProvider.getContext(),
CredentialManager.Codes.RESOLVE_CONNECTION_REQUEST_CODE);
} catch (IntentSender.SendIntentException e) {
// Unable to resolve, log error
Log.e(CredentialManager.TAG, "Resolution failed: " + e.getMessage());
}
} else {
//instead of displaying a dialog, just let the user continue and login manually.
Log.e(CredentialManager.TAG, "Connection failed: " + connectionFailedResult.getErrorMessage());
}
})
.addApi(Auth.CREDENTIALS_API)
.build();
}
If you have any insight as to what is causing this error, please let me know. I've scoured the internet for anyone that has seen something like this before, but couldn't find anything.
The issue was that some google play services dependencies had their versions updated and not the play-services-auth dependency used for google smart lock. The apk would compile fine, but crash when the Google Api Client was trying to initialize. The fix was to make all the versions the same, and invalidate cache + restart android studio, recompile, and run.
I want to display some tweets with the twitter API in my app. To do so I have fetched some tweet ids (which is working without any hassle) and use the TweetViewFetchAdapter adapter provided by the Twitter API to display my tweets.
The weird thing is: this has worked at some point! But then suddenly it stopped working (company app, multiple people working on the code but I haven't seen any changes to the twitter stuff in the time between working and not working)
The code is super straight forward taken from the official twitter site:
// fill the tweet adapter with the loaded tweet ids
#Override
protected void onPostExecute(List<Long> params){
if (params != null && params.size() > 0) {
adapter.setTweetIds(params,
new LoadCallback<List<Tweet>>() {
#Override
public void success(List<Tweet> tweets) {
Log.i("twitter", "Success!");
}
#Override
public void failure(TwitterException exception) {
Log.e("twitter", "Exception: " + exception.getMessage());
}
});
}
Log.i("twitter", "params.size = " + params.size() + "adapter.tweetCount = " + adapter.getCount());
}
(inside an AsyncTask). The adapter seems to fail to set the tweet ids as the debug output is I/twitter﹕ params.size = 10 adapter.tweet Count = 0
I tried to debug/have a log output in the success/failure callbacks, but I never got anything as if the methods would never be called (quite weird actually..)
Regarding log cat output I haven't seen any, but I'm afraid there is a little chance I might have messed it up as we just recently moved to Android Studio and I just can't get my head around some stuff there yet.
Issue was caused by an wrong version of okhttp / okhttp-urlconnection.
The weird part is that no debug messages was shown. This code resolved the debug message issue and helped resolve the issue overall:
final Fabric fabric = new Fabric.Builder(this)
.kits(new Twitter(authConfig))
.logger(new DefaultLogger(Log.DEBUG))
.debuggable(true)
.build();
Fabric.with(fabric);
Overall fix: change build.gradle:
dependencies {
// ...
compile 'com.squareup.okhttp:okhttp:2.3.0'
compile 'com.squareup.okhttp:okhttp-urlconnection:2.3.0'
}
Original conversation: https://twittercommunity.com/t/adapter-settweetid-seems-to-be-unable-to-load-the-tweets-but-doesnt-fire-a-success-failure-callback/36506/13
I am trying to Integrating Aurasma in my application. All application work well but on Aurasma part when I launch it on Button Click IT throws a message on splash screen as "An error is occurred" and on Log Cat It shows "Resource integrity check failed" I am wondering why this is happening, I integrate aurasma on a separate application without any click event, it launches directly then it works but in side of my application its not working, why. I am sure about these points:
Make sure the SDK tools are version 14 or above.
Check the Eclipse project to make sure that AurasmaKernel is set as required on the build path
Check that the AurasmaKernel package has built properly in Eclipse (also try building it manually)
Make sure that the kernel is correctly extracted, and that your resources don't clash with any of the packaged library
But yet it not working same error message.
Code for launching Aurasma is below:
aurasmaIntent = AurasmaIntentFactory.getAurasmaLaunchIntent(HomeActivity.this,
getString(R.string.app_name), getString(R.string.app_version));
} catch (AurasmaLaunchException e) {
Log.e("AKTest", "Error getting intent", e);
showDialog(DIALOG_ERROR);
return;
}
if (DELAY_START) {
AurasmaSetupCallback callback = new AurasmaSetupCallback() {
#Override
public void onLoaded() {
dismissDialog(DIALOG_PROGRESS);
startActivity(aurasmaIntent);
}
#Override
public void onLoadWarning(final int code) {
Log.w("AKTest", "Preload warning: " + code);
}
#Override
public void onLoadFail(final int code) {
Log.e("AKTest", "Preload error: " + code);
dismissDialog(DIALOG_PROGRESS);
showDialog(DIALOG_ERROR);
}
};
showDialog(DIALOG_PROGRESS);
AurasmaIntentFactory.startAurasmaPreload(getApplicationContext(), aurasmaIntent,
callback);
} else {
startActivity(aurasmaIntent);
}
}
If you change some resource from Aurasma library(layout or string) you will get this error - "An error is occurred". Library checks resources on Aurasma start. Don't change or delete any files.
Another thing that can cause error is:
aurasmaIntent = AurasmaIntentFactory.getAurasmaLaunchIntent(HomeActivity.this,
getString(R.string.app_name), getString(R.string.app_version));
Here second parameter is userAgentName. This is the name of your app that you have from studio.aurasma.com. In "Make your own app" you can see the application name - this name is connected with your application but can be different.
check your minSdkVersion in the manifest
android:minSdkVersion="8"