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