I have just finished my first android app as part of a school project ..one of my friends encountered a problem while trying to explore one of the activities in the app ..so i searched for solutions to get the crashes reports whenever they happen to fix the bugs ..i came across ACRA ..and I followed one of SO threads to setup ACRA to my app ..
RESULT: when the crashs happens the gmail app get launch in the device and the user (if he want to) he'll send the crash report by email ..Consedering not all users will want to ..i found in a comment in one of the SO threads that some developers use tracepot.
so i have used their link for integration in formUri but exploring my account on tracepot i get nothing ..is there something i am doing wrong (or if there is a better solution than using tracepot a backend , please suggest/explain or link a good tutorial, thanks!)
MyApplication.Java ( AFTER EDITING
#ReportsCrashes(
formUri = "https://collector.tracepot.com/79b1***",
reportType = org.acra.sender.HttpSender.Type.JSON,
httpMethod = org.acra.sender.HttpSender.Method.PUT,
mode = ReportingInteractionMode.TOAST,
resToastText = R.string.crash_toast_text
)
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
CaocConfig.Builder.create()
//.errorActivity(CustomErrorActivity.class) //default: null (default error activity)
.apply();
// The following line triggers the initialization of ACRA
ACRA.init(this);
}
}
EDIT :
msg in logcat if i use the http and email:
09-17 18:37:33.700 14329-14812/ma.ac.iav.menunaviagtion:acra W/ACRA: ma.ac.iav.menunaviagtion reports will be sent by email (if accepted by user).
09-17 18:37:33.703 14329-14812/ma.ac.iav.menunaviagtion:acra I/ACRA: Sending report /data/user/0/ma.ac.iav.menunaviagtion/app_ACRA-approved/2018-09-17T18:37:33.441+01:00-IS_SILENT.stacktrace
if i use only the http :
09-17 22:47:00.648 20116-20137/ma.ac.iav.myapplication:acra E/ACRA: Failed to send crash report for /data/user/0/ma.ac.iav.myapplication/app_ACRA-approved/2018-09-17T22:44:52.199+00:00-IS_SILENT.stacktrace
IMPLEMENTATION:
compile 'ch.acra:acra:4.9.2'
LOGCAT FOR F43nd1r
09-18 01:39:49.631 18508-18803/? E/AndroidRuntime: FATAL EXCEPTION: Thread-5
Process: ma.ac.iav.myapplication, PID: 18508
java.lang.InternalError: Thread starting during runtime shutdown
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:733)
at android.app.SharedPreferencesImpl.startLoadFromDisk(SharedPreferencesImpl.java:119)
at android.app.SharedPreferencesImpl.<init>(SharedPreferencesImpl.java:112)
at android.app.ContextImpl.getSharedPreferences(ContextImpl.java:392)
at android.app.ContextImpl.getSharedPreferences(ContextImpl.java:373)
at android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:167)
at cat.ereza.customactivityoncrash.CustomActivityOnCrash.getLastCrashTimestamp(CustomActivityOnCrash.java:673)
at cat.ereza.customactivityoncrash.CustomActivityOnCrash.hasCrashedInTheLastSeconds(CustomActivityOnCrash.java:683)
at cat.ereza.customactivityoncrash.CustomActivityOnCrash.access$200(CustomActivityOnCrash.java:52)
at cat.ereza.customactivityoncrash.CustomActivityOnCrash$1.uncaughtException(CustomActivityOnCrash.java:112)
at org.acra.builder.ReportExecutor.endApplication(ReportExecutor.java:269)
at org.acra.builder.ReportExecutor.dialogAndEnd(ReportExecutor.java:254)
at org.acra.builder.ReportExecutor.access$400(ReportExecutor.java:42)
at org.acra.builder.ReportExecutor$2.run(ReportExecutor.java:217)
By default, if the mail config is present, Acra 4 will send via mail and nothing else.
To use both you'd have to configure the reportSenderFactories.
400: Client error
Indicates that tracepot rejected your report. This could have multiple reasons. To find out what the problem is, call ACRA.DEV_LOGGING = true; right before ACRA.init and post all logcat with the ACRA tag.
Also note that ACRA 4.9.2 does not support android Oreo and above, it is recommended to upgrade to at least ACRA 4.11, or just the newest version 5.2.0.
You are not sending all required fields to Tracepot.
https://tracepot.uservoice.com/knowledgebase/articles/355272-what-are-the-required-fields-acra-needs-to-send
ANDROID_VERSION
APP_VERSION_CODE
APP_VERSION_NAME
PACKAGE_NAME
REPORT_ID
STACK_TRACE
USER_APP_START_DATE
USER_CRASH_DATE
On iOS it's possible to use recordError(error) to log non-fatal errors on Crashlytics but apparently this feature is not available for Android.
The only alternative I found is to use logException(e).
I manage errors on my app and I want to log when specifics errors codes are returned. So, on Crashlytics I'd like the non-fatal errors to be referenced by the errorCode. But using the logException(e) method, errors are referenced by the method where logException(e) has been called.
How can I do that?
What I do in order to report a non-fatal issue is to log an exception using the following code (remember you can throw any subclass of Exception):
Crashlytics.logException(new Exception("My custom error message"));
You can also use Crashlytics below features to provide more information.
Logging Non-Fatal Events:
try {
myMethodThatThrows();
} catch (Exception e) {
Crashlytics.logException(e);
// handle your exception here!
}
Add some more messages:
Crashlytics.log(int priority, String tag, String msg);
Crashlytics.log("Higgs-Boson detected! Bailing out...");
Also you can provide some user information:
void Crashlytics.setUserIdentifier(String identifier);
void Crashlytics.setUserName(String name);
void Crashlytics.setUserEmail(String email);
For those who have migrated from Fabric-Crashlytics SDK to Firebase-Crashlytics SDK, the new way of logging non-critical exceptions or exceptions which have been caught in a try-catch block is this -
FirebaseCrashlytics.getInstance().recordException(e)
To add additional data fields to the crash report you can key-value pairs before logging the exception like this
val crashlytics = FirebaseCrashlytics.getInstance()
crashlytics.setCustomKey("position", 1)
crashlytics.setCustomKey("marker_mode", "hidden")
crashlytics.setCustomKey("direction_shown", true)
To add some log messages,
FirebaseCrashlytics.getInstance().log("Reached breakpoint 2")
As per the latest version of Crashlytics library 2.9.2 .. You can log non-fatal exception through this code
Firebase.crashlytics.recordException(e)
Here's the code:
Observable.combineLatest(observable1, observable2,observable3, observable4,observable5,new Function5<>())
When one or sevral observables return code = 404,I throw exception
return Observable.error(
new RxApiException(tHttpResult.getCode(), tHttpResult.getMessage()));
And I will get
FATAL EXCEPTION : RxCachedThreadScheduler-3
How to solve this problem?
You need to define how you handle errors. If no onError handler is set up for the consumer of the Observable it gets forwarded to the Uncaught Exception Handler for the executing thread instead.
On android the exception handler causes a fatal exception when triggered, closing the application.
Either define a way that error should be handled or use RxJavaPlugins.registerErrorHandler(...) to define how unhandled exceptions should be processed for your entire application.
I know some of exceptions are thrown by Android framework. Like ActivityNotFoundException, WindowManager.BadTokenException.
But i am not aware of all other exceptions which are specific to android framework.
Can anybody list possible Android framework specific exceptions with a small description. Or suggest me blogs information which contains the required information.
http://developer.android.com/reference/java/lang/Exception.html
I think here you can find it, "Known Indirect Subclasses", totally 224 exceptions.
Only choose the one started by "Android", here are about 72 exceptions, these should be the list
android.content.ActivityNotFoundException
android.util.AndroidRuntimeException
android.accounts.AuthenticatorException
android.os.BadParcelableException
android.util.Base64DataException
android.hardware.camera2.CameraAccessException
android.database.CursorIndexOutOfBoundsException
android.os.DeadObjectException
android.media.DeniedByServerException
android.support.v4.app.Fragment.InstantiationException
android.opengl.GLException
android.view.InflateException
android.content.IntentFilter.MalformedMimeTypeException
android.content.IntentSender.SendIntentException
android.view.KeyCharacterMap.UnavailableException
android.security.keystore.KeyExpiredException
android.security.keystore.KeyNotYetValidException
android.security.keystore.KeyPermanentlyInvalidatedException
android.util.MalformedJsonException
android.media.MediaCodec.CodecException
android.media.MediaCodec.CryptoException
android.media.MediaDrm.MediaDrmStateException
android.media.MediaDrmResetException
android.accounts.NetworkErrorException
android.os.NetworkOnMainThreadException
android.util.NoSuchPropertyException
android.media.NotProvisionedException
android.support.v4.os.OperationCanceledException
android.content.pm.PackageManager.NameNotFoundException
android.os.ParcelFileDescriptor.FileDescriptorDetachedException
android.os.ParcelFormatException
android.net.ParseException
android.app.PendingIntent.CanceledException
android.support.v8.renderscript.RSDriverException
android.support.v8.renderscript.RSIllegalArgumentException
android.support.v8.renderscript.RSInvalidStateException
android.support.v8.renderscript.RSRuntimeException
android.content.ReceiverCallNotAllowedException
android.os.RemoteException
android.widget.RemoteViews.ActionException
android.media.ResourceBusyException
android.content.res.Resources.NotFoundException
android.database.SQLException
android.database.sqlite.SQLiteAbortException
android.database.sqlite.SQLiteAccessPermException
android.database.sqlite.SQLiteBindOrColumnIndexOutOfRangeException
android.database.sqlite.SQLiteBlobTooBigException
android.database.sqlite.SQLiteCantOpenDatabaseException
android.database.sqlite.SQLiteConstraintException
android.database.sqlite.SQLiteDatabaseCorruptException
android.database.sqlite.SQLiteDatabaseLockedException
android.database.sqlite.SQLiteDatatypeMismatchException
android.database.sqlite.SQLiteDiskIOException
android.database.sqlite.SQLiteDoneException
android.database.sqlite.SQLiteException
android.database.sqlite.SQLiteFullException
android.database.sqlite.SQLiteMisuseException
android.database.sqlite.SQLiteOutOfMemoryException
android.database.sqlite.SQLiteReadOnlyDatabaseException
android.database.sqlite.SQLiteTableLockedException
android.provider.Settings.SettingNotFoundException
android.database.StaleDataException
android.view.Surface.OutOfResourcesException
android.view.SurfaceHolder.BadSurfaceTypeException
android.nfc.TagLostException
android.util.TimeFormatException
android.os.TransactionTooLargeException
android.media.UnsupportedSchemeException
android.security.keystore.UserNotAuthenticatedException
android.view.WindowManager.BadTokenException
android.view.WindowManager.LayoutParams#token
android.view.WindowManager.InvalidDisplayException
The following are the exceptions that are supported by Android:
1.) InflateException : This exception is thrown When an error conditions are occurred.
2.) Surface.OutOfResourceException: This exception is thrown When a surface is not created or resized.
3.) SurfaceHolder.BadSurfaceTypeException: This exception is thrown from the lockCanvas() method, when invoked on a Surface whose is SURFACE_TYPE_PUSH_BUFFERS
4.) WindowManager.BadTokenException: This exception is thrown at the time of trying to add view an invalid WindowManager.LayoutParamstoken.
I've been banging my head against a wall for hours on this one. The v4 docs for Google Analytics specify 2 different ways of getting your app to report uncaught exceptions. I can get neither to work. In both cases I see lines like this in LogCat when I trigger the uncaught exception to occur in my app (using dummy names for my own code):
08-17 17:33:30.248: V/GAV4(8968): Thread[main,5,main]: Tracking Exception: MyException (#MyClass:myMethod:143) {main}
08-17 17:33:30.248: V/GAV4(8968): Thread[main,5,main]: Dispatch call queued. Dispatch will run once initialization is complete.
08-17 17:33:30.248: V/GAV4(8968): Thread[main,5,main]: Passing exception to original handler.
...followed by the stacktrace for my exception and then finally:
08-17 17:33:44.282: I/Process(8968): Sending signal. PID: 8968 SIG: 9
From LogCat it looks like GA never actually dispatches the exception to Google's servers!
If someone has managed to get uncaught exceptions being reported in their Google Analytics Console it would be fantastic if they could share with us how they did it, please. I've seen other people on SO with queries like this (e.g., here and here) but no confirmation that uncaught exceptions are being reported.
I've got screen views showing up in the GA Console so I must be doing something right. But not uncaught exceptions. I'm assuming one should be looking for them under Behavior > Crashes and Exceptions, and I've set the end date to include today (it seems to be set to yesterday by default). Finally, in my analytics_global_config.xml I have:
<integer name="ga_dispatchPeriod">1</integer>
because otherwise the default is 1800 seconds, in which case I assume exceptions would not be seen in the GA console for at least 30 minutes after they occurred. ga_dryRun is false too.
As #xitx kindly pointed out, it looks like there's a bug in later versions of the Google Play Services library installed on people's devices. Because when I ran my existing code on an emulator for a relatively old device (API 9, and presumably running an old Google Play Services library) the crash did get reported to GA's console automatically. Here's what LogCat said when the crash occurred:
08-31 12:27:59.522: V/GAV4(335): Thread[GAThread,5,main]: Sending hit to store PATH: https: PARAMS: ul=en-us, ht=1409484468454, sr=480x800, a=746864705, sf=100.0, aid=com.redula.vsavings, cid=32da19a1-7e15-4c83-aaa9-f3f1d502b775, av=1.2, v=1, t=exception, an=Savings Organiser, tid=UA-XXXXXXXX, exd=NullPointerException (#HomeActivity:connectToInAppBillingService:202) {main}, _u=.2nKKhAAAL, exf=1,
08-31 12:27:59.622: V/GAV4(335): Thread[GAThread,5,main]: PowerSaveMode initiated.
08-31 12:27:59.652: V/GAV4(335): Thread[GAThread,5,main]: PowerSaveMode terminated.
08-31 12:27:59.652: V/GAV4(335): Thread[GAThread,5,main]: Dispatch running...
08-31 12:27:59.702: V/GAV4(335): Thread[GAThread,5,main]: User-Agent: GoogleAnalytics/3.0 (Linux; U; Android 2.3.1; en-us; sdk Build/GSI11)
08-31 12:27:59.702: V/GAV4(335): Host: ssl.google-analytics.com
08-31 12:27:59.702: V/GAV4(335): GET /collect?ul=en-us&ht=1409484468454&sr=480x800&a=746864705&sf=100.0&aid=com.redula.vsavings&cid=32da19a1-7e15-4c83-aaa9-f3f1d502b775&av=1.2&v=1&t=exception&an=Savings+Organiser&tid=UA-XXXXXXX&exd=NullPointerException+%28%40HomeActivity%3AconnectToInAppBillingService%3A202%29+%7Bmain%7D&_u=.2nKKhAAAL&_v=ma4.0.2&exf=1&qt=11249&z=2 HTTP/1.1
08-31 12:28:00.482: V/GAV4(335): Thread[GAThread,5,main]: sent 1 of 1 hits
08-31 12:28:00.492: V/GAV4(335): Thread[GAThread,5,main]: PowerSaveMode initiated.
08-31 12:32:48.562: I/Process(335): Sending signal. PID: 335 SIG: 9
And this is what the GA Console showed within a minute or so of the crash:
I know you only get the first line of the stacktrace but that will do for me for now. Various other people have their own approaches for getting the whole stacktrace (see #xitx's comments above and here for example).
So I plan to use my existing code and wait for Google to ship the fix to their bug in a later version of Google Play Service. My app should then work as-is once their fix is released.
For the record, I am using this in my tracker's XML file (res/xml/app_tracker_config.xml):
<bool name="ga_reportUncaughtExceptions">true</bool>
My getTracker() implementation:
public class MyApp extends Application {
private static Tracker tracker = null;
synchronized Tracker getTracker() {
if (tracker == null) {
GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);
analytics.enableAutoActivityReports(this);
tracker = analytics.newTracker(R.xml.app_tracker_config);
tracker.enableAdvertisingIdCollection(true);
}
return tracker;
}
}
Then in onCreate() for my home screen's activity I just do this to initialise GA:
((MyApp) getApplication()).getTracker();
EDIT (extra info): Global config file, res/xml/analytics_global_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="ga_logLevel">verbose</string>
<integer name="ga_dispatchPeriod">1</integer>
<bool name="ga_dryRun">false</bool>
</resources>
My app's manifest refers to this file in this child tag of the application element:
<meta-data
android:name="com.google.android.gms.analytics.globalConfigResource"
android:resource="#xml/analytics_global_config" />
Just add this in your manifest
<meta-data
android:name="com.google.android.gms.analytics.globalConfigResource"
android:resource="#xml/tracker.xml" />
After that you should start to receive in this logcat:
V/GAV4﹕ Thread[main,5,main]: Tracking Exception: ArithmeticException (#MyActivity:onResume:111) {main}
V/GAV4﹕ Thread[main,5,main]: Dispatch call queued. Dispatch will run once initialization is complete.
V/GAV4﹕ Thread[main,5,main]: Passing exception to original handler.
After restarting of application:
V/GAV4﹕ Thread[client_id_fetcher,5,main]: Loaded client id from disk.
V/GAV4﹕ Thread[main,5,main]: Loading Tracker config values.
V/GAV4﹕ Thread[main,5,main]: [Tracker] trackingId loaded: UA-XXXXXXXX-X
V/GAV4﹕ Thread[main,5,main]: [Tracker] session timeout loaded: 300000
V/GAV4﹕ Thread[main,5,main]: ExceptionReporter created, original handler is com.android.internal.os.RuntimeInit$UncaughtHandler
V/GAV4﹕ Thread[main,5,main]: Uncaught exceptions will be reported to Google Analytics.
V/GAV4﹕ Thread[GAThread,5,main]: connecting to Analytics service
V/GAV4﹕ Thread[main,5,main]: service connected, binder: android.os.BinderProxy#42175d30
V/GAV4﹕ Thread[main,5,main]: bound to service
V/GAV4﹕ Thread[GAThread,5,main]: connect: bindService returned true for Intent { act=com.google.android.gms.analytics.service.START cmp=com.google.android.gms/.analytics.service.AnalyticsService (has extras) }
V/GAV4﹕ Thread[main,5,main]: Connected to service
I/GAV4﹕ Thread[GAThread,5,main]: No campaign data found.
V/GAV4﹕ Thread[GAThread,5,main]: Initialized GA Thread
V/GAV4﹕ Thread[GAThread,5,main]: Loaded clientId
V/GAV4﹕ Thread[GAThread,5,main]: Loaded clientId
V/GAV4﹕ Thread[GAThread,5,main]: putHit called
V/GAV4﹕ Thread[GAThread,5,main]: Sending hit to service PATH: https: PARAMS: ul=en-us, ht=1408554996959, sr=720x1184, a=194292074, aid=<app package>, cid=9639b81c-b17a-4c3a-a43e-0c1f43a6d5c1, av=1.5.0.1, v=1, t=exception, an=<app name>, tid=UA-XXXXXXXX-X, exd=SQLiteBindOrColumnIndexOutOfRangeException (#MyApp:onCreate:185) {main}, _u=.nKhAAAL, exf=0
Currently in my project I'm using this code (in Application.onCreate() method), it works just fine:
GoogleAnalytics googleAnalytics = GoogleAnalytics.getInstance(this);
applicationPreferences = new ApplicationPreferences(getApplicationContext());
tracker = googleAnalytics.newTracker(R.xml.tracker);
tracker.enableExceptionReporting(true);
String lastErrorString = applicationPreferences.getLastErrorString();
if (lastErrorString != null) {
applicationPreferences.clearLastErrorString();
tracker.send(new HitBuilders.ExceptionBuilder().setDescription(lastErrorString).setFatal(true).build());
}
final Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable throwable) {
applicationPreferences.setLastErrorString(Throwables.getStackTraceAsString(throwable));
defaultUncaughtExceptionHandler.uncaughtException(thread, throwable);
}
});
Note: Throwables is class from guava
Variation without Guava but without full stacktrace, only original line number and method included into report:
GoogleAnalytics googleAnalytics = GoogleAnalytics.getInstance(this);
applicationPreferences = new ApplicationPreferences(getApplicationContext());
tracker = googleAnalytics.newTracker(R.xml.tracker);
tracker.enableExceptionReporting(true);
String lastErrorString = applicationPreferences.getLastErrorString();
if (lastErrorString != null) {
applicationPreferences.clearLastErrorString();
tracker.send(new HitBuilders.ExceptionBuilder().setDescription(lastErrorString).setFatal(true).build());
}
final Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable throwable) {
applicationPreferences.setLastErrorString(
new StandardExceptionParser(getApplicationContext(), null).getDescription(thread.getName(), throwable)
);
defaultUncaughtExceptionHandler.uncaughtException(thread, throwable);
}
});
Sorry for the offtopic, but since that problem I switched to using Crashlytics for error collecting and it is rather more effective, than GA.