Runtime Exception - How Do Obtain All Log Entries From Logcat? [duplicate] - android

Is there a way to make Throwable.printStackTrace(PrintStream s) print the full stack trace, so that I can see beyond the final line of "... 40 more"?

You don't need to; that information is present elsewhere in the stack trace. From the docs of printStackTrace():
Note the presence of lines containing the characters "...". These lines indicate that the remainder of the stack trace for this exception matches the indicated number of frames from the bottom of the stack trace of the exception that was caused by this exception (the "enclosing" exception).
This shorthand can greatly reduce the length of the output in the common case where a wrapped exception is thrown from same method as the "causative exception" is caught.
In other words, the "... x more" only appears on a chained exception, and only when the last x lines of the stack trace are already present as part of another chained exception's stack trace.
Suppose that a method catches exception Foo, wraps it in exception Bar, and throws Bar. Then Foo's stack trace will be shortened. If you for some reason want the full trace, all you need to do is take the last line before the ... in Foo's stack trace and look for it in the Bar's stack trace; everything below that line is exactly what would have been printed in Foo's stack trace.

Let's take the stack trace from the documentation of Throwable.printStackTrace():
HighLevelException: MidLevelException: LowLevelException
at Junk.a(Junk.java:13)
at Junk.main(Junk.java:4)
Caused by: MidLevelException: LowLevelException
at Junk.c(Junk.java:23)
at Junk.b(Junk.java:17)
at Junk.a(Junk.java:11)
... 1 more
Caused by: LowLevelException
at Junk.e(Junk.java:30)
at Junk.d(Junk.java:27)
at Junk.c(Junk.java:21)
... 3 more
The causes are displayed from the most nested one at the bottom (the "root cause"), to the one which the printed stack trace belongs to.
In this case the root cause is LowLevelException, which caused MidLevelException, which caused HighLevelException.
To get the complete stack trace you have to look at the frames of the enclosing exception (and its enclosing exceptions):
Look at how many frames were omitted: "... X more"
Look for the omitted frames at the enclosing exception
Look at how many frames were omitted: "... Y more"
Append the first X - Y frames to the stack trace
If Y > 0, repeat step 2 with it as number of omitted frames
So if we wanted to get the complete stack trace of LowLevelException we would do the following:
Look at how many frames were omitted: "... 3 more"
Look for the omitted frames at the enclosing exception (MidLevelException)
1 frame has been omitted ("... 1 more")
Append the first 2 (3 - 1) frames to the stack trace
Repeat step 2 with 1 as number of omitted frames
Look at the enclosing exception of MidLevelException (HighLevelException)
Append the first 1 frame to the stack trace
Your complete stack trace then looks like this:
LowLevelException
at Junk.e(Junk.java:30)
at Junk.d(Junk.java:27)
at Junk.c(Junk.java:21)
// From MidLevelException stack trace
at Junk.b(Junk.java:17)
at Junk.a(Junk.java:11)
// From HighLevelException stack trace
at Junk.main(Junk.java:4)
Side notes:
There might be cases where no frames are listed, e.g.:
HighLevelException: MidLevelException
at Junk.main(Junk.java:4)
Caused by: MidLevelException
... 1 more
This can happen when the cause it created in the same line: new HighLevelException(new MidLevelException()). Don't get confused by this, the approach described above still works, there are just no frames to use from the exception, continue with its enclosing one.
In some cases you can save yourself the counting by looking at the first frame which was not omitted (the line above ... X more). If you know which methods call the method in that line you can directly search for the callers in the frames of the enclosing exception:
HighLevelException: MidLevelException: LowLevelException
at Junk.c(Junk.java:29)
at Junk.b(Junk.java:21)
at Junk.a(Junk.java:13)
at Junk.main(Junk.java:4)
Caused by: MidLevelException
// You know Junk.d is only called by Junk.b
at Junk.d(Junk.java:35)
... 3 more

Quick guess at a method for you.
static void printLongerTrace(Throwable t){
for(StackTraceElement e: t.getStackTrace())
System.out.println(e);
}

Related

How do I run a Performance Trace multiple times in Parallel?

I have a Firebase Performance Monitoring trace called my_trace.
Now, I start this trace when I load an image:
void loadImage() {
final Trace trace = performance.newTrace("my_trace");
trace.start();
// ... (loading that happens asynchronously)
trace.stop();
}
This works fine when I try to load a single image, however, in my application I need to load many images in parallel.
This means that the following error is reported when I load my images:
Trace 'my_trace' has already started, should not start again!
How do I correctly start a trace multiple times in parallel as I want to record the performance of every single loading process?
Note: I cannot use HTTPMetric as the loading trace also contains image conversion and not just downloading.
You can record it manually by storing the start time yourself and then just recording the duration. This should work.
Reference: https://firebase.google.com/docs/reference/js/firebase.performance.Trace#record
As the error message says, there can only be a single trace with a unique name active at any time. So you'll either have to wait for the first my_trace to finish before starting the second (running them sequentially instead of in parallel), or you'll have to generate a unique name for each trace.
Given how the API is structured it should be possible to allow multiple traces of the same name to run in parallel. If you think Firebase should consider allowing that, I recommend you file a feature request.
Traces are allowed to run in parallel already. Traces are not indexed by trace names. As long the trace object is unique, you should be able to run traces in parallel. Same trace object cannot be re-used.
Eg: (Incorrect way of using trace object)
final Trace trace = performance.newTrace("my_trace");
trace.start();
trace.start(); // This would not work. Fails with the error message that the trace is already started.
// ... (loading that happens asynchronously)
trace.stop();
Eg: Right way using the same trace name multiple times in parallel.
final Trace trace1 = performance.newTrace("my_trace");
final Trace trace2 = performance.newTrace("my_trace");
trace1.start();
trace2.start();
// ... (loading that happens asynchronously)
trace1.stop();
trace2.stop();

Firebase crash report contains stack trace with <OR>

I have an app in production and I'm using Firebase for error and crash logging. Lately, I've been seeing some lines in the stack trace of the exceptions, starting with <OR>. Below is an example taken directly (save for the package name) from an exception reported by Firebase:
Exception java.lang.NullPointerException: Attempt to invoke interface method 'void com.mycompany.myapp.managers.b$a.f()' on a null object reference
com.mycompany.myapp.managers.PermissionManager.getInstance (PermissionManager.java)
<OR>.checkPermission (PermissionManager.java)
<OR>.onRequestPermissionsResult (PermissionManager.java)
com.mycompany.myapp.activities.ShareImageActivity.onSaveShare (ShareImageActivity.java)
com.mycompany.myapp.activities.ShareImageActivity$3.onClick (ShareImageActivity.java)
I know that this is not a regular stack trace since onRequestPermissionResults does not call checkPermission and checkPermission does not call PermissionManager.getInstance.
I assume this is one of the ways Android obfuscates the stack trace for the sake of security, but I couldn't find any documentation on this. Does anyone know how to interpret this stack trace?
The you see here is an indication that that Crash Reporting could not determine the actual object at that point. Currently, there is a known situation with Proguard deobfuscation where it could be ambiguous which object is the target here. This could be the case if you're stripping line numbers from your classes, which it looks like you are doing. This situation may improve if you are able to change your Proguard settings to remove the stripping of line numbers.
Add this to your proguard-rules.pro:
// obfuscate file name and keep line numbers
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
It should remove ambiguity and you should not see <OR> in your stacktrace anymore.

ANR has no line number

I have received an ANR from an end user, but the top line (in my code) has no line number. Why is that, and how am I supposed to identify the error? The code is obfuscated using progaurd.
More specifically, the first few lines of my stack trace are:
java.lang.NullPointerException
at com.perinote.perinote.main.MainActivity.onOptionsItemSelected(Unknown Source)
at android.app.Activity.onMenuItemSelected(Activity.java:2502)
at com.android.internal.policy.impl.PhoneWindow.onMenuItemSelected(PhoneWindow.java:950)

Traceview maximum record time?

I am using Debug.startMethodTracing and Debug.stopMethodTracing to optimize a piece of code that takes about 30 sec to execute but when I open the trace file with trace view it only shows me about 6.5 secondes of trace data.
Any clues ?
The function startMethodTracing by default only logs 8MB of trace data. To get a longer trace, set the second parameter to the maximum trace size you want it to record (in bytes).
startMethodTracing("mytrace", 100000000);
The buffer is limited by the device ram. You cannot specify a too big buffer when calling Debug.startMethodTracing.

Eclipse Logcat window cuts off exception stack traces

My logcat window in Eclipse only displays the first few lines of the StackTrace for each exception. This means that I often can't see where an exception occured. Is there any way to change this setting?
If you're referring to the "...12 more lines..." part, you only see that for exceptions that were the cause of another exception. If the top part of the stack trace is the same as the earlier trace, the full set of frames is only shown for the outermost exception, and the other traces get the "..." treatment.
Put another way, the chunk of a trace that isn't shown is a duplicate of a trace that appeared earlier in the exception cause chain. For example, suppose I have code where the method main() calls one(), which calls two(), and so on. four() throws an exception. two() catches it and re-throws it. The exception will look like this:
java.lang.RuntimeException: re-throw
at Foo.two(Foo.java:14)
at Foo.one(Foo.java:7)
at Foo.main(Foo.java:3)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: first
at Foo.four(Foo.java:23)
at Foo.three(Foo.java:19)
at Foo.two(Foo.java:12)
... 3 more
The "caused by" exception says "... 3 more" rather than explicitly listing one(), main(), and dalvik.system.NativeStart.main. So to get the full trace of the initial exception, you would start by reading its trace, then continue at the trace above.
Note there is no overlap -- two() appears in both, but in the "first" trace it's on the call to three(), and in the "re-throw" trace it's on the throw instruction.
you can overload all the log methods (log.d, log.i, log.e, etc) with (String tag, String msg, Throwable tr) parameters, where the third parameter is the exception. This will give you the full stacktrace in logcat
http://developer.android.com/reference/android/util/Log.html
If your code calls a method which produces too tall of stack you can (and should) handle the exception in your code and output whatever is relevant to logs.
If you have no exception handling whatsoever and you don't even know where in your code should you be putting such a handler then the problem is entirely elsewhere - you should be handling exceptions a bit better than that.

Categories

Resources