You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ji...@apache.org on 2019/08/28 03:02:00 UTC

[incubator-iotdb] branch log_tool updated: add comments

This is an automated email from the ASF dual-hosted git repository.

jiangtian pushed a commit to branch log_tool
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git


The following commit(s) were added to refs/heads/log_tool by this push:
     new 22b29d6  add comments
22b29d6 is described below

commit 22b29d63d6767c37a2470ac5a505f5b69c9d6caf
Author: jt <jt...@163.com>
AuthorDate: Wed Aug 28 10:52:08 2019 +0800

    add comments
---
 .../resources/tools/logAnalyze/default.log.pattern |  12 +-
 .../logAnalyze/plans/flushTimeConsumption.plan     |  23 +++-
 .../apache/iotdb/db/tools/logvisual/LogEntry.java  |  41 ++++++
 .../apache/iotdb/db/tools/logvisual/LogFilter.java |  53 +++++---
 .../apache/iotdb/db/tools/logvisual/LogParser.java |  11 ++
 .../iotdb/db/tools/logvisual/LogVisualizer.java    | 141 +++++++++++++--------
 .../iotdb/db/tools/logvisual/PatternLogParser.java |  12 ++
 .../db/tools/logvisual/TimeSeriesStatistics.java   |  27 +---
 .../iotdb/db/tools/logvisual/VisualUtils.java      |   6 +-
 .../db/tools/logvisual/VisualizationPlan.java      |  35 ++++-
 .../db/tools/logvisual/conf/PropertyKeys.java      |  18 ++-
 .../db/tools/logvisual/gui/ClosableComboTab.java   |   7 +-
 .../iotdb/db/tools/logvisual/gui/ClosableTab.java  |   5 +-
 .../db/tools/logvisual/gui/FileSelectionBox.java   |  13 +-
 .../db/tools/logvisual/gui/LabeledComboBox.java    |   8 +-
 .../iotdb/db/tools/logvisual/gui/LoadLogBox.java   |  29 +++--
 ...gVisualizeGui.java => LogVisualizationGui.java} |  46 ++++++-
 .../iotdb/db/tools/logvisual/gui/MainPanel.java    |  30 ++++-
 .../iotdb/db/tools/logvisual/gui/PlanBox.java      |  35 ++++-
 .../db/tools/logvisual/gui/PlanDetailPanel.java    |  23 +++-
 .../db/tools/logvisual/gui/ResultPlotTab.java      |   4 +
 .../db/tools/logvisual/gui/ResultStatisticTab.java |  10 +-
 22 files changed, 427 insertions(+), 162 deletions(-)

diff --git a/server/src/assembly/resources/tools/logAnalyze/default.log.pattern b/server/src/assembly/resources/tools/logAnalyze/default.log.pattern
index 9cf7f9f..57fdf42 100644
--- a/server/src/assembly/resources/tools/logAnalyze/default.log.pattern
+++ b/server/src/assembly/resources/tools/logAnalyze/default.log.pattern
@@ -17,10 +17,20 @@
 # under the License.
 #
 
+# Pattern defines how a log looks like. A log must be exactly one line.
 pattern=([^\\[]*)(\\[.*])(\\s\\w+\\s)([^:]*:\\d+)(\\s-\\s)(.*)
+# The index of the group which represents the date that the log is generated, one based
 date_index=1
+# How the date is formatted
+date_pattern=yyyy-MM-dd hh:mm:ss,SSS
+# The index of the group which represents the thread name, one based
 thread_name_index=2
+# The index of the group which represents the log level, one based
 level_index=3
+# The index of the group which represents the position of the code (class name and line number)
+# that generated the log, one based
 code_location_index=4
+# The index of the group which represents the message in the log, one based
 content_index=6
-date_pattern=yyyy-MM-dd hh:mm:ss,SSS
+
+
diff --git a/server/src/assembly/resources/tools/logAnalyze/plans/flushTimeConsumption.plan b/server/src/assembly/resources/tools/logAnalyze/plans/flushTimeConsumption.plan
index ccf1b11..d88232d 100644
--- a/server/src/assembly/resources/tools/logAnalyze/plans/flushTimeConsumption.plan
+++ b/server/src/assembly/resources/tools/logAnalyze/plans/flushTimeConsumption.plan
@@ -17,19 +17,34 @@
 # under the License.
 #
 
+# the name of the this plan
 name=flushTimeConsumption
-content_pattern=Storage group (.*) memtable (.*) flushing a memtable has finished! Time consumption: (\\d+)ms
+# how are the targeted logs formatted and what fields are interesting and should be grouped
+content_pattern=Storage group (.*) memtable (.*) flushing a memtable has finished! Time consumption: (.*)ms
 
-# if you add more, use comma to separate
+# the following 3 properties are all one-based, if there are more than one measurements or tags, use
+# comma to separate the positions
+# the position of the groups in the pattern that will be plotted as values, must be real values
 measurement_positions=3
+# the name of each measurement
 legends=Time
+# the position of the groups in the pattern that will be used to group the logs, each log group will
+# be plotted separately
 tag_positions=1
 
-# min_level=info
-# thread_name_white_list=pool-1-IoTDB-JDBC-CLient-thread-5
+# only logs with levels higher or equal to this will be visualized, one of DEBUG,INFO,WARN,ERROR
+# min_level=INFO
+# only logs whose threads are in the list will be visualized, comma separated
+# thread_name_white_list=pool-1-IoTDB-JDBC-Client-thread-5
+# only logs whose classes are in the list will be visualized, comma separated
 # class_name_white_list=org.apache.iotdb.db.engine.storagegroup.StorageGroupProcessor
+# only logs whose line numbers are in the list will be visualized, comma separated
 # line_num_white_list=392
 
+# the pattern of start_date and end_date, only after this is set will start_date and end_date become
+# valid
 date_pattern=yyyy-MM-dd hh:mm:ss
+# only logs generated within [start_date, end_date] will be visualized and the dates must be
+# parsable by date_pattern
 start_date=2019-08-21 09:00:00
 end_date=2019-08-22 09:00:00
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogEntry.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogEntry.java
index 18b7634..8d8e1df 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogEntry.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogEntry.java
@@ -4,17 +4,58 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
+/**
+ * LogEntry is a parsed log event.
+ * We will take the log:
+ *  "2019-08-21 09:57:16,552 [pool-4-IoTDB-Flush-ServerServiceImpl-thread-4] INFO  org.apache
+ *  .iotdb.db.engine.flush.MemTableFlushTask:95 - Storage group root.perform.group_6 memtable org
+ *  .apache.iotdb.db.engine.memtable.PrimitiveMemTable@66 flushing a memtable has finished! Time
+ *  consumption: 9942ms"
+ *  as a running example.
+ */
 public class LogEntry {
 
+  // if a visualization plan has no tag, this tag will be the tag of all events
   private static List<String> DEFAULT_TAG = Collections.EMPTY_LIST;
 
+  /**
+   * The time when the log is logged.
+   * "2019-08-21 09:57:16,552" in the example.
+   */
   private Date date;
+  /**
+   * The name of the thread which has written the log.
+   *  "pool-4-IoTDB-Flush-ServerServiceImpl-thread-4" in the example.
+   */
   private String threadName;
+  /**
+   * The level of the log, one of "DEBUG", "INFO", "WARN", "ERROR".
+   * "INFO" in the example.
+   */
   private LogLevel logLevel;
+  /**
+   * The class and line of code that generated this log.
+   * "org.apache.iotdb.db.engine.flush.MemTableFlushTask:95" in the example.
+   */
   private CodeLocation codeLocation;
+  /**
+   * The message contained in the log.
+   *  "Storage group root.perform.group_6 memtable org
+   *  .apache.iotdb.db.engine.memtable.PrimitiveMemTable@66 flushing a memtable has finished! Time
+   *  consumption: 9942ms" in the example.
+   */
   private String logContent;
 
+  /**
+   * tags are a list of strings cut out of the logContent to group the logs into different groups.
+   * This is specified by a given visualization plan.
+   */
   private List<String> tags = DEFAULT_TAG;
+
+  /**
+   * measurements are real values occurred in the logContent that should be plotted.
+   * This is also specified by a given visualization plan.
+   */
   private List<Double> measurements;
 
   LogEntry(Date date, String threadName,
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogFilter.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogFilter.java
index 662ccde..fdc37e5 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogFilter.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogFilter.java
@@ -10,29 +10,38 @@ import java.util.Date;
 import java.util.Properties;
 import org.apache.iotdb.db.tools.logvisual.LogEntry.LogLevel;
 
+/**
+ * LogFilter filters log events by its level, threadName, className, lineNum and date.
+ */
 public class LogFilter {
-  // optional, only logs with levels equal to or higher than this will be analyzed
-  private LogLevel minLevel = LogLevel.DEBUG;
-  // optional, only threads, classes, lines in the lists are analyzed. When unset, all logs will
+
+  /**
+   * optional, only logs with levels equal to or higher than this will be analyzed
+   */
+  private LogLevel minLevel;
+
+  // optional, only threads, classes, lines in the lists are analyzed. When unset, all logs will be
   // analyzed. comma-separated
   private String[] threadNameWhiteList;
   private String[] classNameWhiteList;
   private int[] lineNumWhiteList;
-  // optional, only time ranges within the interval will be analyzed
-  // if startDate or endDate is set, datePattern must be set too
-  private DateFormat datePartten;
+
+  /**
+   * optional, only time ranges within the interval will be analyzed
+   * if startDate or endDate is set, datePattern must be set too
+   */
+  private DateFormat datePattern;
   private Date startDate = new Date(Long.MIN_VALUE);
   private Date endDate = new Date(Long.MAX_VALUE);
 
-  public LogFilter() {
+  LogFilter() {
     minLevel = LogLevel.DEBUG;
   }
 
-  public LogFilter(Properties properties) throws IOException {
+  LogFilter(Properties properties) throws IOException {
     minLevel = LogLevel.valueOf(properties.getProperty(MIN_LEVEL.getPropertyName(), minLevel.name()));
 
-    String threadNameWhiteListStr = properties.getProperty(THREAD_NAME_WHITE_LIST.getPropertyName
-        ());
+    String threadNameWhiteListStr = properties.getProperty(THREAD_NAME_WHITE_LIST.getPropertyName());
     if (threadNameWhiteListStr != null) {
       threadNameWhiteList = threadNameWhiteListStr.trim().split(",");
     }
@@ -47,11 +56,13 @@ public class LogFilter {
 
     String datePatternStr = properties.getProperty(DATE_PATTERN.getPropertyName());
     if (datePatternStr != null) {
-      this.datePartten = new SimpleDateFormat(datePatternStr.trim());
+      this.datePattern = new SimpleDateFormat(datePatternStr.trim());
+
+      // only when date pattern is set should we parse the start date and end date
       String startDateStr = properties.getProperty(START_DATE.getPropertyName());
       if (startDateStr != null) {
         try {
-          startDate = datePartten.parse(startDateStr.trim());
+          startDate = datePattern.parse(startDateStr.trim());
         } catch (ParseException e) {
           throw new IOException(e);
         }
@@ -60,7 +71,7 @@ public class LogFilter {
       String endDatePattern = properties.getProperty(END_DATE.getPropertyName());
       if (startDateStr != null) {
         try {
-          endDate = datePartten.parse(endDatePattern.trim());
+          endDate = datePattern.parse(endDatePattern.trim());
         } catch (ParseException e) {
           throw new IOException(e);
         }
@@ -119,8 +130,8 @@ public class LogFilter {
     return lineNumWhiteList;
   }
 
-  public DateFormat getDatePatten() {
-    return datePartten;
+  public DateFormat getDatePattern() {
+    return datePattern;
   }
 
   public Date getStartDate() {
@@ -147,8 +158,8 @@ public class LogFilter {
     this.lineNumWhiteList = lineNumWhiteList;
   }
 
-  public void setDatePartten(DateFormat datePartten) {
-    this.datePartten = datePartten;
+  public void setDatePattern(DateFormat datePattern) {
+    this.datePattern = datePattern;
   }
 
   public void setStartDate(Date startDate) {
@@ -172,13 +183,13 @@ public class LogFilter {
           (lineNumWhiteList));
     }
     if (startDate != null) {
-      properties.put(START_DATE.propertyName, datePartten.format(startDate));
+      properties.put(START_DATE.propertyName, datePattern.format(startDate));
     }
     if (endDate != null) {
-      properties.put(END_DATE.propertyName, datePartten.format(endDate));
+      properties.put(END_DATE.propertyName, datePattern.format(endDate));
     }
-    if (datePartten != null) {
-      properties.put(DATE_PATTERN.propertyName, ((SimpleDateFormat) datePartten).toPattern());
+    if (datePattern != null) {
+      properties.put(DATE_PATTERN.propertyName, ((SimpleDateFormat) datePattern).toPattern());
     }
   }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogParser.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogParser.java
index 2675085..356f17d 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogParser.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogParser.java
@@ -2,6 +2,9 @@ package org.apache.iotdb.db.tools.logvisual;
 
 import java.io.IOException;
 
+/**
+ * LogParser works as an iterator of logs.
+ */
 public interface LogParser {
 
   /**
@@ -9,7 +12,15 @@ public interface LogParser {
    */
   LogEntry next() throws IOException;
 
+  /**
+   * Release resources such as file streams.
+   * @throws IOException
+   */
   void close() throws IOException;
 
+  /**
+   * Start the parse from the beginning. Must be called before the first call to next().
+   * @throws IOException
+   */
   void reset() throws IOException;
 }
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogVisualizer.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogVisualizer.java
index f897fb1..f94ac5e 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogVisualizer.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogVisualizer.java
@@ -14,7 +14,6 @@ import java.util.Map.Entry;
 import java.util.Properties;
 import org.apache.iotdb.db.tools.logvisual.exceptions.AnalyzeException;
 import org.apache.iotdb.db.tools.logvisual.exceptions.NoLogFileLoadedException;
-import org.apache.iotdb.db.tools.logvisual.exceptions.NoSuchPlanException;
 import org.apache.iotdb.db.tools.logvisual.exceptions.UnmatchedContentException;
 import org.jfree.chart.ChartFactory;
 import org.jfree.chart.JFreeChart;
@@ -26,24 +25,65 @@ import org.jfree.data.time.TimeSeriesCollection;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
+/**
+ * LogVisualizer is the backend of this tool, which parses, groups and plots the logs according
+ * to a given visualization plan.
+ * The general procedure of one visualization would be:
+ *  1. call setLogFile() and setPropertyFile() to set those files;
+ *  2. call loadLogParser() to create a logParser;
+ *  3. call executePlan() to execute a visualization plan.
+ *  4. call getCharts() and getStatisticMap() to get the results.
+ */
 public class LogVisualizer {
 
   private static final Logger logger = LoggerFactory.getLogger(LogVisualizer.class);
 
   private LogParser logParser;
+  /**
+   * logCache stores the logs that satisfies the filter of the plan being executed.
+   */
   private List<LogEntry> logCache = new ArrayList<>();
+  /**
+   * logGroups stores the logs by their their tags (specified by the plan).
+   */
+  private Map<List<String>, List<LogEntry>> logGroups = new HashMap<>();
 
+  /**
+   * the plans currently loaded into memory.
+   */
   private Map<String, VisualizationPlan> plans = new HashMap<>();
-  private Map<List<String>, List<LogEntry>> logGroups = new HashMap<>();
 
+  /**
+   * the timeseries plots generated for each group of logs.
+   */
   private Map<String, JFreeChart> charts;
+  /**
+   * the statistics (count, mean, min, max) of each group of logs.
+   */
   private Map<String, List<TimeSeriesStatistics>> statisticsMap;
 
+  /**
+   * the file that defines how to parse the logs in the log file.
+   */
   private File parserPropertyFile;
+  /**
+   * the file that contains the logs to be visualized.
+   */
   private File logFile;
 
-  private void clearLogs() {
-    logCache.clear();
+  public static void main(String[] args) throws IOException {
+    LogVisualizer visualizer = new LogVisualizer();
+    visualizer.setParserPropertyFile(new File("E:\\codestore\\incubator-iotdb\\server\\src\\assembly"
+        + "\\resources"
+        + "\\tools\\logAnalyze\\default.log.pattern"));
+    visualizer.setLogFile( new File("C:\\Users\\admin\\Desktop\\logs\\log-all-2019-08-21.0.log"));
+    visualizer.loadLogParser();
+    visualizer.loadPlan("E:\\codestore\\incubator-iotdb\\server\\src\\assembly\\resources\\tools\\logAnalyze\\plans\\flushTimeConsumption.plan");
+  }
+
+  private void clearLogGroups() {
+    // log cache is cleared after logGroups are generated, so we do not clear it here
     logGroups.clear();
   }
 
@@ -54,6 +94,8 @@ public class LogVisualizer {
     if (logFile == null) {
       throw new IOException("Log file unset!");
     }
+    // close the previous
+    close();
     String propertyFilePath = parserPropertyFile.getPath();
     String logFilePath = logFile.getPath();
     Properties properties = new Properties();
@@ -65,8 +107,10 @@ public class LogVisualizer {
   }
 
   public void close() throws IOException {
-    logParser.close();
-    logParser = null;
+    if (logParser != null) {
+      logParser.close();
+      logParser = null;
+    }
   }
 
   public void loadPlans(File[] planFiles) throws IOException {
@@ -75,7 +119,7 @@ public class LogVisualizer {
     }
   }
 
-  public void loadPlan(File file) throws IOException {
+  private void loadPlan(File file) throws IOException {
     if (!file.exists()) {
       return;
     }
@@ -95,19 +139,12 @@ public class LogVisualizer {
     return plans.values();
   }
 
-  public void executePlan(String planName) throws AnalyzeException {
-    VisualizationPlan plan = plans.get(planName);
-    if (plan == null) {
-      throw new NoSuchPlanException(planName);
-    }
-    executePlan(plan);
-  }
-
   public void executePlan(VisualizationPlan plan) throws AnalyzeException {
     if (logParser == null) {
       throw new NoLogFileLoadedException();
     }
     try {
+      // read the logs fom the beginning
       logParser.reset();
     } catch (IOException e) {
       throw new AnalyzeException(e);
@@ -117,11 +154,16 @@ public class LogVisualizer {
     Map<String,TimeSeriesCollection> taggedTimeSeries = createTimeSeries(plan);
     charts = drawCharts(taggedTimeSeries, plan);
     statisticsMap = genStatisticMap(taggedTimeSeries);
+    clearLogGroups();
   }
 
+  /**
+   * Read all logs from the logParser and filter unwanted or malformed ones.
+   * @param plan
+   * @throws AnalyzeException
+   */
   private void collectLogs(VisualizationPlan plan) throws AnalyzeException {
     LogFilter logFilter = plan.getLogFilter();
-    clearLogs();
     try {
       LogEntry logEntry;
       readLogs:
@@ -133,6 +175,7 @@ public class LogVisualizer {
         }
 
         switch (logFilter.filter(logEntry)) {
+          // all logs must be time-ordered, so on meeting a log that is too new we can end the loop
           case BEYOND_END_TIME:
             break readLogs;
           case REJECT:
@@ -144,13 +187,14 @@ public class LogVisualizer {
     } catch (IOException e) {
       throw new AnalyzeException(e);
     }
-    logger.info("Collected {} logs", logCache.size());
+    logger.info("Collected {} logs from {}", logCache.size(), logFile.getPath());
   }
 
   private void groupLogs() {
     for (LogEntry logEntry : logCache) {
       logGroups.computeIfAbsent(logEntry.getTags(), tag -> new ArrayList<>()).add(logEntry);
     }
+    logCache.clear();
     logger.info("Found {} different tags", logGroups.size());
   }
 
@@ -159,6 +203,7 @@ public class LogVisualizer {
     for (Entry<List<String>, List<LogEntry>> entry : logGroups.entrySet()) {
       List<String> tags = entry.getKey();
       List<LogEntry> logs = entry.getValue();
+      // create a tag string for the log group as the key of the timeseries
       String concatenatedTag;
       if (tags.isEmpty()) {
         concatenatedTag = plan.getName();
@@ -170,27 +215,32 @@ public class LogVisualizer {
         builder.append(" ");
         concatenatedTag = builder.toString();
       }
-      TimeSeriesCollection tagTimeseries = new TimeSeriesCollection();
+
+      TimeSeriesCollection timeseriesGroup = new TimeSeriesCollection();
       if (plan.getMeasurementPositions() != null) {
+        // the measurements are given, create a timeseries for each measurement
         String[] legends = plan.getLegends();
         for (String legend : legends) {
+          // name each timeseries with the legend of each measurement
           TimeSeries timeSeries = new TimeSeries(concatenatedTag + legend);
-          tagTimeseries.addSeries(timeSeries);
+          timeseriesGroup.addSeries(timeSeries);
         }
+        // use the values in each log to build the timeseries
         for (LogEntry logEntry : logs) {
           List<Double> values = logEntry.getMeasurements();
           for (int i = 0; i < values.size(); i++) {
-            tagTimeseries.getSeries(i).addOrUpdate(new Millisecond(logEntry.getDate()), values.get(i));
+            timeseriesGroup.getSeries(i).addOrUpdate(new Millisecond(logEntry.getDate()), values.get(i));
           }
         }
       } else {
-        TimeSeries happenedInstance = new TimeSeries("HappenedInstance");
+        // the measurement are not given, just record the time when each log happened
+        TimeSeries happenedInstance = new TimeSeries(concatenatedTag + "HappenedInstance");
         for (LogEntry logEntry : logs) {
           happenedInstance.addOrUpdate(new Millisecond(logEntry.getDate()), 1.0);
         }
-        tagTimeseries.addSeries(happenedInstance);
+        timeseriesGroup.addSeries(happenedInstance);
       }
-      ret.put(concatenatedTag, tagTimeseries);
+      ret.put(concatenatedTag, timeseriesGroup);
     }
     return ret;
   }
@@ -201,30 +251,21 @@ public class LogVisualizer {
     for (Entry<String, TimeSeriesCollection> entry : taggedTimeSeries.entrySet()) {
       String tag = entry.getKey();
       TimeSeriesCollection timeSeriesList = entry.getValue();
+      // contain the start time of the timeseries in the x-axis name
       Date startDate = new Date((long) timeSeriesList.getDomainBounds(true).getLowerBound());
-      if (plan.getMeasurementPositions() != null) {
-        // a real-valued timeseries, draw a curve
-        JFreeChart chart = ChartFactory.createTimeSeriesChart(tag, "time-"+ startDate, "value",
-            timeSeriesList);
-        XYPlot xyPlot = chart.getXYPlot();
-        XYLineAndShapeRenderer xyLineAndShapeRenderer = ((XYLineAndShapeRenderer) xyPlot
-            .getRenderer());
-        xyLineAndShapeRenderer.setDefaultShapesVisible(true);
-        xyLineAndShapeRenderer.setDefaultShapesFilled(true);
-
-        charts.put(tag, chart);
-      } else {
-        JFreeChart chart = ChartFactory.createTimeSeriesChart(tag, "time-"+ startDate, "value",
-            timeSeriesList);
-        XYPlot xyPlot = chart.getXYPlot();
-        XYLineAndShapeRenderer xyLineAndShapeRenderer = ((XYLineAndShapeRenderer) xyPlot
-            .getRenderer());
-        xyLineAndShapeRenderer.setDefaultShapesVisible(true);
-        xyLineAndShapeRenderer.setDefaultShapesFilled(true);
+      JFreeChart chart = ChartFactory.createTimeSeriesChart(tag, "time-"+ startDate, "value",
+          timeSeriesList);
+      XYPlot xyPlot = chart.getXYPlot();
+      XYLineAndShapeRenderer xyLineAndShapeRenderer = ((XYLineAndShapeRenderer) xyPlot
+          .getRenderer());
+      // show the origin data points in the plot
+      xyLineAndShapeRenderer.setDefaultShapesVisible(true);
+      xyLineAndShapeRenderer.setDefaultShapesFilled(true);
+      if (plan.getMeasurementPositions() == null) {
+        // do not draw lines if we only record the time instances of the logs
         xyLineAndShapeRenderer.setDefaultLinesVisible(false);
-
-        charts.put(tag, chart);
       }
+      charts.put(tag, chart);
     }
     return charts;
   }
@@ -245,6 +286,7 @@ public class LogVisualizer {
       taggedTimeSeries) {
     Map<String, List<TimeSeriesStatistics>> ret = new HashMap<>();
     for (Entry<String, TimeSeriesCollection> timeSeriesCollectionEntry : taggedTimeSeries.entrySet()) {
+      // calculate the statistics of the logs in each group
       String tag = timeSeriesCollectionEntry.getKey();
       TimeSeriesCollection timeSeriesCollection = timeSeriesCollectionEntry.getValue();
       List<TimeSeriesStatistics> seriesStatistics = new ArrayList<>();
@@ -260,15 +302,4 @@ public class LogVisualizer {
   public Map<String, List<TimeSeriesStatistics>> getStatisticsMap() {
     return statisticsMap;
   }
-
-  public static void main(String[] args) throws IOException, AnalyzeException {
-    LogVisualizer visualizer = new LogVisualizer();
-    visualizer.setParserPropertyFile(new File("E:\\codestore\\incubator-iotdb\\server\\src\\assembly"
-        + "\\resources"
-        + "\\tools\\logAnalyze\\default.log.pattern"));
-    visualizer.setLogFile( new File("C:\\Users\\admin\\Desktop\\logs\\log-all-2019-08-21.0.log"));
-    visualizer.loadLogParser();
-    visualizer.loadPlan("E:\\codestore\\incubator-iotdb\\server\\src\\assembly\\resources\\tools\\logAnalyze\\plans\\flushTimeConsumption.plan");
-    visualizer.executePlan("flushTimeConsumption");
-  }
 }
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/PatternLogParser.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/PatternLogParser.java
index 68021cf..47a714a 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/PatternLogParser.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/PatternLogParser.java
@@ -24,6 +24,18 @@ import org.apache.iotdb.db.tools.logvisual.LogEntry.LogLevel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * PatternLogParser parse logs according to a property file which defines how a log looks like
+ * and what fields in the log are interesting.
+ * A running example of the property file:
+ *   pattern=([^\\[]*)(\\[.*])(\\s\\w+\\s)([^:]*:\\d+)(\\s-\\s)(.*)
+ *   date_index=1
+ *   thread_name_index=2
+ *   level_index=3
+ *   code_location_index=4
+ *   content_index=6
+ *   date_pattern=yyyy-MM-dd hh:mm:ss,SSS
+ */
 public class PatternLogParser implements LogParser{
   private static final Logger logger = LoggerFactory.getLogger(LogParser.class);
 
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/TimeSeriesStatistics.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/TimeSeriesStatistics.java
index 1bdcdee..71d36b5 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/TimeSeriesStatistics.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/TimeSeriesStatistics.java
@@ -23,6 +23,9 @@ import java.util.Date;
 import org.jfree.data.time.TimeSeries;
 import org.jfree.data.time.TimeSeriesDataItem;
 
+/**
+ * TimeSeriesStatistics store the the count, mean, max, min of both time and measurements.
+ */
 public class TimeSeriesStatistics {
 
   public static final String[] HEADER = new String[] {
@@ -69,30 +72,6 @@ public class TimeSeriesStatistics {
     return size;
   }
 
-  public double getMeanInterval() {
-    return meanInterval;
-  }
-
-  public long getMaxInterval() {
-    return maxInterval;
-  }
-
-  public long getMinInterval() {
-    return minInterval;
-  }
-
-  public double getMeanVal() {
-    return meanVal;
-  }
-
-  public double getMaxVal() {
-    return maxVal;
-  }
-
-  public double getMinVal() {
-    return minVal;
-  }
-
   public Object[] toArray() {
     Object[] ret = new Object[HEADER.length];
     int i = 0;
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/VisualUtils.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/VisualUtils.java
index cc56f69..0f61d5e 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/VisualUtils.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/VisualUtils.java
@@ -25,9 +25,9 @@ public class VisualUtils {
     throw new UnsupportedOperationException("Initializing a util class");
   }
 
-  public static int[] parseIntArray(String intarrayStr) {
-    if (intarrayStr != null) {
-      String[] intStrs = intarrayStr.split(",");
+  public static int[] parseIntArray(String intArrayStr) {
+    if (intArrayStr != null) {
+      String[] intStrs = intArrayStr.split(",");
       int[] ints = new int[intStrs.length];
       for (int i = 0; i < ints.length; i++) {
         ints[i] = Integer.parseInt(intStrs[i]);
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/VisualizationPlan.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/VisualizationPlan.java
index 66f6643..4447eed 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/VisualizationPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/VisualizationPlan.java
@@ -14,6 +14,26 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.apache.iotdb.db.tools.logvisual.exceptions.UnmatchedContentException;
 
+/**
+ * VisualizationPlan defines what fields (by using groups in regexp) should be plotted as value,
+ * what fields should be used to group the logs and what logs should be filtered.
+ * An example plan:
+    name=flushTimeConsumption
+    content_pattern=Storage group (.*) memtable (.*) flushing a memtable has finished! Time consumption: (.*)ms
+
+    measurement_positions=3
+    legends=Time
+    tag_positions=1
+
+    min_level=INFO
+    thread_name_white_list=pool-1-IoTDB-JDBC-Client-thread-5
+    class_name_white_list=org.apache.iotdb.db.engine.storagegroup.StorageGroupProcessor
+    line_num_white_list=392
+
+    date_pattern=yyyy-MM-dd hh:mm:ss
+    start_date=2019-08-21 09:00:00
+    end_date=2019-08-22 09:00:00
+ */
 public class VisualizationPlan {
   // optional, this will be used as the title of the figure.
   private String name;
@@ -39,6 +59,7 @@ public class VisualizationPlan {
 
   private LogFilter logFilter;
 
+  // where the plan is stored
   private String planFilePath;
 
   public VisualizationPlan() {
@@ -73,13 +94,21 @@ public class VisualizationPlan {
     logFilter = new LogFilter(properties);
   }
 
+  /**
+   * parse the content in a LogEntry using contentPattern and store the parsed fields back to the
+   * entry.
+   * @param logEntry
+   * @throws UnmatchedContentException
+   */
   public void parseContents(LogEntry logEntry) throws UnmatchedContentException {
     Matcher matcher = contentPattern.matcher(logEntry.getLogContent());
     if (!matcher.matches()) {
       throw new UnmatchedContentException(logEntry.getLogContent(), contentPattern.pattern());
     }
+
     String[] matchedValues = new String[matcher.groupCount()];
     for (int i = 1; i <= matcher.groupCount(); i++) {
+      // group(0) is the whole string
       matchedValues[i - 1] = matcher.group(i);
     }
     if (tagPositions != null) {
@@ -141,11 +170,7 @@ public class VisualizationPlan {
   public void setTagPositions(int[] tagPositions) {
     this.tagPositions = tagPositions;
   }
-
-  public void setLogFilter(LogFilter logFilter) {
-    this.logFilter = logFilter;
-  }
-
+  
   public void setPlanFilePath(String planFilePath) {
     this.planFilePath = planFilePath;
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/conf/PropertyKeys.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/conf/PropertyKeys.java
index 593f65f..b6e24d8 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/conf/PropertyKeys.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/conf/PropertyKeys.java
@@ -19,9 +19,23 @@
 
 package org.apache.iotdb.db.tools.logvisual.conf;
 
+/**
+ * PropertyKeys holds the keys of properties that store the paths chosen by the user the last
+ * time he uses this tool for convenience.
+ */
 public enum PropertyKeys {
-  DEFAULT_PARSER_FILE_PATH("parser_properties_path"), DEFAULT_LOG_FILE_PATH
-      ("log_path"), DEFAULT_PLAN_PATH("plans_path");
+  /**
+   * The last path of the parser property file chosen by the user.
+   */
+  DEFAULT_PARSER_FILE_PATH("parser_properties_path"),
+  /**
+   * The last path of the log file chosen by the user.
+   */
+  DEFAULT_LOG_FILE_PATH("log_path"),
+  /**
+   * The last path of the visualization plan file chosen by the user.
+   */
+  DEFAULT_PLAN_PATH("plans_path");
   private String key;
 
   PropertyKeys(String key) {
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ClosableComboTab.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ClosableComboTab.java
index 227f973..7525001 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ClosableComboTab.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ClosableComboTab.java
@@ -21,11 +21,14 @@ package org.apache.iotdb.db.tools.logvisual.gui;
 
 import java.util.Map;
 
-public abstract class ClosableComboTab extends ClosableTab {
+/**
+ * ClosableComboTab is a ClosableTab with a comboBox.
+ */
+abstract class ClosableComboTab extends ClosableTab {
 
   private LabeledComboBox comboBox;
 
-  public ClosableComboTab(String name, Map comboItems, TabCloseCallBack tabCloseCallBack) {
+  ClosableComboTab(String name, Map comboItems, TabCloseCallBack tabCloseCallBack) {
     super(name, tabCloseCallBack);
 
     comboBox = new LabeledComboBox(comboItems, this::onItemSelected, "Please select an item to "
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ClosableTab.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ClosableTab.java
index 956d974..44a8932 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ClosableTab.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ClosableTab.java
@@ -25,6 +25,9 @@ import javax.swing.AbstractAction;
 import javax.swing.JButton;
 import javax.swing.JPanel;
 
+/**
+ * ClosableTab is a JPanel with a "close" button.
+ */
 abstract class ClosableTab extends JPanel {
 
   private JButton closeTabButton;
@@ -47,6 +50,6 @@ abstract class ClosableTab extends JPanel {
   }
 
   public interface TabCloseCallBack {
-    void call(String name);
+    void call(String tabName);
   }
 }
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/FileSelectionBox.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/FileSelectionBox.java
index 5a6db5d..4f6f268 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/FileSelectionBox.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/FileSelectionBox.java
@@ -30,14 +30,19 @@ import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JTextField;
 
-public class FileSelectionBox extends Box{
+/**
+ * FileSelectionBox is a combination of a JLabel (showing the name of this component), a
+ * JTextField (showing the path of the chosen file) and a JButton (on clicking it the user can
+ * choose a single file).
+ */
+class FileSelectionBox extends Box{
 
   private JLabel panelName;
   private JTextField filePathField;
   private JButton selectFileButton;
-  FilePathBoxSelectionCallBack callBack;
+  private FilePathBoxSelectionCallBack callBack;
 
-  public FileSelectionBox(String name, FilePathBoxSelectionCallBack callBack, String
+  FileSelectionBox(String name, FilePathBoxSelectionCallBack callBack, String
       defaultFilePath) {
     super(BoxLayout.X_AXIS);
     this.callBack = callBack;
@@ -63,6 +68,7 @@ public class FileSelectionBox extends Box{
     add(selectFileButton);
 
     if (defaultFilePath != null) {
+      // select the default file if provided
       File defaultFile = new File(defaultFilePath);
       if (!defaultFile.exists()) {
         JOptionPane.showMessageDialog(this, panelName.getText() + ":default file " +
@@ -78,6 +84,7 @@ public class FileSelectionBox extends Box{
     JFileChooser fileChooser = new JFileChooser();
     int status = fileChooser.showOpenDialog(this);
     if (status == JFileChooser.APPROVE_OPTION) {
+      // only one file is allowed
       File chosenFile = fileChooser.getSelectedFile();
       callBack.call(chosenFile);
       filePathField.setText(chosenFile.getPath());
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LabeledComboBox.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LabeledComboBox.java
index 2852a6e..e587a7f 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LabeledComboBox.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LabeledComboBox.java
@@ -28,12 +28,15 @@ import javax.swing.DefaultComboBoxModel;
 import javax.swing.JComboBox;
 import javax.swing.JLabel;
 
-public class LabeledComboBox<K, V> extends Box {
+/**
+ * LabeledComboBox is JComboBox with a label, using a map as the data source of the ComboBox.
+ */
+class LabeledComboBox<K, V> extends Box {
 
   private ComboBoxModel comboBoxModel;
   private JComboBox comboBox;
 
-  public LabeledComboBox(Map<K, V> itemMap, ComboSelectedCallback callback, String labelText) {
+  LabeledComboBox(Map<K, V> itemMap, ComboSelectedCallback callback, String labelText) {
     super(BoxLayout.Y_AXIS);
 
     JLabel label = new JLabel(labelText);
@@ -54,6 +57,7 @@ public class LabeledComboBox<K, V> extends Box {
   }
 
   public interface ComboSelectedCallback {
+    // this methods accepts the value instead of the key in the itemMap
     void call(Object value);
   }
 }
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LoadLogBox.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LoadLogBox.java
index e91191e..43174d1 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LoadLogBox.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LoadLogBox.java
@@ -29,33 +29,34 @@ import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import org.apache.iotdb.db.tools.logvisual.LogVisualizer;
 
-public class LoadLogBox extends Box{
+/**
+ * LoadLogBox contains a JButton to load a log parser into memory to prepare for visualization
+ * and a JLabel to show whether the loading of the log parser is successful.
+ */
+class LoadLogBox extends Box{
 
   private JLabel status;
   private JButton loadLogButton;
-
   private LogVisualizer visualizer;
 
-  public LoadLogBox(LogVisualizer visualizer) {
+  LoadLogBox(LogVisualizer visualizer) {
     super(BoxLayout.Y_AXIS);
     this.visualizer = visualizer;
 
     status = new JLabel("No logs are loaded");
     loadLogButton = new JButton("Load logs");
-    loadLogButton.addActionListener(new AbstractAction() {
-      @Override
-      public void actionPerformed(ActionEvent e) {
-        try {
-          visualizer.loadLogParser();
-          status.setText("Logs are successfully loaded");
-        } catch (IOException e1) {
-          JOptionPane.showMessageDialog(LoadLogBox.this, "Cannot load logs: " + e1);
-        }
-      }
-    });
+    loadLogButton.addActionListener(this::onLoadLog);
 
     add(status);
     add(loadLogButton);
   }
 
+  private void onLoadLog(ActionEvent e) {
+    try {
+      visualizer.loadLogParser();
+      status.setText("Logs are successfully loaded");
+    } catch (IOException e1) {
+      JOptionPane.showMessageDialog(LoadLogBox.this, "Cannot load logs: " + e1);
+    }
+  }
 }
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LogVisualizeGui.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LogVisualizationGui.java
similarity index 73%
rename from server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LogVisualizeGui.java
rename to server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LogVisualizationGui.java
index 570d84c..ba6b599 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LogVisualizeGui.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LogVisualizationGui.java
@@ -22,26 +22,59 @@ import org.apache.iotdb.db.tools.logvisual.LogVisualizer;
 import org.apache.iotdb.db.tools.logvisual.TimeSeriesStatistics;
 import org.jfree.chart.JFreeChart;
 
-public class LogVisualizeGui {
+/**
+ * LogVisualizationGui provides a graphic way wo manipulate visualization plans and view the
+ * results of visualization.
+ */
+public class LogVisualizationGui {
 
-  private final String DEFAULT_PROPERTY = "visual.config";
+  /**
+   * if a config file is not provided, this will be used as a default config file saving the
+   * paths use chooses for the next usage.
+   */
+  private final String DEFAULT_CONFIG = "visual.config";
   private final int DEFAULT_HEIGHT = 600;
   private final int DEFAULT_WIDTH = 800;
 
   private LogVisualizer visualizer;
+
+  /**
+   * mainFrame is the main and only window of this gui.
+   */
   private JFrame mainFrame;
+  /**
+   * tabbedPane is the only direct component of mainFrame, which consists of one mainPanel and
+   * many result panels.
+   */
   private JTabbedPane tabbedPane;
+  /**
+   * mainPanel provide gui of loading log files and visualization plans and running visualization
+   * plans to generate results panels.
+   */
   private MainPanel mainPanel;
 
+  /**
+   * Each time a visualization plan is executed, two tabs will be generated, one (the
+   * ResultPlotTab) contains the
+   * timeseries plot of the visualized logs and the other (the ResultStatisticTab) contains a table
+   * showing the statistics of the observed logs.
+   * They will be store in the following maps with keys {planName}-plot and {planName}-statistic
+   * respectively.
+   */
   private Map<String, ResultPlotTab> resultPlotPanels = new HashMap<>();
   private Map<String, ResultStatisticTab> resultTablePanels = new HashMap<>();
+
+  /**
+   * properties contain most recently chosen files, so when the next time the user use this tool,
+   * he will not need to set all from the beginning.
+   */
   private String propertyFilePath;
   private Properties properties;
 
-  public LogVisualizeGui(String propertyFilePath) throws IOException {
+  private LogVisualizationGui(String propertyFilePath) throws IOException {
     properties = new Properties();
     if (propertyFilePath == null) {
-      propertyFilePath = DEFAULT_PROPERTY;
+      propertyFilePath = DEFAULT_CONFIG;
     }
     this.propertyFilePath = propertyFilePath;
     File propertyFile = new File(propertyFilePath);
@@ -70,6 +103,7 @@ public class LogVisualizeGui {
 
   private void onPlanExecuted(String planName, Map<String, JFreeChart> charts, Map<String,
       List<TimeSeriesStatistics>> statisticMap) {
+    // create a tab to display the timeseries plots, may replace the old one
     String tabName = planName + "-plot";
     ResultPlotTab resultPlotTab = new ResultPlotTab(tabName, charts, this::onTabClose);
     ResultPlotTab oldPlotTab = resultPlotPanels.get(tabName);
@@ -79,6 +113,7 @@ public class LogVisualizeGui {
     resultPlotPanels.put(tabName, resultPlotTab);
     tabbedPane.add(resultPlotTab);
 
+    // create a tab to display the log statistics, may replace the old one
     tabName = planName + "-statistics";
     ResultStatisticTab resultStatisticTab = new ResultStatisticTab(tabName, statisticMap,
         this::onTabClose);
@@ -91,6 +126,7 @@ public class LogVisualizeGui {
   }
 
   private void onPropertyChange(String key, String value) {
+    // when the user chooses a new file, the properties should be updated and persisted
     properties.put(key, value);
     try (FileWriter writer = new FileWriter(propertyFilePath);
         BufferedWriter bufferedWriter = new BufferedWriter(writer)) {
@@ -121,7 +157,7 @@ public class LogVisualizeGui {
     if (args.length > 0) {
       propertyFilePath = args[0];
     }
-    LogVisualizeGui gui = new LogVisualizeGui(propertyFilePath);
+    LogVisualizationGui gui = new LogVisualizationGui(propertyFilePath);
   }
 
 
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/MainPanel.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/MainPanel.java
index 3755c0a..8ff49ca 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/MainPanel.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/MainPanel.java
@@ -23,24 +23,44 @@ import java.io.File;
 import java.util.Properties;
 import javax.swing.JPanel;
 import org.apache.iotdb.db.tools.logvisual.LogVisualizer;
-import org.apache.iotdb.db.tools.logvisual.VisualizationPlan;
 import org.apache.iotdb.db.tools.logvisual.conf.PropertyKeys;
-import org.apache.iotdb.db.tools.logvisual.gui.LogVisualizeGui.PropertyChangeCallback;
+import org.apache.iotdb.db.tools.logvisual.gui.LogVisualizationGui.PropertyChangeCallback;
 import org.apache.iotdb.db.tools.logvisual.gui.PlanBox.ExecutePlanCallback;
 
-public class MainPanel extends JPanel {
+/**
+ * MainPanel provides components that enable the user to choose log file to be visualized,
+ * manipulate or execute visualization plans.
+ */
+class MainPanel extends JPanel {
 
+  /**
+   * to select a log file that will be visualized.
+   */
   private FileSelectionBox logFileSelectionBox;
+  /**
+   * to select a file that describe how to parse the logs.
+   */
   private FileSelectionBox parserPropertyBox;
+  /**
+   * to generate a log parser and prepare to load the logs.
+   */
   private LoadLogBox loadLogBox;
+  /**
+   * to provide means of manipulating the visualizations plans and execute them.
+   */
   private PlanBox planBox;
 
-
+  /**
+   * A backend that actually performs the visualization.
+   */
   private LogVisualizer visualizer;
 
+  /**
+   * When a user choose a new file, call this to remember the choice.
+   */
   private PropertyChangeCallback propertyChangeCallback;
 
-  public MainPanel(LogVisualizer logVisualizer, ExecutePlanCallback executePlanCallback,
+  MainPanel(LogVisualizer logVisualizer, ExecutePlanCallback executePlanCallback,
       Properties properties, PropertyChangeCallback propertyChangeCallback) {
     this.visualizer = logVisualizer;
     this.propertyChangeCallback = propertyChangeCallback;
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/PlanBox.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/PlanBox.java
index 3e381ea..986869b 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/PlanBox.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/PlanBox.java
@@ -43,27 +43,36 @@ import org.apache.iotdb.db.tools.logvisual.TimeSeriesStatistics;
 import org.apache.iotdb.db.tools.logvisual.VisualizationPlan;
 import org.apache.iotdb.db.tools.logvisual.conf.PropertyKeys;
 import org.apache.iotdb.db.tools.logvisual.exceptions.AnalyzeException;
-import org.apache.iotdb.db.tools.logvisual.gui.LogVisualizeGui.PropertyChangeCallback;
+import org.apache.iotdb.db.tools.logvisual.gui.LogVisualizationGui.PropertyChangeCallback;
 import org.jfree.chart.JFreeChart;
 
-public class PlanBox extends Box{
+/**
+ * PlanBox provides interfaces to save, load, create, delete and execute visualization plans.
+ */
+@SuppressWarnings("unused") // ignore the event parameter
+class PlanBox extends Box{
   private JLabel panelName;
   private JButton loadPlanButton;
   private JButton executePlanButton;
   private JButton savePlanButton;
   private JButton createPlanButton;
   private JButton deletePlanButton;
+
+  // display of plans
   private JScrollPane scrollPane;
   private DefaultListModel<VisualizationPlan> planListModel;
   private JList planList;
   private PlanDetailPanel planDetailPanel;
 
+  // plan execution backend
   private LogVisualizer visualizer;
 
+  // call this to create tabs to display the results when a plan is executed
   private ExecutePlanCallback executePlanCallback;
+  // call this to remember the choice when the user has loaded new plans
   private PropertyChangeCallback propertyChangeCallback;
 
-  public PlanBox(LogVisualizer visualizer, ExecutePlanCallback executePlanCallback, String defaultPlanPath,
+  PlanBox(LogVisualizer visualizer, ExecutePlanCallback executePlanCallback, String defaultPlanPath,
       PropertyChangeCallback propertyChangeCallback) {
     super(BoxLayout.X_AXIS);
 
@@ -104,7 +113,6 @@ public class PlanBox extends Box{
     vBox.add(executePlanButton);
     vBox.add(Box.createGlue());
     add(vBox);
-    setAlignmentY(0.5f);
 
     planDetailPanel = new PlanDetailPanel();
     planDetailPanel.setPreferredSize(new Dimension(400, 300));
@@ -118,14 +126,17 @@ public class PlanBox extends Box{
     deletePlanButton.addActionListener(this::onDeletePlan);
 
     if (defaultPlanPath != null) {
+      // load default plans if given
       String[] defaultPaths = defaultPlanPath.split(";");
       File[] defaultPlanFiles = new File[defaultPaths.length];
       for (int i = 0; i < defaultPaths.length; i++) {
         defaultPlanFiles[i] = new File(defaultPaths[i]);
       }
       try {
+        // read the plans from the disk
         visualizer.loadPlans(defaultPlanFiles);
         Collection<VisualizationPlan> planList = visualizer.listPlans();
+        // show plans in the gui
         updatePlan(planList);
       } catch (IOException e1) {
         JOptionPane.showMessageDialog(this, "Cannot load plan: " + e1);
@@ -137,14 +148,18 @@ public class PlanBox extends Box{
     JFileChooser fileChooser = new JFileChooser();
     fileChooser.setMultiSelectionEnabled(true);
     fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+    // let the user choose plan files or directories that contain visualization plans
     int status = fileChooser.showOpenDialog(this);
     if (status == JFileChooser.APPROVE_OPTION) {
       File[] chosenFiles = fileChooser.getSelectedFiles();
       try {
+        // read plans from disk
         visualizer.loadPlans(chosenFiles);
         Collection<VisualizationPlan> planList = visualizer.listPlans();
+        // display the plans in the panel
         updatePlan(planList);
 
+        // save the paths so that the tool can load the plans automatically next time
         if (chosenFiles.length > 0) {
           StringBuilder builder = new StringBuilder(chosenFiles[0].getPath());
           for (int i = 1; i < chosenFiles.length; i++) {
@@ -153,7 +168,7 @@ public class PlanBox extends Box{
           propertyChangeCallback.call(PropertyKeys.DEFAULT_PLAN_PATH.getKey(), builder.toString());
         }
       } catch (IOException e1) {
-        JOptionPane.showMessageDialog(this, "Cannot load plan: " + e1);
+        JOptionPane.showMessageDialog(this, "Cannot load plan: " + e1.getMessage());
       }
     }
   }
@@ -175,7 +190,9 @@ public class PlanBox extends Box{
     } catch (AnalyzeException e1) {
       JOptionPane.showMessageDialog(this, "Cannot execute plan: " + e1.getMessage());
     }
+    // timeseries plots of each measurement in the visualization plan
     Map<String, JFreeChart> charts = visualizer.getCharts();
+    // statistics (count, mean, max, min) of each measurement
     Map<String, List<TimeSeriesStatistics>> statisticMap = visualizer.getStatisticsMap();
     executePlanCallback.call(plan.getName(), charts, statisticMap);
   }
@@ -185,24 +202,30 @@ public class PlanBox extends Box{
     if (plan == null) {
       return;
     }
+    // update the display of the panel according to the new plan
     planDetailPanel.setPlan(plan);
   }
 
   private void onPlanSave(ActionEvent e) {
+    // update the content of the plan according to the text fields
     planDetailPanel.updatePlan();
   }
 
   private void onCreatePlan(ActionEvent e) {
     JFileChooser fileChooser = new JFileChooser();
+    // let the user to choose a place for the new plan
     int status = fileChooser.showOpenDialog(this);
     if (status == JFileChooser.APPROVE_OPTION) {
       File chosenFile = fileChooser.getSelectedFile();
       VisualizationPlan plan = new VisualizationPlan();
       plan.setPlanFilePath(chosenFile.getPath());
+      // the name of the file will also be the name of the plan
       plan.setName(chosenFile.getName());
+      // a default plan matches every thing
       plan.setContentPattern(Pattern.compile(".*"));
 
       planListModel.addElement(plan);
+      // the new plan will be focused on
       planList.setSelectedIndex(planListModel.getSize() - 1);
       planDetailPanel.setPlan(plan);
     }
@@ -220,11 +243,13 @@ public class PlanBox extends Box{
       File file = new File(plan.getPlanFilePath());
       file.delete();
       planListModel.removeElement(plan);
+      // update the display since the deleted one is always the one being displayed
       planDetailPanel.setPlan(null);
     }
   }
 
   public interface ExecutePlanCallback {
+    // call this to create new tabs to show the results after the plan is executed
     void call(String planName, Map<String, JFreeChart> charts, Map<String,
         List<TimeSeriesStatistics>> statisticMap);
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/PlanDetailPanel.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/PlanDetailPanel.java
index f932760..4a13fb0 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/PlanDetailPanel.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/PlanDetailPanel.java
@@ -30,12 +30,13 @@ import org.apache.iotdb.db.tools.logvisual.LogEntry.LogLevel;
 import org.apache.iotdb.db.tools.logvisual.VisualUtils;
 import org.apache.iotdb.db.tools.logvisual.VisualizationPlan;
 
+/**
+ * PlanDetailPanel displays the information of a visualization plan.
+ */
 public class PlanDetailPanel extends JScrollPane {
 
   private VisualizationPlan plan;
 
-  private Box box;
-
   private JTextField nameField = new JTextField();
   private JTextField patternField = new JTextField();
   private JTextField measurementsField = new JTextField();
@@ -49,7 +50,7 @@ public class PlanDetailPanel extends JScrollPane {
   private JTextField startDateField = new JTextField();
   private JTextField endDateField = new JTextField();
 
-  public PlanDetailPanel() {
+  PlanDetailPanel() {
     super(null, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
     setBorder(BorderFactory.createTitledBorder("Plan detail"));
 
@@ -84,6 +85,10 @@ public class PlanDetailPanel extends JScrollPane {
     setViewportView(box);
   }
 
+  /**
+   * Set the currently displayed plan. If it is null, clean the display.
+   * @param plan
+   */
   public void setPlan(VisualizationPlan plan) {
     this.plan = plan;
     updateFields();
@@ -131,8 +136,8 @@ public class PlanDetailPanel extends JScrollPane {
     if (plan.getLogFilter().getLineNumWhiteList() != null) {
       lineNumField.setText(VisualUtils.intArrayToString(plan.getLogFilter().getLineNumWhiteList()));
     }
-    if (plan.getLogFilter().getDatePatten() != null) {
-      SimpleDateFormat datePatten = (SimpleDateFormat) plan.getLogFilter().getDatePatten();
+    if (plan.getLogFilter().getDatePattern() != null) {
+      SimpleDateFormat datePatten = (SimpleDateFormat) plan.getLogFilter().getDatePattern();
       datePatternField.setText(datePatten.toPattern());
       if (plan.getLogFilter().getStartDate() != null) {
         startDateField.setText(datePatten.format(plan.getLogFilter().getStartDate()));
@@ -143,6 +148,9 @@ public class PlanDetailPanel extends JScrollPane {
     }
   }
 
+  /**
+   * Update the current displayed plan after it is modified amd save it to a file.
+   */
   public void updatePlan() {
     if (plan == null) {
       return;
@@ -161,6 +169,7 @@ public class PlanDetailPanel extends JScrollPane {
     String startDate = startDateField.getText();
     String endDate = endDateField.getText();
 
+    // validate the fields
     if (name.matches("\\s*")) {
       JOptionPane.showMessageDialog(this, "Name cannot be empty");
       return;
@@ -221,13 +230,13 @@ public class PlanDetailPanel extends JScrollPane {
       plan.getLogFilter().setMinLevel(LogLevel.valueOf(logLevel));
       SimpleDateFormat simpleDateFormat = datePattern != null ? new SimpleDateFormat(datePattern) :
           null;
-      plan.getLogFilter().setDatePartten(simpleDateFormat);
+      plan.getLogFilter().setDatePattern(simpleDateFormat);
       plan.getLogFilter().setStartDate(startDate != null ? simpleDateFormat.parse(startDate) : null);
       plan.getLogFilter().setEndDate(endDate != null ? simpleDateFormat.parse(endDate) : null);
 
       plan.saveAsFile();
     } catch (Exception e) {
-      JOptionPane.showMessageDialog(this, e.toString());
+      JOptionPane.showMessageDialog(this, e.getMessage());
     }
   }
 }
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ResultPlotTab.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ResultPlotTab.java
index fa293e0..8c31aca 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ResultPlotTab.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ResultPlotTab.java
@@ -25,6 +25,9 @@ import javax.swing.BorderFactory;
 import org.jfree.chart.ChartPanel;
 import org.jfree.chart.JFreeChart;
 
+/**
+ * ResultPlotTab shows the timeseries-plot of the log events.
+ */
 class ResultPlotTab extends ClosableComboTab {
 
   private ChartPanel chartPanel;
@@ -39,6 +42,7 @@ class ResultPlotTab extends ClosableComboTab {
     chartPanel.setSize(800, 480);
     add(chartPanel);
   }
+
   void onItemSelected(Object chart){
     chartPanel.setChart((JFreeChart) chart);
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ResultStatisticTab.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ResultStatisticTab.java
index f764c7c..a8544d0 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ResultStatisticTab.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ResultStatisticTab.java
@@ -19,14 +19,11 @@
 
 package org.apache.iotdb.db.tools.logvisual.gui;
 
-import java.awt.BorderLayout;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
-import javax.swing.BorderFactory;
 import javax.swing.Box;
-import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTable;
 import javax.swing.table.DefaultTableModel;
@@ -34,6 +31,9 @@ import javax.swing.table.TableModel;
 import javax.swing.table.TableRowSorter;
 import org.apache.iotdb.db.tools.logvisual.TimeSeriesStatistics;
 
+/**
+ * ResultStatisticTab shows the statistic (count, mean, min, max) of the log events.
+ */
 class ResultStatisticTab extends ClosableTab {
 
   private TableModel tableModel;
@@ -46,8 +46,11 @@ class ResultStatisticTab extends ClosableTab {
     table = new JTable();
 
     Box box = Box.createVerticalBox();
+    // the header and the data should be added separately
     box.add(table.getTableHeader());
     box.add(table);
+
+    // provides a scroll bar for many series
     JScrollPane scrollPane = new JScrollPane(box);
     scrollPane.setLocation(0, 100);
     scrollPane.setSize(800, 600);
@@ -65,6 +68,7 @@ class ResultStatisticTab extends ClosableTab {
     }
     tableModel = new DefaultTableModel(data, header);
     table.setModel(tableModel);
+    // enable sort by column
     table.setRowSorter(new TableRowSorter<>(tableModel));
   }
 }
\ No newline at end of file