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; 17 18 import com.android.loganalysis.item.BugreportItem; 19 import com.android.loganalysis.item.DvmLockSampleItem; 20 import com.android.loganalysis.item.IItem; 21 import com.android.loganalysis.item.KernelLogItem; 22 import com.android.loganalysis.item.LogcatItem; 23 import com.android.loganalysis.item.MemoryHealthItem; 24 import com.android.loganalysis.item.MonkeyLogItem; 25 import com.android.loganalysis.parser.BugreportParser; 26 import com.android.loganalysis.parser.DvmLockSampleParser; 27 import com.android.loganalysis.parser.KernelLogParser; 28 import com.android.loganalysis.parser.LogcatParser; 29 import com.android.loganalysis.parser.MemoryHealthParser; 30 import com.android.loganalysis.parser.MonkeyLogParser; 31 import com.android.loganalysis.rule.RuleEngine; 32 import com.android.loganalysis.rule.RuleEngine.RuleType; 33 import com.android.loganalysis.util.config.ArgsOptionParser; 34 import com.android.loganalysis.util.config.ConfigurationException; 35 import com.android.loganalysis.util.config.Option; 36 37 import org.json.JSONArray; 38 import org.json.JSONException; 39 import org.json.JSONObject; 40 41 import java.io.BufferedReader; 42 import java.io.Closeable; 43 import java.io.File; 44 import java.io.FileNotFoundException; 45 import java.io.FileReader; 46 import java.io.IOException; 47 48 import java.util.ArrayList; 49 import java.util.List; 50 51 /** 52 * A command line tool to parse a bugreport, logcat, or kernel log file and return the output. 53 */ 54 public class LogAnalyzer { 55 56 private enum OutputFormat{ 57 // TODO: Add text output support. 58 JSON; 59 } 60 61 private enum ResultType { 62 RAW, ANALYSIS; 63 } 64 65 @Option(name="bugreport", description="The path to the bugreport") 66 private String mBugreportPath = null; 67 68 @Option(name="logcat", description="The path to the logcat") 69 private String mLogcatPath = null; 70 71 @Option(name="kernel-log", description="The path to the kernel log") 72 private String mKernelLogPath = null; 73 74 @Option(name="monkey-log", description="The path to the monkey log") 75 private String mMonkeyLogPath = null; 76 77 @Option(name="memory-health", description="The path to the memory health log") 78 private String mMemoryHealthLogPath = null; 79 80 @Option(name="output", description="The output format, currently only JSON") 81 private OutputFormat mOutputFormat = OutputFormat.JSON; 82 83 @Option(name="rule-type", description="The type of rules to be applied") 84 private RuleType mRuleType = RuleType.ALL; 85 86 @Option(name="print", description="Print the result type") 87 private List<ResultType> mResultType = new ArrayList<ResultType>(); 88 89 @Option(name="events-log", description="The path to the events log") 90 private String mEventsLogPath = null; 91 92 /** Constant for JSON output */ 93 private static final String RAW_DATA = "RAW"; 94 /** Constant for JSON output */ 95 private static final String ANALYSIS_DATA = "ANALYSIS"; 96 97 /** 98 * Run the command line tool 99 */ run(String[] args)100 public void run(String[] args) { 101 try { 102 initArgs(args); 103 } catch (ConfigurationException e) { 104 printUsage(); 105 return; 106 } 107 108 if (!checkPreconditions()) { 109 printUsage(); 110 return; 111 } 112 113 BufferedReader reader = null; 114 try { 115 if (mBugreportPath != null) { 116 reader = getBufferedReader(mBugreportPath); 117 BugreportItem bugreport = new BugreportParser().parse(reader); 118 printBugreport(bugreport); 119 return; 120 } 121 122 if (mLogcatPath != null) { 123 reader = getBufferedReader(mLogcatPath); 124 LogcatItem logcat = new LogcatParser().parse(reader); 125 printLogcat(logcat); 126 return; 127 } 128 129 if (mKernelLogPath != null) { 130 reader = getBufferedReader(mKernelLogPath); 131 KernelLogItem kernelLog = new KernelLogParser().parse(reader); 132 printKernelLog(kernelLog); 133 return; 134 } 135 136 if (mMonkeyLogPath != null) { 137 reader = getBufferedReader(mMonkeyLogPath); 138 MonkeyLogItem monkeyLog = new MonkeyLogParser().parse(reader); 139 printMonkeyLog(monkeyLog); 140 return; 141 } 142 143 if (mMemoryHealthLogPath != null) { 144 reader = getBufferedReader(mMemoryHealthLogPath); 145 MemoryHealthItem item = new MemoryHealthParser().parse(reader); 146 printMemoryHealthLog(item); 147 return; 148 } 149 150 if (mEventsLogPath != null) { 151 reader = getBufferedReader(mEventsLogPath); 152 153 // The only log we know how to parse in the Events log are 154 // DVM lock samples. 155 DvmLockSampleItem item = new DvmLockSampleParser().parse(reader); 156 printDVMLog(item); 157 return; 158 } 159 } catch (FileNotFoundException e) { 160 System.err.println(e.getMessage()); 161 } catch (IOException e) { 162 System.err.println(e.getMessage()); 163 } finally { 164 close(reader); 165 } 166 167 // Should never reach here. 168 printUsage(); 169 } 170 printMemoryHealthLog(MemoryHealthItem item)171 private void printMemoryHealthLog(MemoryHealthItem item) { 172 System.out.println(item.toJson().toString()); 173 } 174 175 /** 176 * Print the bugreport to stdout. 177 */ printBugreport(BugreportItem bugreport)178 private void printBugreport(BugreportItem bugreport) { 179 if (OutputFormat.JSON.equals(mOutputFormat)) { 180 if (mResultType.size() == 0) { 181 printJson(bugreport); 182 } else if (mResultType.size() == 1) { 183 switch (mResultType.get(0)) { 184 case RAW: 185 printJson(bugreport); 186 break; 187 case ANALYSIS: 188 printBugreportAnalysis(getBugreportAnalysis(bugreport)); 189 break; 190 default: 191 // should not get here 192 return; 193 } 194 } else { 195 JSONObject result = new JSONObject(); 196 try { 197 for (ResultType resultType : mResultType) { 198 switch (resultType) { 199 case RAW: 200 result.put(RAW_DATA, bugreport.toJson()); 201 break; 202 case ANALYSIS: 203 result.put(ANALYSIS_DATA, getBugreportAnalysis(bugreport)); 204 break; 205 default: 206 // should not get here 207 break; 208 } 209 } 210 } catch (JSONException e) { 211 // Ignore 212 } 213 printJson(result); 214 } 215 } 216 } 217 getBugreportAnalysis(BugreportItem bugreport)218 private JSONArray getBugreportAnalysis(BugreportItem bugreport) { 219 RuleEngine ruleEngine = new RuleEngine(bugreport); 220 ruleEngine.registerRules(mRuleType); 221 ruleEngine.executeRules(); 222 if (ruleEngine.getAnalysis() != null) { 223 return ruleEngine.getAnalysis(); 224 } else { 225 return new JSONArray(); 226 } 227 } 228 printBugreportAnalysis(JSONArray analysis)229 private void printBugreportAnalysis(JSONArray analysis) { 230 if (analysis != null && analysis.length() > 0) { 231 System.out.println(analysis.toString()); 232 } else { 233 System.out.println(new JSONObject().toString()); 234 } 235 } 236 237 /** 238 * Print the logcat to stdout. 239 */ printLogcat(LogcatItem logcat)240 private void printLogcat(LogcatItem logcat) { 241 if (OutputFormat.JSON.equals(mOutputFormat)) { 242 printJson(logcat); 243 } 244 // TODO: Print logcat in human readable form. 245 } 246 247 /** 248 * Print the kernel log to stdout. 249 */ printKernelLog(KernelLogItem kernelLog)250 private void printKernelLog(KernelLogItem kernelLog) { 251 if (OutputFormat.JSON.equals(mOutputFormat)) { 252 printJson(kernelLog); 253 } 254 // TODO: Print kernel log in human readable form. 255 } 256 257 /** 258 * Print the monkey log to stdout. 259 */ printMonkeyLog(MonkeyLogItem monkeyLog)260 private void printMonkeyLog(MonkeyLogItem monkeyLog) { 261 if (OutputFormat.JSON.equals(mOutputFormat)) { 262 printJson(monkeyLog); 263 } 264 // TODO: Print monkey log in human readable form. 265 } 266 267 /** 268 * Print a DVM log entry to stdout. 269 */ printDVMLog(DvmLockSampleItem dvmLog)270 private void printDVMLog(DvmLockSampleItem dvmLog) { 271 if (OutputFormat.JSON.equals(mOutputFormat)) { 272 printJson(dvmLog); 273 } 274 // TODO: Print DVM log in human readable form. 275 } 276 277 /** 278 * Print an {@link IItem} to stdout. 279 */ printJson(IItem item)280 private void printJson(IItem item) { 281 if (item != null && item.toJson() != null) { 282 printJson(item.toJson()); 283 } else { 284 printJson(new JSONObject()); 285 } 286 } 287 288 /** 289 * Print an {@link JSONObject} to stdout 290 */ printJson(JSONObject json)291 private void printJson(JSONObject json) { 292 if (json != null) { 293 System.out.println(json.toString()); 294 } else { 295 System.out.println(new JSONObject().toString()); 296 } 297 } 298 299 /** 300 * Get a {@link BufferedReader} from a given filepath. 301 * @param filepath the path to the file. 302 * @return The {@link BufferedReader} containing the contents of the file. 303 * @throws FileNotFoundException if the file could not be found. 304 */ getBufferedReader(String filepath)305 private BufferedReader getBufferedReader(String filepath) throws FileNotFoundException { 306 return new BufferedReader(new FileReader(new File(filepath))); 307 } 308 309 /** 310 * Helper to close a {@link Closeable}. 311 */ close(Closeable closeable)312 private void close(Closeable closeable) { 313 if (closeable != null) { 314 try { 315 closeable.close(); 316 } catch (IOException e) { 317 // Ignore 318 } 319 } 320 } 321 322 /** 323 * Parse the command line options and set {@link Option} annotated fields. 324 */ initArgs(String[] args)325 private void initArgs(String[] args) throws ConfigurationException { 326 ArgsOptionParser opt = new ArgsOptionParser(this); 327 opt.parse(args); 328 } 329 330 /** 331 * Checks the arguments to see if they are valid. 332 * 333 * @return true if they are valid, false if they are not. 334 */ checkPreconditions()335 private boolean checkPreconditions() { 336 // Check to see that exactly one log is set. 337 int logCount = 0; 338 if (mBugreportPath != null) logCount++; 339 if (mLogcatPath != null) logCount++; 340 if (mKernelLogPath != null) logCount++; 341 if (mMonkeyLogPath != null) logCount++; 342 if (mMemoryHealthLogPath != null) logCount++; 343 return (logCount == 1); 344 } 345 346 /** 347 * Print the usage for the command. 348 */ printUsage()349 private void printUsage() { 350 System.err.println("Usage: loganalysis [--bugreport FILE | --events-log FILE | --logcat FILE | " + 351 "--kernel-log FILE | --monkey-log FILE]"); 352 } 353 354 /** 355 * Run the LogAnalyzer from the command line. 356 */ main(String[] args)357 public static void main(String[] args) { 358 LogAnalyzer analyzer = new LogAnalyzer(); 359 analyzer.run(args); 360 } 361 } 362