summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Siniavine <siniavine@google.com>2014-12-03 17:39:33 -0800
committerMaxim Siniavine <siniavine@google.com>2014-12-09 15:30:51 -0800
commitc2f8ca20c05a22b5438c2fdbdceb32070321b243 (patch)
tree62acb1fbd447109970ed810b3bf086c26647a333
parentde0755858206387d9632365410c429ec05689312 (diff)
downloadloganalysis-c2f8ca20c05a22b5438c2fdbdceb32070321b243.tar.gz
Allow the use of custom tags to detect java crahes
Change-Id: I949bf99eae6ae4c45140ab90659b7fc9b20f703e
-rw-r--r--src/com/android/loganalysis/parser/JavaCrashParser.java16
-rw-r--r--src/com/android/loganalysis/parser/LogcatParser.java89
-rw-r--r--tests/src/com/android/loganalysis/parser/JavaCrashParserTest.java24
-rw-r--r--tests/src/com/android/loganalysis/parser/LogcatParserTest.java80
4 files changed, 207 insertions, 2 deletions
diff --git a/src/com/android/loganalysis/parser/JavaCrashParser.java b/src/com/android/loganalysis/parser/JavaCrashParser.java
index f1c87a1..e8d561a 100644
--- a/src/com/android/loganalysis/parser/JavaCrashParser.java
+++ b/src/com/android/loganalysis/parser/JavaCrashParser.java
@@ -41,6 +41,10 @@ public class JavaCrashParser implements IParser {
*/
private static final Pattern AT = Pattern.compile("^\tat .+$");
+ // Sometimes logcat explicitly marks where exception begins and ends
+ private static final String BEGIN_MARKER = "----- begin exception -----";
+ private static final String END_MARKER = "----- end exception -----";
+
/**
* {@inheritDoc}
*
@@ -56,6 +60,18 @@ public class JavaCrashParser implements IParser {
boolean inStack = false;
for (String line : lines) {
+ if (line.contains(BEGIN_MARKER)) {
+ inMessage = false;
+ inCausedBy = false;
+ inStack = false;
+ stack = new StringBuilder();
+ message = new StringBuilder();
+ jc = null;
+ continue;
+ }
+ if (line.contains(END_MARKER)) {
+ break;
+ }
if (!inStack) {
Matcher exceptionMatch = EXCEPTION.matcher(line);
if (exceptionMatch.matches()) {
diff --git a/src/com/android/loganalysis/parser/LogcatParser.java b/src/com/android/loganalysis/parser/LogcatParser.java
index 7011646..f729bb6 100644
--- a/src/com/android/loganalysis/parser/LogcatParser.java
+++ b/src/com/android/loganalysis/parser/LogcatParser.java
@@ -26,6 +26,7 @@ import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
@@ -127,10 +128,14 @@ public class LogcatParser implements IParser {
private Map<Integer, String> mPids = new HashMap<Integer, String>();
+ private List<JavaCrashTag> mJavaCrashTags = new ArrayList<JavaCrashTag>();
+
/**
* Constructor for {@link LogcatParser}.
*/
public LogcatParser() {
+ // Add default tag for java crash
+ addJavaCrashTag("E", "AndroidRuntime", LogcatParser.JAVA_CRASH);
initPatterns();
}
@@ -284,7 +289,7 @@ public class LogcatParser implements IParser {
}
// PID and TID are enough to separate Java crashes.
- if (("E".equals(level) && "AndroidRuntime".equals(tag))) {
+ if (anyJavaCrashTagMatches(level, tag)) {
String key = encodeLine(pid, tid, level, tag);
LogcatData data;
if (!mDataMap.containsKey(key)) {
@@ -321,7 +326,7 @@ public class LogcatParser implements IParser {
MiscLogcatItem item = null;
if ("E".equals(data.mLevel) && "ActivityManager".equals(data.mTag)) {
item = new AnrParser().parse(data.mLines);
- } else if ("E".equals(data.mLevel) && "AndroidRuntime".equals(data.mTag)) {
+ } else if (anyJavaCrashTagMatches(data.mLevel, data.mTag)) {
// Get the process name/PID from the Java crash, then pass the rest of the lines to
// the parser.
Integer pid = null;
@@ -349,6 +354,7 @@ public class LogcatParser implements IParser {
if (item != null) {
item.setApp(app);
item.setPid(pid);
+ item.setCategory(getCategory(data.mLevel, data.mTag));
}
} else if ("I".equals(data.mLevel) && "DEBUG".equals(data.mTag)) {
// CLog.v("Parsing native crash: %s", data.mLines);
@@ -481,4 +487,83 @@ public class LogcatParser implements IParser {
return false;
}
}
+
+ /**
+ * Allows Java crashes to be picked up from different parts of logcat. Normally the crashes
+ * are error level messages from AndroidRuntime, but they could also be from other sources.
+ * Use this method to parse java crashes from those other sources.
+ *
+ * @param level log level on which to look for java crashes
+ * @param tag log tag where to look for java crashes
+ */
+ public void addJavaCrashTag(String level, String tag, String category) {
+ mJavaCrashTags.add(new JavaCrashTag(level, tag, category));
+ }
+
+ /**
+ * Determines if any of the java crash tags is matching a logcat line.
+ *
+ * @param level log level of the logcat line
+ * @param tag tag of the logcat line
+ * @return True if any java crash tag matches the current level and tag. False otherwise.
+ */
+ private boolean anyJavaCrashTagMatches(String level, String tag) {
+ return findCrashTag(level, tag) != null;
+ }
+
+ /**
+ * Finds JavaCrashTag matching given level and tag.
+ *
+ * @param level level to find
+ * @param tag tag to find
+ * @return matching JavaCrashTag or null if no matches exist.
+ */
+ private JavaCrashTag findCrashTag(String level, String tag) {
+ for (JavaCrashTag t : mJavaCrashTags) {
+ if (t.matches(level, tag)) {
+ return t;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns category for a given JavaCrashTag.
+ *
+ * @param level level of the JavaCrashTag
+ * @param tag tag of the JavaCrashTag
+ * @return category of the JavaCrashTag, matching search criteria. If nothing was found
+ * returns default value for the standard java crash.
+ */
+ private String getCategory(String level, String tag) {
+ JavaCrashTag jct = findCrashTag(level, tag);
+ if (jct == null) {
+ return LogcatParser.JAVA_CRASH;
+ } else {
+ return jct.getCategory();
+ }
+ }
+
+ /**
+ * Class to encapsulate the tags that indicate which java crashes should be parsed.
+ */
+ private class JavaCrashTag {
+ private String mLevel;
+ private String mTag;
+ private String mCategory;
+
+ public JavaCrashTag(String level, String tag, String category) {
+ mLevel = level;
+ mTag = tag;
+ mCategory = category;
+ }
+
+ public boolean matches(String level, String tag) {
+ return mLevel.equals(level) && mTag.equals(tag);
+ }
+
+ public String getCategory() {
+ return mCategory;
+ }
+ }
}
diff --git a/tests/src/com/android/loganalysis/parser/JavaCrashParserTest.java b/tests/src/com/android/loganalysis/parser/JavaCrashParserTest.java
index 723633f..a7d06b3 100644
--- a/tests/src/com/android/loganalysis/parser/JavaCrashParserTest.java
+++ b/tests/src/com/android/loganalysis/parser/JavaCrashParserTest.java
@@ -124,4 +124,28 @@ public class JavaCrashParserTest extends TestCase {
assertEquals("This is the message", jc.getMessage());
assertEquals(ArrayUtil.join("\n", lines.subList(0, lines.size()-2)), jc.getStack());
}
+
+ /**
+ * Tests that only parts between the markers are parsed.
+ */
+ public void testParse_begin_end_markers() {
+ List<String> lines = Arrays.asList(
+ "error: this message has begin and end",
+ "----- begin exception -----",
+ "java.lang.Exception: This message",
+ "is many lines",
+ "long.",
+ "\tat class.method1(Class.java:1)",
+ "\tat class.method2(Class.java:2)",
+ "\tat class.method3(Class.java:3)",
+ "----- end exception -----");
+
+ JavaCrashItem jc = new JavaCrashParser().parse(lines);
+ assertNotNull(jc);
+ assertEquals("java.lang.Exception", jc.getException());
+ assertEquals("This message\nis many lines\nlong.", jc.getMessage());
+ assertNotNull(jc.getStack());
+ assertFalse(jc.getStack().contains("begin exception"));
+ assertFalse(jc.getStack().contains("end exception"));
+ }
}
diff --git a/tests/src/com/android/loganalysis/parser/LogcatParserTest.java b/tests/src/com/android/loganalysis/parser/LogcatParserTest.java
index 44f3151..9b6dff0 100644
--- a/tests/src/com/android/loganalysis/parser/LogcatParserTest.java
+++ b/tests/src/com/android/loganalysis/parser/LogcatParserTest.java
@@ -106,6 +106,86 @@ public class LogcatParserTest extends TestCase {
logcat.getJavaCrashes().get(0).getEventTime());
}
+ public void testParse_test_exception() throws ParseException {
+ List<String> lines = Arrays.asList(
+ "11-25 19:26:53.581 5832 7008 I TestRunner: ----- begin exception -----",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: ",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: java.util.concurrent.TimeoutException",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at android.support.test.uiautomator.WaitMixin.wait(WaitMixin.java:49)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at android.support.test.uiautomator.WaitMixin.wait(WaitMixin.java:36)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at android.support.test.uiautomator.UiDevice.wait(UiDevice.java:169)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at com.android.test.uiautomator.common.helpers.MapsHelper.doSearch(MapsHelper.java:87)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at com.android.test.uiautomator.aupt.MapsTest.testMaps(MapsTest.java:58)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at java.lang.reflect.Method.invoke(Native Method)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at java.lang.reflect.Method.invoke(Method.java:372)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:214)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:199)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at junit.framework.TestCase.runBare(TestCase.java:134)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at junit.framework.TestResult$1.protect(TestResult.java:115)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at junit.framework.TestResult.runProtected(TestResult.java:133)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at junit.framework.TestResult.run(TestResult.java:118)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at junit.framework.TestCase.run(TestCase.java:124)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at android.support.test.aupt.AuptTestRunner$AuptPrivateTestRunner.runTest(AuptTestRunner.java:182)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1848)",
+ "11-25 19:26:53.589 5832 7008 I TestRunner: ----- end exception -----"
+ );
+
+ LogcatParser logcatParser = new LogcatParser("2012");
+ logcatParser.addJavaCrashTag("I", "TestRunner", LogcatParser.JAVA_CRASH);
+ LogcatItem logcat = logcatParser.parse(lines);
+ assertNotNull(logcat);
+ assertEquals(1, logcat.getEvents().size());
+ assertEquals(1, logcat.getJavaCrashes().size());
+ assertEquals(5832, logcat.getJavaCrashes().get(0).getPid().intValue());
+ assertEquals(7008, logcat.getJavaCrashes().get(0).getTid().intValue());
+ assertEquals("", logcat.getJavaCrashes().get(0).getLastPreamble());
+ assertEquals("", logcat.getJavaCrashes().get(0).getProcessPreamble());
+ assertEquals(LogcatParser.JAVA_CRASH, logcat.getJavaCrashes().get(0).getCategory());
+ }
+
+ public void testParse_test_exception_with_exras() throws ParseException {
+ List<String> lines = Arrays.asList(
+ "12-06 17:19:18.746 6598 7960 I TestRunner: failed: testYouTube(com.android.test.uiautomator.aupt.YouTubeTest)",
+ "12-06 17:19:18.746 6598 7960 I TestRunner: ----- begin exception -----",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: ",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: java.util.concurrent.TimeoutException",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at android.support.test.uiautomator.WaitMixin.wait(WaitMixin.java:49)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at android.support.test.uiautomator.WaitMixin.wait(WaitMixin.java:36)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at android.support.test.uiautomator.UiDevice.wait(UiDevice.java:169)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at android.support.test.aupt.AppLauncher.launchApp(AppLauncher.java:127)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at com.android.test.uiautomator.common.helpers.YouTubeHelper.open(YouTubeHelper.java:49)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at com.android.test.uiautomator.aupt.YouTubeTest.setUp(YouTubeTest.java:44)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at junit.framework.TestCase.runBare(TestCase.java:132)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at junit.framework.TestResult$1.protect(TestResult.java:115)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at junit.framework.TestResult.runProtected(TestResult.java:133)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at junit.framework.TestResult.run(TestResult.java:118)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at junit.framework.TestCase.run(TestCase.java:124)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at android.support.test.aupt.AuptTestRunner$AuptPrivateTestRunner.runTest(AuptTestRunner.java:182)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1851)",
+ "12-06 17:19:18.747 6598 7960 I TestRunner: ----- end exception -----"
+ );
+
+ LogcatParser logcatParser = new LogcatParser("2012");
+ logcatParser.addJavaCrashTag("I", "TestRunner", LogcatParser.JAVA_CRASH);
+ LogcatItem logcat = logcatParser.parse(lines);
+ assertNotNull(logcat);
+ assertEquals(1, logcat.getEvents().size());
+ assertEquals(1, logcat.getJavaCrashes().size());
+ assertEquals(6598, logcat.getJavaCrashes().get(0).getPid().intValue());
+ assertEquals(7960, logcat.getJavaCrashes().get(0).getTid().intValue());
+ assertEquals("", logcat.getJavaCrashes().get(0).getLastPreamble());
+ assertEquals("", logcat.getJavaCrashes().get(0).getProcessPreamble());
+ // Check that lines not related to java crash are absent
+ assertFalse(logcat.getJavaCrashes().get(0).getStack().contains("begin exception"));
+ assertFalse(logcat.getJavaCrashes().get(0).getStack().contains("end exception"));
+ assertFalse(logcat.getJavaCrashes().get(0).getStack().contains("failed: testYouTube"));
+ //System.out.println(logcat.getJavaCrashes().get(0).getStack());
+ }
+
/**
* Test that Java crashes from system server can be parsed.
*/