So, Android built in this "feature", that any exception which has an UnknownHostException in its cause stack will not have its stack trace logged when passed into Log.X methods... See for example the questions here or here. Or check the original commit which introduced this (n.b. the comment).
Personally I consider this to be a really stupid decision: in my case this so called feature even prevents any kind of toString() call on my custom exceptions, so if any error or exception at any point was caused by UnknownHostException it'll log just... nothing. :/ (Well yes, I get the timestamp, tag, etc. but no actual logged content.)
Is there any way around this issue, except for replacing the logging framework with something else entirely?
Is there some config I haven't found or some other clever way to fix logging?
Related
Map<String, Object> city = new HashMap<>();
city.put("name", "Los Angeles");
city.put("state", "CA");
city.put("country", "USA");
db.collection("cities").document("LA")
.set(city)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "DocumentSnapshot successfully written!");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Error writing document", e);
}
});
This is FirebaseFirestore's simple data input code.
but When I look into onSuccess() and onFailure() methods, each of them has a different method of Log class. and I don't know why this code use them differently in those Overriding methods(onSuccess() and onFailure()).
Why did this particular code use one over the other? Because the person who wrote chose to. They could have used i (info) and e (error) instead.
The short answer is use whatever you want because it ultimately doesn't matter: at the end of the day your message goes into the LogCat output stream that you can look at.
The longer answer is that you want to log to a particular "stream" based on the type of information you're logging. You have your choice of 5 main "streams" of logging, listed here in order of how frequently you might expect to use them, from least to most: Error, Warn, Info, Debug, and Verbose.
Again, you can log to whichever your heart desires but generally speaking:
Log to ERROR (Log.e()) when you detect a valid error state or exception that actually prevents your app from functioning correctly. For example, if you think you're handling every case of a switch statement, you might add an error log in the default case which shouldn't happen. These are cases that you as the developer want to know about and fix, even if they are not crashing your app. You might report these as "non-fatal" exceptions in Crashlytics.
Log to WARN (Log.w()) for unexpected but non-critical errors that occur. These are to draw attention that something went wrong, but that the app continued as best as it could. In your posted example, the "failure listener" might be using WARN because that failure is a valid case to handle and you want to be aware of failures, but it's known that failure is possible so the app should handle it gracefully and be able to continue.
Log to INFO (Log.i()) for information you would find generally always find useful but that doesn't get too noisy. These would be things that would help you track down bugs in a crash report. Logging Activity lifecycle events would be an example.
Log to DEBUG (Log.d()) for information you would find temporarily helpful while in development to help you solve a particular problem or while trying to track down a specific bug. For example, if your app is crashing at a specific location, you might add a Log.d call just before that spot and log the state of the local variables or something to help you find out what's causing the crash. You would probably remove these once that issue or bug is resolved.
Log to VERBOSE (Log.v()) when you need even more information even more frequently then you can get with DEBUG. As its name implies, this is intended to be verbose. It will spew a lot of text into LogCat making it so noisy as to be unusable. For example, you might log every iteration of a long loop to VERBOSE.
Once you're logging to any particular stream, you can filter the LogCat logs to aid in finding particular messages. For example, if something is going wrong with a library you're using in your app, you might filter to WARN to narrow the size of the LogCat logs and look for any warnings the library may have reported.
You filter in Android Studio by selecting the drop down in the LogCat tab. Android Studio also colors each stream (which you can configure in settings) to aid in differentiating the log messages).
Hope that helps!
They are calling different method: d stands for debug and w for warning.
Warning is used when the action fails, debug when all is OK just to tell you...
During debugging of Android app, sometimes InterruptedException occurs and crashes the app. I've been able to set a break-point on default exception handler, but call stack is not informative.
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:1991)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2025)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1048)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:776)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1035)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1097)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:820)
What is telling is that the interrupted thread is always RxCachedThreadScheduler-4 (or some other number)
What would be a systematic approach towards finding the root cause of the exception?
Set breakpoint at the method Thread::interrupt and catch the offender. If you think that this interruption should not happen, and you cannot switch off the call which interrupts your thread, then you can override Thread::interrupt in your thread implementation, and force the the thread pool to use your implementation by providing your own ThreadFactory.
It looks like the crash is happening from a third party code package, you should post your issue with the source project as well for additional help. Please post any code related to how you use this package to help troubleshoot too. Make sure you're using the latest version of this package in case they already fixed this issue. The stack trace isn't very helpful because the other project is launching threads and the crash happens from within one of their threads. Likely, you're not using the package as intended or there is a bug in it that they need to fix.
https://github.com/ReactiveX/RxJava
I just learned about Log.wtf ("What a Terrible Failure" lol) and I'm wondering when I should use it.
What is the difference between calling Log.wtf with an exception and letting an exception go unhandled (crash)?
How does it affect crash reports in the Google Play Developer Console?
I usually throw an IllegalStateException for unexpected conditions. Should I consider calling Log.wtf instead?
Edit:
See also: Under what circumstances will Android's Log.wtf terminate my app?
What Log.wtf does is write the exception and its stack trace in the log, and only that. It neither catches nor throws exceptions. So
The difference is the exception is logged or not. The exception remains unhandled.
It doesn't affect crash reports.
If you wish to log it, go ahead. But you'll want to keep throwing IllegalStateException.
EDIT
I tried debugging and stepping into Log.wtf but no luck.
What I've found is pretty much what is answered in the linked question. It seems that in the "default terrible failure handling" Log.wtf creates an internal exception (TerribleFailure) which wraps any given exception. Then it calls RuntimeInit.wtf(). Its javadoc says:
Report a serious error in the current process. May or may not cause
the process to terminate (depends on system settings).
I guess the behavior of Log.wtf is up to the device manufacturer. My Sony C6503 doesn't seem to raise any exception or kill the process.
Some open source reference:
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/util/Log.java
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/com/android/internal/os/RuntimeInit.java
Unhandled exceptions are not logged by default. Log.wtf may or may not crash the application. If you pass an exception to Log.wtf and it crashes, then you should get a stack trace similar to what you would get if the exception were not handled. After calling Log.wtf, you should (re)throw an exception if you want to ensure a crash (without catching it of course).
There may be specific use cases for Log.wtf, but if you are unsure, it's probably better to use Log.e instead.
My Android app uses the AWS Java SDK for uploading user photos to S3.
Whenever a user's phone's clock is 'skewed', this causes all transfers to fail. This is a well documented aspect of S3:
http://aws.amazon.com/articles/1109?_encoding=UTF8&jiveRedirect=1#04
It appears that the upstream S3 service reports this error quite clearly:
HTTP Status Code: 403 Forbidden
Error Code: RequestTimeToo-Skewed
Description: The difference between the request time and the server's
time is too large.
However when using the Java SDK, it seems as if the informative 403 code is lost ... and I have only an opaque "TransferState.Failed" to go by (which incidentally is the same error if internet connectivity is lost, if it times out, etc...).
As far as I can tell from the docs:
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/index.html
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/transfer/TransferProgress.html
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/transfer/Transfer.TransferState.html
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/transfer/Upload.html
There is no way to get the additional "RequestTimeToo-Skewed" metadata about a transfer failure.
Am I missing it? Is there any way to get additional error information when an S3 transfer fails using Amazon's Java SDK?
UPDATE #1:
A commenter kindly highlighted that I should clarity two points:
I am actually using the AWS SDK for Android (which seems very similar to the Java SDK, but is nonetheless distinct)
I am using the TransferManager class to perform my upload. Apparently, this is a high-level class that wraps the lower-level AmazonS3Client ... and this lower-level class should expose the error reporting I need, but I am still investigating the exact tradeoffs involved between TransferManager and AmazonS3Client. As far as I can tell, there is no way to get progress information via the (synchronous) AmazonS3Client.putObjectRequest which would be a blocker for me...
UPDATE #2:
My sincere thanks to Jason (of the AWS SDK team) for stopping by and helping me out here. The important information is, indeed, available as properties on an AmazonS3Exception if you use certain methods. The docs had originally confused me and I thought that a manual Thread.sleep() loop was required to poll status (and thus I could not leverage waitForCompletion or waitForException), but if you use ProgressListener on PutObjectRequest you can get full progress callbacks and the error-fidelity of AmazonS3Exception.
these two methods should help you out:
Transfer.waitForCompletion()
Transfer.waitForException()
If you detect that your transfer has failed based on a transfer progress event, you can simply call Transfer.waitForException() to be returned the exception that occurred. That exception will be an AmazonServiceException in this case, with all of the info that you need to see that the real problem was a clock skew issue.
Alternatively, the Transfer.waitForCompletion() method will unwrap the original exception from an ExecutionException and directly throw the original exception, just as if it'd all been happening on one thread. This might be a more convenient approach if you want to use a catch blocks to catch different types of errors cleanly and elegantly.
I disagree that the "catch Exception" block is "brutally broad". The point of that code is to catch any error that happens, mark the transfer as failed and rethrow the error so that the application code can know about it. If it were less broad, then that's exactly the case where exceptions could sneak through and transfer progress wouldn't be updated correctly and would be out of sync with reality.
Give those two methods and shot and let us know if that helps!
Well, I have debugged Amazon's SDK and I'm sorry to say that this information is being swallowed internally. Perhaps I will try to submit a patch.
Details: an AmazonS3Exception is being thrown internally which does in fact accurately report this exact error scenario, but a brutally broad try catch ( Exception e ) consumes it and washes away the specificity.
Here is the guilty try-catch:
https://github.com/aws/aws-sdk-java/blob/master/src/main/java/com/amazonaws/services/s3/transfer/internal/UploadMonitor.java#L145
Here is a screenshot showing that an AmazonS3Exception is correctly thrown with the right info...
I would like to be able to determine, in case an exception occurs while the user is using my application, where exactly the exception took place. I'd like to do something similar ti printStackTrace() method. (So this is during build mode, not debug mode )
Currently I've put almost all my methods from all my classes inside a try-catch statement (each method has a try-catch statement which encompasses all it's instructions) and i can, at this point, display the "tree" or stack of methods if an exception occurs. But is there a way to determine either a line number of something to more precisely indicate where inside the method the exception occurred? Similar to what is displayed when you use printStackTrace().
I'm not really used with Exception handling, what is the best practice for doing this and can in be done?
EDIT
And one other thing. When i use printStackTrace() during build mode, where does it display the content, because Logcat isn't available? Can i retrieve that information and maybe do something with it?
OR
Even better, can i use getStackTrace() during build mode and convert the stuff there in String and maybe output it somewhere?
All the exceptions that are not handled by your code and make your app crash in release mode will appear in the android developper console, close to your app.
For this to work, you will need to retrace obfuscated stack traces.
About exception handling : I suggest you read this for instance. You are making a mistake about exception handling if you surround all your code by a try/catch block.
Exception handling is more subtile than that and is often influenced by design considerations (whether to treat exceptions locally or throw them back to the caller).
To sum up : in the core of your app : don't treat exception but throw them or let them be thrown, using the throws clause of your methods signatures. In the upper layers, closer to the UI, treat exceptions with try/catch and if an error occurs, make sure your app is in a stable state and display some usefull messages to users.
More details (but not that much) :
in the database layer : throw exception. You can still catch them to log them, but throw or rethrow them to tell caller that something went wrong.
in the business layer : catch them, make sure your business/domain model is in a stable state and recovers from the error, and throw them back to the caller.
in the UI layer : catch the exceptions and display some messages to users.