Should I remove e.printStackTrace() from my code before publishing - android

I was reading the the Android Publishing docs and they said to remove all Log calls from my code. I have some calls to e.printStackTrace() in my code that can be printed as part of the normal running of my program (ie. if a file does not exist yet).
Should I also remove these calls?

You shouldn't be using e.printStackTrace() directly anyway — doing so will send the info to the Android log without displaying which application (log tag) it came from.
As others have mentioned, continue to catch the Exception in question, but use one of the android.util.Log methods to do the logging. You could log only the message, but not the stack trace, or use verbose logging for the stack trace:
try {
Object foo = null;
foo.toString();
} catch (NullPointerException ex) {
Log.w(LOG_TAG, "Foo didn't work: "+ ex.getMessage());
Log.d(LOG_TAG, Util.stackTraceWriter(ex));
}
You should strip DEBUG or VERBOSE log messages from your production builds. The easiest way is to use ProGuard to remove Log.[dv] calls from your code.

If you allow an Exception to propagate up to the OS then the OS will log it and also pop up a Force Close window, killing your application. If you catch it, then you can prevent your application from being force closed.
If you want your users to have the ability to send you errors that they are getting, then I would log the stack trace. They can then send you the log via an app like Log Collector.
If you want to avoid the possibility of exposing your stack trace information to your users, then catch the exception and don't log it.

I would use Log class for message out put. For logs that you think are important to stay in the app - use Log.i
for errors warning - Log.e Log.w
For you debug Log.d - and that you can turnoff on base on if your application is in debug mode.
http://developer.android.com/reference/android/util/DebugUtils.html

Well printStackTrace() will log it into the OS, causing your andorid (or computer) app to terminate (force close), instead, do something like this:
public void nullPointerExceptionCauser()
{
try
{
Object example = null;
example.toString();
}
catch (Exception e)
{
Logger.log(Level.SEVERE, "Caught Exception: {0}", e.getStackTrace());
}
}

in my modest opinion (I'm not an Android developer)
It should be nice. I don't know the logging options for Android but I'm sure you have some configurable thing to output (or not) your traces.
And if you don't do printStackTrace() Android will not be doing the dirty work of ignoring it.
:)
It's only a good-feeling (style) thing.

If you want to be secure i.e. not allow anyone snooping to read exception logs you can do something like
private void hideExceptionsInReleaseMode()
{
final Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
if(!BuildConfig.DEBUG)
{
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler()
{
#Override
public void uncaughtException(Thread thread, Throwable ex)
{
defaultHandler.uncaughtException(thread, new RuntimeException("Something went wrong :p"));
}
});
}
}

In order to use printStackTrace in a safer way I would use StringWrite and PrintWriter:
...
catch (final Exception e)
{
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
Log.e("TAG", sw.toString());
}
Or alternatively:
catch (final Exception e)
{
Log.e(TAG, Log.getStackTraceString(e));
}

Use this to remove the logs from release apk
if (BuildConfig.DEBUG) Log.d(TAG, "your meseage");

Related

How do I save app logs locally on Android?

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/

Handle IOException inside function

I have a method which copies some files from shared memory to internal app memory using the library FileUtils.
The goal is handling IOException in order not to crash the app: it's acceptable if some files are not copied out of the total number.
In the second snippet below there is the called method where the exception is handled.
I need to know 2 things:
a) is there a way to handle the exception only in the called method
and not also in the calling code?
b) in your opinion the exception handling is correct or do I need to add some other code?
Below is the code:
try {
copyfilesfromshared(context);
} catch (IOException e) {
e.printStackTrace();
}
public void copyfilesfromshared(Context context) throws IOException {
for (int ii = 0; ii < numfiles; ii++) {
try {
FileUtils.copyFileToDirectory(files[ii], dirwrite);
} catch (IOException e) {
e.printStackTrace();
}
}
}
is there a way to handle the exception only in the called method and not also in the calling code?
If you handle the exception in copyfilesfromshared() function you do not need to declare throws IOException
public void copyfilesfromshared(Context context) {
for (int ii = 0; ii < numfiles; ii++) {
try {
FileUtils.copyFileToDirectory(files[ii], dirwrite);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Then you can use it normally, without declarin try {...} catch(...) again:
copyfilesfromshared(context);
in your opinion the exception handling is correct or do I need to add some other code?
This looks fine to me, but better check the signature of FileUtils.copyFileToDirectory if it throws any other exception as well, you maybe want to catch here too.
Beside that, it is totally on your side where you wanna handle the exception, but in general the earlier the better.
Heyy,
For your first question
a) is there a way to handle the exception only in the called method
and not also in the calling code?
There is a choise between throwing the IOException from the called method OR
to implement try/catch inside method.
And thats your problem
You are choosing both options instead of one, So just choose one.
And about 2 question
b) in your opinion the exception handling is correct or do I need to
add some other code?
Exception handeling is best at this moment, So don't think and other thought
And that's all!!

Restart app after crash using Crashlytics

Is it possible to auto-restart app after crash using Crashlytics? Unfortunately there is nothing about that topic in docs. I defined my own exception handler which is restarting app, but when i use it crash logs are not sent.
In your custom exception handler you can call Craslytics.logException(exception);.
public class MyExceptionHandler implements Thread.UncaughtExceptionHandler {
#Override
public void uncaughtException(Thread thread, Throwable exception) {
//you should also log the exception to logcat
Log.e(TAG, "UncaughtException", exception);
try {
//log to crashlytics
Crashlytics.logException(exception);
} catch (Exception e) {
Log.d(TAG, "uncaughtException: Crashlytics not initialized, cannot send logs.");
}
//exit with error code 1 (0 is normal program termination,
//which here is not the case)
System.exit(1);
}
}
One thing worth noting is that Crashlytics.logError(...) logs exceptions as "non-fatal". So I usually wrap them so I can differentiate non-fatal exceptions from actual fatal ones.
So:
Crashlytics.logException(exception);
becomes:
//wrap the original exception to your custom 'fatal' exception type.
FatalException fatalException = new FatalException(originalException);
//log with Crashlytics
Crashlytics.logException(fatalException);
Sample from an open source app here.

How to effectively group non fatal exceptions in Crashlytics (Fabrics)?

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.

Log.d() stops working after calling Integer.parseInt(INVALID_INT)

private void someFunction(String html) {
Document doc = Jsoup.parse(html);
Element vol = doc.select(CSS_PATH).first();
Log.d("Vol", vol.text());
Log.d(TAG, "This gets printed");
Float.parseFloat(vol.text());
Log.d(TAG, "BUT THIS ONE NOT");
}
These two objects are elements of the Jsoup library.
Document doc = Jsoup.parse(html);
Element vol = doc.select(PATH.PEAK_DOWN_VOL).first();
vol.text() returns a String containing a float value.
Log.d("Vol", vol.text()); // logs something similar to 'Vol: 12.4'
But after calling Float.parseFloat(peakDownVol.text());, Log.d in this class will stop entirely. But Log.d's in the Activity class seems to work just fine.
If I change Float.parseFloat(vol.text()); to Integer.parseInt(vol.text());, it logs the subsequent statements without any problem.
I have lot of number parsing to do. So I'd like to know why is this happening exactly?
If you want the rest of the method to run regardless, you should catch the potential exception locally, so that the program can continue executing the rest of the method and not bubble back up the call stack until it finds an exception handler or crashes for the lack of one:
Log.d(TAG, "This gets printed");
try {
Float.parseFloat(vol.text());
} catch (NumberFormatException e) {
e.printStackTrace(); //leave evidence in the log
}
Log.d(TAG, "So does this");

Categories

Resources