/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.loganalysis; import com.android.loganalysis.item.BugreportItem; import com.android.loganalysis.item.DvmLockSampleItem; import com.android.loganalysis.item.IItem; import com.android.loganalysis.item.KernelLogItem; import com.android.loganalysis.item.LogcatItem; import com.android.loganalysis.item.MemoryHealthItem; import com.android.loganalysis.item.MonkeyLogItem; import com.android.loganalysis.parser.BugreportParser; import com.android.loganalysis.parser.DvmLockSampleParser; import com.android.loganalysis.parser.KernelLogParser; import com.android.loganalysis.parser.LogcatParser; import com.android.loganalysis.parser.MemoryHealthParser; import com.android.loganalysis.parser.MonkeyLogParser; import com.android.loganalysis.rule.RuleEngine; import com.android.loganalysis.rule.RuleEngine.RuleType; import com.android.loganalysis.util.config.ArgsOptionParser; import com.android.loganalysis.util.config.ConfigurationException; import com.android.loganalysis.util.config.Option; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.Closeable; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * A command line tool to parse a bugreport, logcat, or kernel log file and return the output. */ public class LogAnalyzer { private enum OutputFormat{ // TODO: Add text output support. JSON; } private enum ResultType { RAW, ANALYSIS; } @Option(name="bugreport", description="The path to the bugreport") private String mBugreportPath = null; @Option(name="logcat", description="The path to the logcat") private String mLogcatPath = null; @Option(name="kernel-log", description="The path to the kernel log") private String mKernelLogPath = null; @Option(name="monkey-log", description="The path to the monkey log") private String mMonkeyLogPath = null; @Option(name="memory-health", description="The path to the memory health log") private String mMemoryHealthLogPath = null; @Option(name="output", description="The output format, currently only JSON") private OutputFormat mOutputFormat = OutputFormat.JSON; @Option(name="rule-type", description="The type of rules to be applied") private RuleType mRuleType = RuleType.ALL; @Option(name="print", description="Print the result type") private List mResultType = new ArrayList(); @Option(name="events-log", description="The path to the events log") private String mEventsLogPath = null; /** Constant for JSON output */ private static final String RAW_DATA = "RAW"; /** Constant for JSON output */ private static final String ANALYSIS_DATA = "ANALYSIS"; /** * Run the command line tool */ public void run(String[] args) { try { initArgs(args); } catch (ConfigurationException e) { printUsage(); return; } if (!checkPreconditions()) { printUsage(); return; } BufferedReader reader = null; try { if (mBugreportPath != null) { reader = getBufferedReader(mBugreportPath); BugreportItem bugreport = new BugreportParser().parse(reader); printBugreport(bugreport); return; } if (mLogcatPath != null) { reader = getBufferedReader(mLogcatPath); LogcatItem logcat = new LogcatParser().parse(reader); printLogcat(logcat); return; } if (mKernelLogPath != null) { reader = getBufferedReader(mKernelLogPath); KernelLogItem kernelLog = new KernelLogParser().parse(reader); printKernelLog(kernelLog); return; } if (mMonkeyLogPath != null) { reader = getBufferedReader(mMonkeyLogPath); MonkeyLogItem monkeyLog = new MonkeyLogParser().parse(reader); printMonkeyLog(monkeyLog); return; } if (mMemoryHealthLogPath != null) { reader = getBufferedReader(mMemoryHealthLogPath); MemoryHealthItem item = new MemoryHealthParser().parse(reader); printMemoryHealthLog(item); return; } if (mEventsLogPath != null) { reader = getBufferedReader(mEventsLogPath); // The only log we know how to parse in the Events log are // DVM lock samples. DvmLockSampleItem item = new DvmLockSampleParser().parse(reader); printDVMLog(item); return; } } catch (FileNotFoundException e) { System.err.println(e.getMessage()); } catch (IOException e) { System.err.println(e.getMessage()); } finally { close(reader); } // Should never reach here. printUsage(); } private void printMemoryHealthLog(MemoryHealthItem item) { System.out.println(item.toJson().toString()); } /** * Print the bugreport to stdout. */ private void printBugreport(BugreportItem bugreport) { if (OutputFormat.JSON.equals(mOutputFormat)) { if (mResultType.size() == 0) { printJson(bugreport); } else if (mResultType.size() == 1) { switch (mResultType.get(0)) { case RAW: printJson(bugreport); break; case ANALYSIS: printBugreportAnalysis(getBugreportAnalysis(bugreport)); break; default: // should not get here return; } } else { JSONObject result = new JSONObject(); try { for (ResultType resultType : mResultType) { switch (resultType) { case RAW: result.put(RAW_DATA, bugreport.toJson()); break; case ANALYSIS: result.put(ANALYSIS_DATA, getBugreportAnalysis(bugreport)); break; default: // should not get here break; } } } catch (JSONException e) { // Ignore } printJson(result); } } } private JSONArray getBugreportAnalysis(BugreportItem bugreport) { RuleEngine ruleEngine = new RuleEngine(bugreport); ruleEngine.registerRules(mRuleType); ruleEngine.executeRules(); if (ruleEngine.getAnalysis() != null) { return ruleEngine.getAnalysis(); } else { return new JSONArray(); } } private void printBugreportAnalysis(JSONArray analysis) { if (analysis != null && analysis.length() > 0) { System.out.println(analysis.toString()); } else { System.out.println(new JSONObject().toString()); } } /** * Print the logcat to stdout. */ private void printLogcat(LogcatItem logcat) { if (OutputFormat.JSON.equals(mOutputFormat)) { printJson(logcat); } // TODO: Print logcat in human readable form. } /** * Print the kernel log to stdout. */ private void printKernelLog(KernelLogItem kernelLog) { if (OutputFormat.JSON.equals(mOutputFormat)) { printJson(kernelLog); } // TODO: Print kernel log in human readable form. } /** * Print the monkey log to stdout. */ private void printMonkeyLog(MonkeyLogItem monkeyLog) { if (OutputFormat.JSON.equals(mOutputFormat)) { printJson(monkeyLog); } // TODO: Print monkey log in human readable form. } /** * Print a DVM log entry to stdout. */ private void printDVMLog(DvmLockSampleItem dvmLog) { if (OutputFormat.JSON.equals(mOutputFormat)) { printJson(dvmLog); } // TODO: Print DVM log in human readable form. } /** * Print an {@link IItem} to stdout. */ private void printJson(IItem item) { if (item != null && item.toJson() != null) { printJson(item.toJson()); } else { printJson(new JSONObject()); } } /** * Print an {@link JSONObject} to stdout */ private void printJson(JSONObject json) { if (json != null) { System.out.println(json.toString()); } else { System.out.println(new JSONObject().toString()); } } /** * Get a {@link BufferedReader} from a given filepath. * @param filepath the path to the file. * @return The {@link BufferedReader} containing the contents of the file. * @throws FileNotFoundException if the file could not be found. */ private BufferedReader getBufferedReader(String filepath) throws FileNotFoundException { return new BufferedReader(new FileReader(new File(filepath))); } /** * Helper to close a {@link Closeable}. */ private void close(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (IOException e) { // Ignore } } } /** * Parse the command line options and set {@link Option} annotated fields. */ private void initArgs(String[] args) throws ConfigurationException { ArgsOptionParser opt = new ArgsOptionParser(this); opt.parse(args); } /** * Checks the arguments to see if they are valid. * * @return true if they are valid, false if they are not. */ private boolean checkPreconditions() { // Check to see that exactly one log is set. int logCount = 0; if (mBugreportPath != null) logCount++; if (mLogcatPath != null) logCount++; if (mKernelLogPath != null) logCount++; if (mMonkeyLogPath != null) logCount++; if (mMemoryHealthLogPath != null) logCount++; return (logCount == 1); } /** * Print the usage for the command. */ private void printUsage() { System.err.println("Usage: loganalysis [--bugreport FILE | --events-log FILE | --logcat FILE | " + "--kernel-log FILE | --monkey-log FILE]"); } /** * Run the LogAnalyzer from the command line. */ public static void main(String[] args) { LogAnalyzer analyzer = new LogAnalyzer(); analyzer.run(args); } }