1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.loganalysis.parser; 18 19 import com.android.loganalysis.item.JavaCrashItem; 20 21 import java.util.List; 22 import java.util.regex.Matcher; 23 import java.util.regex.Pattern; 24 25 /** 26 * An {@link IParser} to handle Java crashes. 27 */ 28 public class JavaCrashParser implements IParser { 29 30 /** 31 * Matches: java.lang.Exception 32 * Matches: java.lang.Exception: reason 33 */ 34 private static final Pattern EXCEPTION = Pattern.compile("^([^\\s:]+)(: (.*))?$"); 35 /** 36 * Matches: Caused by: java.lang.Exception 37 */ 38 private static final Pattern CAUSEDBY = Pattern.compile("^Caused by: .+$"); 39 /** 40 * Matches: \tat class.method(Class.java:1) 41 */ 42 private static final Pattern AT = Pattern.compile("^\tat .+$"); 43 44 // Sometimes logcat explicitly marks where exception begins and ends 45 private static final String BEGIN_MARKER = "----- begin exception -----"; 46 private static final String END_MARKER = "----- end exception -----"; 47 48 /** 49 * {@inheritDoc} 50 * 51 * @return The {@link JavaCrashItem}. 52 */ 53 @Override parse(List<String> lines)54 public JavaCrashItem parse(List<String> lines) { 55 JavaCrashItem jc = null; 56 StringBuilder stack = new StringBuilder(); 57 StringBuilder message = new StringBuilder(); 58 boolean inMessage = false; 59 boolean inCausedBy = false; 60 boolean inStack = false; 61 62 for (String line : lines) { 63 if (line.contains(BEGIN_MARKER)) { 64 inMessage = false; 65 inCausedBy = false; 66 inStack = false; 67 stack = new StringBuilder(); 68 message = new StringBuilder(); 69 jc = null; 70 continue; 71 } 72 if (line.contains(END_MARKER)) { 73 break; 74 } 75 if (!inStack) { 76 Matcher exceptionMatch = EXCEPTION.matcher(line); 77 if (exceptionMatch.matches()) { 78 inMessage = true; 79 inStack = true; 80 81 jc = new JavaCrashItem(); 82 jc.setException(exceptionMatch.group(1)); 83 if (exceptionMatch.group(3) != null) { 84 message.append(exceptionMatch.group(3)); 85 } 86 } 87 } else { 88 // Match: Caused by: java.lang.Exception 89 Matcher causedByMatch = CAUSEDBY.matcher(line); 90 if (causedByMatch.matches()) { 91 inMessage = false; 92 inCausedBy = true; 93 } 94 95 // Match: \tat class.method(Class.java:1) 96 Matcher atMatch = AT.matcher(line); 97 if (atMatch.matches()) { 98 inMessage = false; 99 inCausedBy = false; 100 } 101 102 if (!causedByMatch.matches() && !atMatch.matches()) { 103 if (inMessage) { 104 message.append("\n"); 105 message.append(line); 106 } 107 if (!inMessage && !inCausedBy) { 108 addMessageStack(jc, message.toString(), stack.toString()); 109 return jc; 110 } 111 } 112 } 113 114 if (inStack) { 115 stack.append(line); 116 stack.append("\n"); 117 } 118 } 119 120 addMessageStack(jc, message.toString(), stack.toString()); 121 return jc; 122 } 123 124 /** 125 * Adds the message and stack to the {@link JavaCrashItem}. 126 */ addMessageStack(JavaCrashItem jc, String message, String stack)127 private void addMessageStack(JavaCrashItem jc, String message, String stack) { 128 if (jc != null) { 129 if (message.length() > 0) { 130 jc.setMessage(message); 131 } 132 jc.setStack(stack.trim()); 133 } 134 } 135 } 136 137