1 /* 2 * Copyright (C) 2013 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 package com.android.loganalysis.parser; 17 18 import com.android.loganalysis.item.SmartMonkeyLogItem; 19 20 import java.io.BufferedReader; 21 import java.io.IOException; 22 import java.text.ParseException; 23 import java.text.SimpleDateFormat; 24 import java.util.Date; 25 import java.util.List; 26 import java.util.regex.Matcher; 27 import java.util.regex.Pattern; 28 29 /** 30 * A {@link IParser} to parse monkey logs. 31 */ 32 public class SmartMonkeyLogParser implements IParser { 33 34 private static final String TIME_STAMP_GROUP = 35 "^(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}.\\d{3}): "; 36 private static final String INVOKE_NUM_GROUP = "\\[.*?(\\d+)\\]"; 37 private static final String SEQ_NUM_GROUP = "\\(Seq:.*?(\\d+)\\)"; 38 39 private static final Pattern START_TIME = Pattern.compile( 40 TIME_STAMP_GROUP + "Starting.*"); 41 42 private static final Pattern START_UPTIME = Pattern.compile( 43 TIME_STAMP_GROUP + "Device uptime: (\\d+) sec$"); 44 45 private static final Pattern STOP_UPTIME = Pattern.compile( 46 TIME_STAMP_GROUP + "Device uptime: (\\d+) sec, Monkey run duration: (\\d+) sec$"); 47 48 private static final Pattern THROTTLE = Pattern.compile( 49 TIME_STAMP_GROUP + "Throttle: (\\d+).*"); 50 51 private static final Pattern TARGET_INVOCATIONS = Pattern.compile( 52 TIME_STAMP_GROUP + "Target invocation count: (\\d+)"); 53 54 private static final Pattern INTERMEDIATE_COUNT = Pattern.compile( 55 TIME_STAMP_GROUP + INVOKE_NUM_GROUP + SEQ_NUM_GROUP + ".*"); 56 57 private static final Pattern INTERMEDIATE_TIME = Pattern.compile(TIME_STAMP_GROUP + ".*"); 58 59 private static final Pattern FINISHED = Pattern.compile( 60 TIME_STAMP_GROUP + "Monkey finished"); 61 62 private static final Pattern FINAL_COUNT = Pattern.compile( 63 TIME_STAMP_GROUP + "Invocations completed: (\\d+)"); 64 65 private static final Pattern APPS_PACKAGES = Pattern.compile( 66 TIME_STAMP_GROUP + "Starting \\[(.*)\\]\\[(.*)\\]"); 67 68 private static final Pattern ABORTED = Pattern.compile( 69 TIME_STAMP_GROUP + "Monkey aborted."); 70 71 private static final Pattern UI_ANR = Pattern.compile( 72 TIME_STAMP_GROUP + INVOKE_NUM_GROUP + SEQ_NUM_GROUP + "-UI Exception: ANR: (.*)"); 73 74 private static final Pattern UI_CRASH = Pattern.compile( 75 TIME_STAMP_GROUP + INVOKE_NUM_GROUP + SEQ_NUM_GROUP + "-UI Exception: CRASH: (.*)"); 76 77 private final SmartMonkeyLogItem mSmartMonkeyLog = new SmartMonkeyLogItem(); 78 79 /** 80 * Parse a monkey log from a {@link BufferedReader} into an {@link SmartMonkeyLogItem} 81 * object. 82 * 83 * @param input a {@link BufferedReader}. 84 * @return The {@link SmartMonkeyLogItem}. 85 * @see #parse(List) 86 */ parse(BufferedReader input)87 public SmartMonkeyLogItem parse(BufferedReader input) throws IOException { 88 String line; 89 while ((line = input.readLine()) != null) { 90 parseLine(line); 91 } 92 return mSmartMonkeyLog; 93 } 94 95 /** 96 * {@inheritDoc} 97 * 98 * @return The {@link SmartMonkeyLogItem}. 99 */ 100 @Override parse(List<String> lines)101 public SmartMonkeyLogItem parse(List<String> lines) { 102 for (String line : lines) { 103 parseLine(line); 104 } 105 106 if (mSmartMonkeyLog.getStopUptimeDuration() == 0) 107 mSmartMonkeyLog.setIsFinished(false); 108 else 109 mSmartMonkeyLog.setIsFinished(true); 110 111 return mSmartMonkeyLog; 112 } 113 114 /** 115 * Parse a line of input. 116 */ parseLine(String line)117 private void parseLine(String line) { 118 Matcher m = THROTTLE.matcher(line); 119 if (m.matches()) { 120 mSmartMonkeyLog.setThrottle(Integer.parseInt(m.group(2))); 121 } 122 m = TARGET_INVOCATIONS.matcher(line); 123 if (m.matches()) { 124 mSmartMonkeyLog.setTargetInvocations(Integer.parseInt(m.group(2))); 125 } 126 m = APPS_PACKAGES.matcher(line); 127 if (m.matches()) { 128 String apps = m.group(2); 129 String packages = m.group(3); 130 131 String[] appsArray = apps.split("\\|"); 132 for (String a : appsArray) { 133 mSmartMonkeyLog.addApplication(a); 134 } 135 136 String[] pkgsArray = packages.split("\\|"); 137 for (String p : pkgsArray) { 138 mSmartMonkeyLog.addPackage(p); 139 } 140 } 141 m = INTERMEDIATE_COUNT.matcher(line); 142 if (m.matches()) { 143 mSmartMonkeyLog.setIntermediateCount(Integer.parseInt(m.group(2))); 144 } 145 m = START_TIME.matcher(line); 146 if (m.matches()) { 147 mSmartMonkeyLog.setStartTime(parseTime(m.group(1))); 148 } 149 m = START_UPTIME.matcher(line); 150 if (m.matches()) { 151 mSmartMonkeyLog.setStartUptimeDuration(Long.parseLong(m.group(2))); 152 } 153 m = STOP_UPTIME.matcher(line); 154 if (m.matches()) { 155 mSmartMonkeyLog.setStopTime(parseTime(m.group(1))); 156 mSmartMonkeyLog.setStopUptimeDuration(Long.parseLong(m.group(2))); 157 mSmartMonkeyLog.setTotalDuration(Long.parseLong(m.group(3))); 158 } 159 m = INTERMEDIATE_TIME.matcher(line); 160 if (m.matches()) { 161 mSmartMonkeyLog.setIntermediateTime(parseTime(m.group(1))); 162 } 163 m = FINAL_COUNT.matcher(line); 164 if (m.matches()) { 165 mSmartMonkeyLog.setFinalCount(Integer.parseInt(m.group(2))); 166 } 167 m = FINISHED.matcher(line); 168 if (m.matches()) { 169 mSmartMonkeyLog.setIsFinished(true); 170 } 171 m = ABORTED.matcher(line); 172 if (m.matches()) { 173 mSmartMonkeyLog.setIsAborted(true); 174 } 175 m = UI_CRASH.matcher(line); 176 if (m.matches()) { 177 mSmartMonkeyLog.addCrashTime(parseTime(m.group(1))); 178 } 179 m = UI_ANR.matcher(line); 180 if (m.matches()) { 181 mSmartMonkeyLog.addAnrTime(parseTime(m.group(1))); 182 } 183 } 184 185 /** 186 * Parse the timestamp and return a date. 187 * 188 * @param timeStr The timestamp in the format {@code yyyy-MM-dd HH:mm:ss.SSS} 189 * @return The {@link Date}. 190 */ parseTime(String timeStr)191 public static Date parseTime(String timeStr) { 192 try { 193 return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(timeStr); 194 } catch (ParseException e) { 195 } 196 return null; 197 } 198 199 } 200