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