You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by hx...@apache.org on 2020/07/18 06:01:33 UTC

[incubator-iotdb] 01/01: remove log visualizer tool from v0.10

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

hxd pushed a commit to branch 0.10-iotdb-799-remove-logvisualizer
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git

commit cd92b6d883fdf7325c68e2ab63106d12e55ac640
Author: xiangdong huang <sa...@gmail.com>
AuthorDate: Sat Jul 18 14:01:07 2020 +0800

    remove log visualizer tool from v0.10
---
 docs/UserGuide/System Tools/Log Visualizer.md      | 160 --------
 docs/zh/UserGuide/System Tools/Log Visualizer.md   | 146 -------
 server/pom.xml                                     |   5 -
 .../apache/iotdb/db/tools/logvisual/LogEntry.java  | 146 -------
 .../apache/iotdb/db/tools/logvisual/LogFilter.java | 220 -----------
 .../apache/iotdb/db/tools/logvisual/LogParser.java |  46 ---
 .../iotdb/db/tools/logvisual/LogVisualizer.java    | 437 ---------------------
 .../iotdb/db/tools/logvisual/PatternLogParser.java | 197 ----------
 .../db/tools/logvisual/TimeSeriesStatistics.java   | 113 ------
 .../iotdb/db/tools/logvisual/VisualUtils.java      |  69 ----
 .../db/tools/logvisual/VisualizationPlan.java      | 259 ------------
 .../db/tools/logvisual/conf/GuiPropertyKeys.java   |  48 ---
 .../exceptions/NoLogFileLoadedException.java       |  28 --
 .../logvisual/exceptions/NoSuchPlanException.java  |  28 --
 .../exceptions/UnmatchedContentException.java      |  28 --
 .../exceptions/VisualizationException.java         |  39 --
 .../db/tools/logvisual/gui/ClosableComboTab.java   |  42 --
 .../iotdb/db/tools/logvisual/gui/ClosableTab.java  |  55 ---
 .../db/tools/logvisual/gui/FileSelectionBox.java   | 109 -----
 .../db/tools/logvisual/gui/LabeledComboBox.java    |  63 ---
 .../iotdb/db/tools/logvisual/gui/LoadLogBox.java   |  62 ---
 .../tools/logvisual/gui/LogVisualizationGui.java   | 182 ---------
 .../iotdb/db/tools/logvisual/gui/MainPanel.java    | 107 -----
 .../iotdb/db/tools/logvisual/gui/PlanBox.java      | 301 --------------
 .../db/tools/logvisual/gui/PlanDetailPanel.java    | 242 ------------
 .../db/tools/logvisual/gui/ResultPlotTab.java      |  49 ---
 .../db/tools/logvisual/gui/ResultStatisticTab.java |  74 ----
 site/src/main/.vuepress/config.js                  |   4 -
 28 files changed, 3259 deletions(-)

diff --git a/docs/UserGuide/System Tools/Log Visualizer.md b/docs/UserGuide/System Tools/Log Visualizer.md
deleted file mode 100644
index 50939dc..0000000
--- a/docs/UserGuide/System Tools/Log Visualizer.md	
+++ /dev/null
@@ -1,160 +0,0 @@
-<!--
-
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you 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.
-
--->
-
-# LogVisualizer
-
-<!-- TOC -->
-
-- [LogVisualizer](#LogVisualizer)
-- [Introduction](#introduction)
-- [Preparation](#preparation)
-- [Usage(GUI)](#Usage(GUI))
-  - [Run the gui](#Run the gui)
-  - [Choose a log file](#Choose the log file(s))
-  - [Choose a parser property file](#Choose a parser property file)
-  - [Load logs](#Load logs)
-  - [Create new plans](#Create new plans)
-  - [Edit plans](#Edit plans)
-  - [Delete plans](#Delete plans)
-  - [Execute plans](#Execute plans)
-- [Usage(CommandLine)](#Usage(CommandLine))
-  
-
-<!-- /TOC -->
-
-# Introduction
-IoTDB generates a variety of logs during runtime like other software systems. The debug and trace
-logs can help the developers keep trace of the status of IoTDB and dig out potential or unclear bugs
-The info logs may tell how healthy the system is and point out directions for database parameter
-optimization. The warn and error logs indicate the system is in a dangerous status or 
-something unexpected happened (very likely a bug or an attack) and helps the database 
-administrator save the system before it crashes or find the reasons why it has crashed.
-
-With the logs being so valuable a source of monitoring system status, mining the logs for their 
-potential precious information has become quite a hot issue both in academy and industry. 
-Traditional ways often require much human-resource to discover the value behind the logs by 
-reading and analyzing the logs carefully. Usually, the logs of different sources (like Java 
-classes) are mixed together in several files and only the most experienced debugging experts know 
-from the beginning what logs exactly they long for, many less experienced programmers would spend 
-time reading unrelated logs and filtering them out. Nevertheless, logs are mostly composed with 
-strings containing numbers which describe the system status and they are much less straight-forward for 
-humans to understand and compare than plots and statistics.
-
-To reduce the difficulty of understanding what has happened behind these logs and better comparing
-them, we present a simple tool LogVisualizer to retrieve interesting (specified by the user) 
-variables in the log files, generate timeseries based on these observations and draw plots to show 
-them in a more human-friendly way. LogVisualizer also collects the statistics of the logs to 
-present an overall view of what was going on.
-
-# Preparation
-Before using LogVisualizer, you should have it built. Since LogVisualizer is integrated in the 
-server module as a tool, you can build the server together with LogVisualizer using:
-> mvn clean package -pl server -DskipTests
-
-Then you fan find the scripts to start LogVisualizer in: 
-`server/target/iotdb-server-{project-version}/tools/logVisualize`
-
-To have access to the advanced usages of this tool, you must have some basic knowledge about regular
-expressions, especially Java style ones. Knowing about regular expressions enables to create your own
-visualization plans or modify the existing ones. However, if you are totally new to regular expressions,
-you can still use the preset plans which are only applicable to IoTDB.
-
-# Usage(GUI)
-## Run the gui
-You can run LogVisualizer using `log-visualizer-gui.sh` (or `log-visualizer-gui.bat` in windows). 
-This will bring you a gui like:
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/main_panel.png?raw=true">
-
-## Choose the log file(s)
-First, you should choose a file containing the logs (or a directory containing such files) to be 
-visualized. Notice that we currently only support single-line logs and logs with multiple lines 
-will be ignored.
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/select_log_file.png?raw=true">
-
-## Choose a parser property file
-Second, you should also choose a file describing how to parse the log file. For log files 
-produced by IoTDB, we provide an example in 
-`server/src/assembly/resources/tools/logVisualize/default.log.pattern`. If your logs have 
-similar structure as the IoTDB ones, you may just use it, otherwise, you should read that file 
-carefully and modify it for your logs.
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/select_log_parser_property.png?raw=true">
-
-## Load logs
-Then, click the `Load logs` button to let the LogVisualizer to prepare to read the logs. If the 
-preparation is successful, the label above will show `Logs are successfully loaded`, otherwise, a
-dialog will show you what has gone wrong and you should fix it accordingly.
-
- <img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/load_logs.png?raw=true">
-
-## Load plans
-Next, you can load existing visualization plans or create new ones. For loading existing plans, 
-just click the button `Load plans` and choose the log files or directories that contain log 
-files. Notice that if choose a directory, then the directory must only contain visualization plans.
-
- <img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/load_plan.png?raw=true">
-
-## Create new plans
-Now, we will present an example of how to create a new plan. First, click the `Create plan` 
-button and choose a place to save the new plan, then the plan will show up in the list in the 
-left. The name of the file will be used as the plan's name and it must be different from 
-any existing plans.
-
- <img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/create_plan.png?raw=true">
-
-## Edit plans
-After creating the new plan, you can edit it in the right panel. We provide an example in 
- `server/src/assembly/resources/tools/logVisualize/plans/flushTimeConsumption.plan.example`, 
-we strongly recommend you read it carefully to know how to fill the fields. You can also edit plans 
-you have loaded here. Do not forget to click the `Save plan` button if you want to save what you 
-have modified. If you want to create a plan that shows the time consumptions of jobs grouped by 
-their type, you may set the fields like the following one.
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/edit_plan.png?raw=true">
-
-## Delete plans
-If you don't need a plan anymore, you can select it and click `Delete plan` button. This will 
-remove the plan from the disk.
-
-## Execute plans
-Finally, you can execute a plan by selecting it and click `Execute plan`. Please make sure you 
-have loaded the logs. Afterwards, two tabs will be added into the main panel. The first contains 
-timeseries charts each corresponding to log groups and plotting the measurements specified by the 
-plan. The second one presents the statistics of each measurement of each log group. Once you have 
-done browsing, you can click the button on the up-right to close the tab.
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/execute_plan.png?raw=true">
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/plot.png?raw=true">
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/statistics.png?raw=true">
-
-# Usage(CommandLine)
- We also provide a command line tool of LogVisualizer, which is `log-visualizer-cmd.sh` 
- (or `log-visualizer-cmd.bat`). This tool takes exactly 4 parameters, which are: `the path of the log file` 
- `the path of the parser property file` `the path of the visualization plan(s)` `the output directory`.
- Running this tool will load the given logs, run all the plans and save the result of each plan into
- a sub-directory of the output path.
- E.g.: 
- > ./log-visualizer-cmd.sh all.log default.log.pattern planB.plan results
-
diff --git a/docs/zh/UserGuide/System Tools/Log Visualizer.md b/docs/zh/UserGuide/System Tools/Log Visualizer.md
deleted file mode 100644
index beeb21c..0000000
--- a/docs/zh/UserGuide/System Tools/Log Visualizer.md	
+++ /dev/null
@@ -1,146 +0,0 @@
-<!--
-
-    Licensed to the Apache Software Foundation (ASF) under one
-    or more contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  The ASF licenses this file
-    to you 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.
-
--->
-
-# 日志可视化工具
-
-<!-- TOC -->
-
-- [日志可视化工具LogVisualizer](#日志可视化工具LogVisualizer)
-- [介绍](#介绍)
-- [准备工作](#准备工作)
-- [使用方法(图形界面)](#使用方法(图形界面))
-  - [启动图形界面](#启动图形界面)
-  - [选择日志文件](#选择日志文件)
-  - [选择解析器配置文件](#选择解析器配置文件)
-  - [载入日志](#载入日志)
-  - [新建可视化计划](#新建可视化计划)
-  - [编辑可视化计划](#编辑可视化计划)
-  - [删除可视化计划](#删除可视化计划)
-  - [执行可视化计划](#执行可视化计划)
-- [使用方法(命令行)](#使用方法(命令行))
-  
-
-<!-- /TOC -->
-
-# 介绍
-和众多其他系统软件一样,IoTDB在运行时会产生大量各种各样的日志。debug和trace级别的日志可以帮助
-开发者掌握IoTDB的运行时状态,找出潜在的或是尚不明确的bug。而info级别的日志可以用来判断系统的健康程度,
-并且可以为系统调优提供一个指导方向。一旦出现warn时甚至error级别的日志,就代表了系统正处于一个危险的
-状态或者是发生了某种异常(往往是某种bug或者黑客攻击),系统管理员可以通过分析这些日志及时对系统调整,
-避免系统走向崩溃,或是在系统崩溃后找寻系统崩溃的原因。
-
-鉴于日志对于监控系统的运行状态具有重大意义,许多学术界和工业界的专家都致力于研究如何对日志进行挖崛来
-提取其中的有价值的信息。传统的日志分析需要对系统和日志高度熟悉的人对日志进行有针对性的仔细阅读与分析
-才能发现日志背后的价值。通常,由不同数据源(例如Java中不同的类)产生的日志混合在若干个文件中,只有经验
-丰富的开发或运维人员才能快速地从海量的日志中找到想要的日志,而那些资历尚浅的人则需要花费大量的时间
-阅读和排除无用的日志才能最终找到他们所希望的日志。并且,日志的形式通常是包含了一些系统状态量的字符串,
-对于人类来说,要从这些字符串中发现其背后的趋势显然没有通过图表和统计信息等其他形式来得容易。
-
-为了方便开发和运维人员了解日志背后的系统状态的变化,以及将它们进行对比分析,我们推出了一个简易的日志
-可视化工具LogVisualizer。在用户通过正则表达式指定了日志中他们所感兴趣的变量后,LogVisualizer将自动
-抽取这些变量,按照对应日志的产生时间为这些变量生成时间序列,并以折线图的形式绘制这些变量的变化,以
-方便后续的比较和分析。同时,LogVisualizer还会对这些时间序列进行统计,找出其中的最大值、最小值、平均值、
-日志条数等信息,使得用户能有一个总体性的认识。
-
-# 准备工作
-在使用LogVisualizer之前,您需要对其进行构建。LogVisualizer被集成到server模块作为一个系统工具,因此您
-可以通过构建server模块来同时构建LogVisualizer。您可以使用以下命令:
-> mvn clean package -pl server -DskipTests
-
-之后您能在这个目录下找到LogVisualizer的启动脚本: 
-`server/target/iotdb-server-{project-version}/tools/logVisualize`
-
-如果您想要掌握本工具的一些进阶使用方法,您需要对正则表达式(特别是Java风格的正则表达式)有一些基本的
-了解。您只有在熟悉正则表达式以后才能新建可视化计划或者对已有的计划进行修改。如果您对正则表达式一无所知,
-我们也提供了一些预设的可视化计划供您使用,但这些可视化计划仅限于分析IoTDB。
-
-# 使用方法(图形界面)
-## 启动图形界面
-您可以通过脚本`log-visualizer-gui.sh` (在Windows下为`log-visualizer-gui.bat`)来启动LogVisualizer. 
-这将会启动一个如下图所示的图形界面:
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/main_panel.png?raw=true">
-
-## 选择日志文件
-首先,您需要点击图示的按钮选择一个含有待可视化日志的文件或者一个仅包含该类文件的文件夹。注意:我们
-目前仅支持单行日志,多行日志无法被正确解析而会被忽略。
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/select_log_file.png?raw=true">
-
-## 选择解析器配置文件
-然后,您还需要选择一个解析器配置文件,该文件将告诉LogVisualizer如何解析日志。对于IoTDB产生的日志,我们在
-`server/src/assembly/resources/tools/logVisualize/default.log.pattern`里提供了一个例子。如果您需要
-解析的日志与IoTDB的日志具有相同的格式,您可以直接使用该文件。否则,您需要仔细阅读该样例文件,并根据
-您的日志结构进行相应的修改。
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/select_log_parser_property.png?raw=true">
-
-## 载入日志
-之后,点击`Load logs`按钮来让LogVisualizer准备对这些日志进行解析。如果准备成功,按钮上方将显示
-`Logs are successfully loaded`。否则将会弹出一个对话框提示错误,您需要根据错误内容进行相应处理。
-
- <img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/load_logs.png?raw=true">
-
-## 加载可视化计划
-接下来,您可以选择加载磁盘上已有的可视化计划或者新建计划。要加载已有的计划,只需要点击 `Load plans`
-按钮,并在弹出的对话框中选择想要加载的计划文件或者包含计划文件的文件夹。注意,如果选择文件夹,该文件
-夹必须只包含计划文件。
-
- <img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/load_plan.png?raw=true">
-
-## 新建可视化计划
-现在,我们将展示如何使用图形界面创建一个新的可视化计划,您也可以参考已有的计划文件,使用文本编辑器编写。
-首先点击`Create plan`按钮并选择存放新计划的文件,新计划将出现在左边的列表。选择的文件名将作为新计划的
-名称,该名称不能与已有的计划重复。
-
- <img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/create_plan.png?raw=true">
-
-## 编辑可视化计划
-在创建了一个新的计划以后,您可以在右边的面板中对其进行编辑。我们在 `server/src/assembly/resources/tools/logVisualize/plans/flushTimeConsumption.plan.example`
-提供了一个样例来帮助您理解计划的每一个字段的含义以及应该如何设置它们,我们强烈推荐您仔细阅读该样例。
-您也可以编辑其他已经加载了的计划。编辑结束后请务必点击`Save plan`按钮来保存您的修改。在下图的例子中,
-我们给出了如何设计一个计划让它能对任务的完成时间进行可视化,并将任务按照其类别进行分组。
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/edit_plan.png?raw=true">
-
-## 删除可视化计划
-如果您不再想使用某个计划,您可以选中它并点击`Delete plan`按钮。这将永久地把该计划从磁盘上移除。
-
-## 执行可视化计划
-最后,选中一个计划并点击`Execute plan`就可以执行该计划。请确保您之前已经加载了日志。计划执行以后,
-主界面上将会多出两个页面,第一个页面包含了若干个时间序列图,每一个对应了计划里的一个分组并且包含了
-计划中的所有测点(measurement),第二个页面包含了对每一组的日志的每个测点的统计信息。当您结束对一个
-页面的浏览以后,您可以点击页面右上角的按钮将其关闭。
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/execute_plan.png?raw=true">
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/plot.png?raw=true">
-
-<img style="width:100%; max-width:800px; max-height:600px; margin-left:auto; margin-right:auto; display:block;" src="https://github.com/jt2594838/PicHub/blob/master/log-visualizer/statistics.png?raw=true">
-
-# 使用方法(命令行)
-我们也提供了LogVisualizer的命令行版本,您可以通过`log-visualizer-cmd.sh` (或 `log-visualizer-cmd.bat`)
-来使用。使用时必须输入四个参数,它们是:`日志文件的路径`,`解析器配置文件的路径`,`可视化计划的路径`,
-`结果输出路径`。运行该脚本,LogVisualizer将根据参数读取日志和可视化计划,执行每一个可视化计划,并将
-每一个计划的结果存储到输出路径的一个子文件夹下。
-例如: 
-> ./log-visualizer-cmd.sh all.log default.log.pattern planB.plan results
-
diff --git a/server/pom.xml b/server/pom.xml
index a1e2152..a277b41 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -136,11 +136,6 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.jfree</groupId>
-            <artifactId>jfreechart</artifactId>
-            <version>1.5.0</version>
-        </dependency>
-        <dependency>
             <groupId>com.clearspring.analytics</groupId>
             <artifactId>stream</artifactId>
             <version>2.9.5</version>
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
deleted file mode 100644
index b8816d3..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogEntry.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual;
-
-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 "TRACE", "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 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,
-      LogLevel logLevel, CodeLocation codeLocation, String logContent) {
-    this.date = date;
-    this.threadName = threadName;
-    this.logLevel = logLevel;
-    this.codeLocation = codeLocation;
-    this.logContent = logContent;
-  }
-
-  public Date getDate() {
-    return date;
-  }
-
-  public String getThreadName() {
-    return threadName;
-  }
-
-  public LogLevel getLogLevel() {
-    return logLevel;
-  }
-  public CodeLocation getCodeLocation() {
-    return codeLocation;
-  }
-
-  public String getLogContent() {
-    return logContent;
-  }
-
-  public List<String> getTags() {
-    return tags;
-  }
-
-  public void setTags(List<String> tags) {
-    this.tags = tags;
-  }
-
-  public List<Double> getMeasurements() {
-    return measurements;
-  }
-
-  public void setMeasurements(List<Double> measurements) {
-    this.measurements = measurements;
-  }
-
-  public enum LogLevel {
-    TRACE, DEBUG, INFO, WARN, ERROR
-  }
-
-  static class CodeLocation {
-    private String className;
-    private int lineNum;
-
-    CodeLocation(String className, int lineNum) {
-      this.className = className;
-      this.lineNum = lineNum;
-    }
-
-    public String getClassName() {
-      return className;
-    }
-
-    public int getLineNum() {
-      return lineNum;
-    }
-  }
-}
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
deleted file mode 100644
index 7c65e59..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogFilter.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual;
-
-import static org.apache.iotdb.db.tools.logvisual.LogFilter.FilterProperties.*;
-
-import java.io.IOException;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-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;
-
-  // 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 logs whose 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);
-
-  LogFilter() {
-    minLevel = LogLevel.DEBUG;
-  }
-
-  LogFilter(Properties properties) throws IOException {
-    this();
-    minLevel = LogLevel.valueOf(properties.getProperty(MIN_LEVEL.getPropertyName(), minLevel.name()));
-
-    String threadNameWhiteListStr = properties.getProperty(THREAD_NAME_WHITE_LIST.getPropertyName());
-    if (threadNameWhiteListStr != null) {
-      threadNameWhiteList = threadNameWhiteListStr.trim().split(",");
-    }
-
-    String classNameWhiteListStr = properties.getProperty(CLASS_NAME_WHITE_LIST.getPropertyName());
-    if (classNameWhiteListStr != null) {
-      classNameWhiteList = classNameWhiteListStr.trim().split(",");
-    }
-
-    lineNumWhiteList = VisualUtils.parseIntArray(properties.getProperty(LINE_NUM_WHITE_LIST
-        .getPropertyName()));
-
-    String datePatternStr = properties.getProperty(DATE_PATTERN.getPropertyName());
-    if (datePatternStr != null) {
-      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 = datePattern.parse(startDateStr.trim());
-        } catch (ParseException e) {
-          throw new IOException(e);
-        }
-      }
-
-      String endDatePattern = properties.getProperty(END_DATE.getPropertyName());
-      if (endDatePattern != null) {
-        try {
-          endDate = datePattern.parse(endDatePattern.trim());
-        } catch (ParseException e) {
-          throw new IOException(e);
-        }
-      }
-    }
-  }
-
-  public FilterFeedBack filter(LogEntry entry) {
-   if (entry.getLogLevel().ordinal() < minLevel.ordinal() ||
-       (threadNameWhiteList != null && !VisualUtils.strsContains(threadNameWhiteList, entry.getThreadName())) ||
-       (classNameWhiteList != null && !VisualUtils.strsContains(classNameWhiteList, entry.getCodeLocation()
-           .getClassName())) ||
-       (lineNumWhiteList != null && !VisualUtils.intsContains(lineNumWhiteList, entry.getCodeLocation()
-           .getLineNum())) ||
-       (startDate != null && entry.getDate().before(startDate))) {
-     return FilterFeedBack.REJECT;
-   }
-
-   if (endDate != null && entry.getDate().after(endDate)) {
-     return FilterFeedBack.BEYOND_END_TIME;
-   }
-    return FilterFeedBack.OK;
-  }
-
-  public LogLevel getMinLevel() {
-    return minLevel;
-  }
-
-  public String[] getThreadNameWhiteList() {
-    return threadNameWhiteList;
-  }
-
-  public String[] getClassNameWhiteList() {
-    return classNameWhiteList;
-  }
-
-  public int[] getLineNumWhiteList() {
-    return lineNumWhiteList;
-  }
-
-  public DateFormat getDatePattern() {
-    return datePattern;
-  }
-
-  public Date getStartDate() {
-    return startDate;
-  }
-
-  public Date getEndDate() {
-    return endDate;
-  }
-
-  public void setMinLevel(LogLevel minLevel) {
-    this.minLevel = minLevel;
-  }
-
-  public void setThreadNameWhiteList(String[] threadNameWhiteList) {
-    this.threadNameWhiteList = threadNameWhiteList;
-  }
-
-  public void setClassNameWhiteList(String[] classNameWhiteList) {
-    this.classNameWhiteList = classNameWhiteList;
-  }
-
-  public void setLineNumWhiteList(int[] lineNumWhiteList) {
-    this.lineNumWhiteList = lineNumWhiteList;
-  }
-
-  public void setDatePattern(DateFormat datePattern) {
-    this.datePattern = datePattern;
-  }
-
-  public void setStartDate(Date startDate) {
-    this.startDate = startDate;
-  }
-
-  public void setEndDate(Date endDate) {
-    this.endDate = endDate;
-  }
-
-  public void saveIntoProperties(Properties properties) {
-    properties.put(MIN_LEVEL.propertyName, minLevel.toString());
-    if (threadNameWhiteList != null) {
-      properties.put(THREAD_NAME_WHITE_LIST.propertyName, String.join(",", threadNameWhiteList));
-    }
-    if (classNameWhiteList != null) {
-      properties.put(CLASS_NAME_WHITE_LIST.propertyName, String.join(",", classNameWhiteList));
-    }
-    if (lineNumWhiteList != null) {
-      properties.put(LINE_NUM_WHITE_LIST.propertyName, VisualUtils.intArrayToString
-          (lineNumWhiteList));
-    }
-
-    if (datePattern != null) {
-      properties.put(DATE_PATTERN.propertyName, ((SimpleDateFormat) datePattern).toPattern());
-      if (startDate != null) {
-        properties.put(START_DATE.propertyName, datePattern.format(startDate));
-      }
-      if (endDate != null) {
-        properties.put(END_DATE.propertyName, datePattern.format(endDate));
-      }
-    }
-  }
-
-  public enum FilterProperties {
-    MIN_LEVEL("min_level"), THREAD_NAME_WHITE_LIST("thread_name_white_list"), CLASS_NAME_WHITE_LIST(
-        "class_name_white_list"),
-    LINE_NUM_WHITE_LIST("line_num_white_list"), START_DATE("start_date"), END_DATE("end_date"),
-    DATE_PATTERN("date_pattern");
-
-    private String propertyName;
-
-    FilterProperties(String propertyName) {
-      this.propertyName = propertyName;
-    }
-
-    public String getPropertyName() {
-      return propertyName;
-    }
-  }
-
-  enum FilterFeedBack {
-    OK, REJECT, BEYOND_END_TIME
-  }
-}
\ No newline at end of file
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
deleted file mode 100644
index beca94a..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogParser.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual;
-
-import java.io.IOException;
-
-/**
- * LogParser works as an iterator of logs.
- */
-public interface LogParser {
-
-  /**
-   * return the next LogEntry or null if there are no more logs.
-   */
-  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
deleted file mode 100644
index 2454b35..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/LogVisualizer.java
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
-import org.apache.iotdb.db.tools.logvisual.exceptions.NoLogFileLoadedException;
-import org.apache.iotdb.db.tools.logvisual.exceptions.UnmatchedContentException;
-import org.apache.iotdb.db.tools.logvisual.exceptions.VisualizationException;
-import org.jfree.chart.ChartFactory;
-import org.jfree.chart.ChartUtils;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
-import org.jfree.data.time.Millisecond;
-import org.jfree.data.time.TimeSeries;
-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.
- *  5. call saveResults() to save the results to a directory.
- */
-public class LogVisualizer {
-
-  private static final Logger logger = LoggerFactory.getLogger(LogVisualizer.class);
-
-  private LogParser logParser;
-
-  /**
-   * the plans currently loaded into memory.
-   * plan name -> plan
-   */
-  private Map<String, VisualizationPlan> plans = new HashMap<>();
-
-  /**
-   * the timeseries plots generated for each group of logs.
-   * measurement name -> the chart of the measurement
-   */
-  private Map<String, JFreeChart> charts;
-  /**
-   * the statistics (count, mean, min, max) of each group of logs.
-   * measurement name -> the statistics of the measurement of each group
-   */
-  private Map<String, List<TimeSeriesStatistics>> statisticsMap;
-  /**
-   *  how many groups are found by the given tags.
-   */
-  private int groupNum = 0;
-
-  /**
-   * 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 or the directory that contains such files.
-   */
-  private File logFile;
-
-  // params: <LogFilePath> <ParserPropertyFilePath> <PlanFilePath> <OutputDirectory>
-  public static void main(String[] args) throws IOException, VisualizationException {
-    if (args.length != 4) {
-      System.out.println("Wrong number of parameters: "
-          + " params: <LogFilePath> <ParserPropertyFilePath> <PlanFilePath> <OutputDirectory>");
-      return;
-    }
-    File logFile = new File(args[0]);
-    if (!logFile.exists()) {
-      System.out.println("Log file does not exist");
-      return;
-    }
-    File parserPropertyFile = new File(args[1]);
-    if (!parserPropertyFile.exists() || !parserPropertyFile.isFile()) {
-      System.out.println("Parser property file does not exist");
-      return;
-    }
-    File planFile = new File(args[2]);
-    if (!planFile.exists()) {
-      System.out.println("Plan file does not exist");
-      return;
-    }
-
-    File destDir = new File(args[3]);
-    if (destDir.exists() && !destDir.isDirectory()) {
-      System.out.println("The output path is not a directory");
-      return;
-    }
-    destDir.mkdirs();
-
-    LogVisualizer visualizer = new LogVisualizer();
-    visualizer.setLogFile(logFile);
-    visualizer.setParserPropertyFile(parserPropertyFile);
-    visualizer.loadLogParser();
-
-    visualizer.loadPlan(planFile);
-    Collection<VisualizationPlan> plans = visualizer.listPlans();
-
-    for (VisualizationPlan plan : plans) {
-      visualizer.executePlan(plan);
-      visualizer.saveResults(destDir.getPath() + File.separator + plan.getName());
-      System.out.println("Executed and saved results of plan "+ plan.getName());
-    }
-
-    System.out.println("Visualization completed");
-  }
-
-  public void loadLogParser() throws IOException {
-    if (parserPropertyFile == null) {
-      throw new IOException("Parser property file unset!");
-    }
-    if (logFile == null) {
-      throw new IOException("Log file unset!");
-    }
-    // close the previous parser
-    close();
-
-    List<String> logFilePaths = new ArrayList<>();
-    getLogFilePaths(logFile, logFilePaths);
-
-    String propertyFilePath = parserPropertyFile.getPath();
-    Properties properties = new Properties();
-    try (FileInputStream inputStream = new FileInputStream(propertyFilePath);
-        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {
-      properties.load(bufferedInputStream);
-    }
-    logParser = new PatternLogParser(properties, logFilePaths.toArray(new String[logFilePaths.size()]));
-  }
-
-  // collect the path of the log file or recursively get log file paths under the directory
-  private void getLogFilePaths(File currLogFile, List<String> logFilePaths) {
-    if (!currLogFile.exists()) {
-      return;
-    }
-    if (!currLogFile.isDirectory()) {
-      logFilePaths.add(currLogFile.getPath());
-    } else {
-      File[] subFiles = currLogFile.listFiles();
-      if (subFiles != null) {
-        for (File subFile : subFiles) {
-          getLogFilePaths(subFile, logFilePaths);
-        }
-      }
-    }
-  }
-
-  public void close() throws IOException {
-    if (logParser != null) {
-      logParser.close();
-      logParser = null;
-    }
-  }
-
-  public void loadPlans(File[] planFiles) throws IOException {
-    for (File file : planFiles) {
-      loadPlan(file);
-    }
-  }
-
-  private void loadPlan(File file) throws IOException {
-    if (!file.exists()) {
-      return;
-    }
-    if (file.isDirectory()) {
-      loadPlans(file.listFiles());
-    } else {
-      loadPlan(file.getPath());
-    }
-  }
-
-  private void loadPlan(String planFilePath) throws IOException {
-    VisualizationPlan plan = new VisualizationPlan(planFilePath);
-    plans.put(plan.getName(), plan);
-  }
-
-  public Collection<VisualizationPlan> listPlans() {
-    return plans.values();
-  }
-
-  public void executePlan(VisualizationPlan plan) throws VisualizationException {
-    if (logParser == null) {
-      throw new NoLogFileLoadedException();
-    }
-
-    List<LogEntry> logCache = collectLogs(plan);
-    // tag -> logs
-    Map<List<String>, List<LogEntry>> logGroups = groupLogs(logCache);
-    // <measurementName, <tag, timeseries>>
-    Map<String,Map<String, TimeSeries>> taggedTimeSeries = createTimeSeries(plan, logGroups);
-    charts = drawCharts(taggedTimeSeries, plan);
-    statisticsMap = genStatisticMap(taggedTimeSeries);
-  }
-
-  /**
-   * Read all logs from the logParser and filter unwanted or malformed ones.
-   * @param plan
-   * @throws VisualizationException
-   */
-  private List<LogEntry> collectLogs(VisualizationPlan plan) throws VisualizationException {
-    try {
-      // read the logs fom the beginning
-      logParser.reset();
-    } catch (IOException e) {
-      throw new VisualizationException(e);
-    }
-
-    List<LogEntry> logCache = new ArrayList<>();
-    LogFilter logFilter = plan.getLogFilter();
-    try {
-      LogEntry logEntry;
-      readLogs:
-      while ((logEntry = logParser.next()) != null) {
-        try {
-          // parse the measurements and tags
-          plan.parseContents(logEntry);
-        } catch (UnmatchedContentException e) {
-          continue;
-        }
-
-        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:
-            break;
-          case OK:
-            logCache.add(logEntry);
-        }
-      }
-    } catch (IOException e) {
-      throw new VisualizationException(e);
-    }
-    logger.info("Collected {} logs from {}", logCache.size(), logFile.getPath());
-    return logCache;
-  }
-
-  private Map<List<String>, List<LogEntry>> groupLogs(List<LogEntry> logCache) {
-    Map<List<String>, List<LogEntry>> logGroups = new HashMap<>();
-    for (LogEntry logEntry : logCache) {
-      logGroups.computeIfAbsent(logEntry.getTags(), tag -> new ArrayList<>()).add(logEntry);
-    }
-    logCache.clear();
-    groupNum = logGroups.size();
-    logger.info("Found {} different tags", groupNum);
-    return logGroups;
-  }
-
-  // <measurementName, <tag, timeseries>>
-  private Map<String, Map<String, TimeSeries>> createTimeSeries(VisualizationPlan plan,
-      Map<List<String>, List<LogEntry>> logGroups) {
-    Map<String, Map<String, TimeSeries>> ret = new HashMap<>();
-    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 prefix of the timeseries
-      String concatenatedTag;
-      if (tags.isEmpty()) {
-        concatenatedTag = plan.getName() + " ";
-      } else {
-        StringBuilder builder = new StringBuilder(plan.getName() + "-" + tags.get(0));
-        for (int i = 1; i < tags.size(); i++) {
-          builder.append(",").append(tags.get(i));
-        }
-        builder.append(" ");
-        concatenatedTag = builder.toString();
-      }
-
-      if (plan.getMeasurementPositions() != null) {
-        // the measurements are given, create a real-valued timeseries for each measurement
-        String[] legends = plan.getLegends();
-        // 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++) {
-            String legend = legends[i];
-            TimeSeries timeSeries = ret.computeIfAbsent(legend, leg -> new HashMap<>())
-                .computeIfAbsent(concatenatedTag, tag -> new TimeSeries(tag + legend));
-            timeSeries.addOrUpdate(new Millisecond(logEntry.getDate()), values.get(i));
-          }
-        }
-      } else {
-        // the measurements are not given, just record the time when each log was generated
-        String legend = "TimeOfOccurrence";
-        TimeSeries timeOfOccurrence = ret.computeIfAbsent(legend, tag -> new HashMap<>())
-            .computeIfAbsent(concatenatedTag, tag -> new TimeSeries( tag + legend));
-        for (LogEntry logEntry : logs) {
-          timeOfOccurrence.addOrUpdate(new Millisecond(logEntry.getDate()), 1.0);
-        }
-      }
-    }
-    return ret;
-  }
-
-  private Map<String, JFreeChart> drawCharts(Map<String, Map<String, TimeSeries>> taggedTimeSeries,
-      VisualizationPlan plan) {
-    Map<String, JFreeChart> charts = new HashMap<>();
-    for (Entry<String, Map<String, TimeSeries>> entry : taggedTimeSeries.entrySet()) {
-      String measurementName = entry.getKey();
-      TimeSeriesCollection timeSeriesList = new TimeSeriesCollection();
-      for (TimeSeries timeSeries : entry.getValue().values()) {
-        timeSeriesList.addSeries(timeSeries);
-      }
-      // add the start time of the timeseries to the x-axis name
-      Date startDate = new Date((long) timeSeriesList.getDomainBounds(true).getLowerBound());
-      JFreeChart chart = ChartFactory.createTimeSeriesChart(measurementName, "time-"+ startDate, measurementName,
-          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 (no measurements)
-        xyLineAndShapeRenderer.setDefaultLinesVisible(false);
-      }
-      charts.put(measurementName, chart);
-    }
-    return charts;
-  }
-
-  public Map<String, JFreeChart> getCharts() {
-    return charts;
-  }
-
-  public void setParserPropertyFile(File parserPropertyFile) {
-    this.parserPropertyFile = parserPropertyFile;
-  }
-
-  public void setLogFile(File logFile) {
-    this.logFile = logFile;
-  }
-
-  private Map<String, List<TimeSeriesStatistics>> genStatisticMap(Map<String, Map<String, TimeSeries>>
-      taggedTimeSeries) {
-    Map<String, List<TimeSeriesStatistics>> ret = new HashMap<>();
-    for (Entry<String, Map<String, TimeSeries>> timeSeriesEntry : taggedTimeSeries.entrySet()) {
-      // compute the statistics of the logs in each group and measurement
-      String measurementName = timeSeriesEntry.getKey();
-      List<TimeSeriesStatistics> seriesStatistics = new ArrayList<>();
-      Map<String, TimeSeries> seriesMap = timeSeriesEntry.getValue();
-      for (TimeSeries timeSeries : seriesMap.values()) {
-        seriesStatistics.add(new TimeSeriesStatistics(timeSeries));
-      }
-      ret.put(measurementName, seriesStatistics);
-    }
-    return ret;
-  }
-
-  // TODO-LogVisualizer: generate html to better view the results
-  public void saveResults(String destDirPath) throws VisualizationException {
-    if (charts == null || statisticsMap == null) {
-      throw new VisualizationException("No results to be saved");
-    }
-
-    File destDir = new File(destDirPath);
-    if (destDir.exists() && !destDir.isDirectory()) {
-      throw new VisualizationException(String.format("%s exists and is not a directory", destDirPath));
-    }
-    if (!destDir.exists() && !destDir.mkdirs()) {
-      throw new VisualizationException(String.format("Cannot create directory %s", destDirPath));
-    }
-
-    // save charts
-    for (Entry<String, JFreeChart> chartEntry : charts.entrySet()) {
-      File chartFile = new File(destDir, chartEntry.getKey() + ".png");
-      JFreeChart chart = chartEntry.getValue();
-      try (FileOutputStream fileOutputStream = new FileOutputStream(chartFile);
-          BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream)) {
-        ChartUtils.writeChartAsPNG(bufferedOutputStream, chart, 800, 600);
-      } catch (IOException e) {
-        throw new VisualizationException(String.format("Cannot save chart of %s", chartEntry.getKey()), e);
-      }
-    }
-
-    // save statistics
-    File statisticFile = new File(destDir, "statistic.csv");
-    try (FileWriter fileWriter = new FileWriter(statisticFile);
-        BufferedWriter writer = new BufferedWriter(fileWriter)) {
-      TimeSeriesStatistics.serializeHeader(writer);
-      for (Entry<String, List<TimeSeriesStatistics>> statisticEntry : statisticsMap.entrySet()) {
-        for (TimeSeriesStatistics timeSeriesStatistics : statisticEntry.getValue()) {
-          timeSeriesStatistics.serialize(writer);
-        }
-      }
-    } catch (IOException e) {
-      throw new VisualizationException(String.format("Cannot save statistics to %s", destDirPath), e);
-    }
-  }
-
-  public Map<String, List<TimeSeriesStatistics>> getStatisticsMap() {
-    return statisticsMap;
-  }
-
-  public int getGroupNum() {
-    return groupNum;
-  }
-}
\ 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
deleted file mode 100644
index bacd1d3..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/PatternLogParser.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual;
-
-import static org.apache.iotdb.db.tools.logvisual.PatternLogParser.PatternProperties.CODE_LOCATION_INDEX;
-import static org.apache.iotdb.db.tools.logvisual.PatternLogParser.PatternProperties.CONTENT_INDEX;
-import static org.apache.iotdb.db.tools.logvisual.PatternLogParser.PatternProperties.DATE_INDEX;
-import static org.apache.iotdb.db.tools.logvisual.PatternLogParser.PatternProperties.DATE_PATTERN;
-import static org.apache.iotdb.db.tools.logvisual.PatternLogParser.PatternProperties.LEVEL_INDEX;
-import static org.apache.iotdb.db.tools.logvisual.PatternLogParser.PatternProperties.PATTERN;
-import static org.apache.iotdb.db.tools.logvisual.PatternLogParser.PatternProperties.THREAD_NAME_INDEX;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Properties;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.apache.iotdb.db.tools.logvisual.LogEntry.CodeLocation;
-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 what 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
- * which parses logs like:
- * "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"
- */
-public class PatternLogParser implements LogParser{
-  private static final Logger logger = LoggerFactory.getLogger(LogParser.class);
-
-  private Pattern pattern;
-  private int dateIndex;
-  private int threadNameIndex;
-  private int levelIndex;
-  private int codeLocationIndex;
-  private int contentIndex;
-
-  private int logFileIdx;
-  private String[] logFilePaths;
-  private BufferedReader reader;
-  private DateFormat dateFormat;
-
-  PatternLogParser(Properties properties, String[] logFilePaths) {
-    this.pattern = Pattern.compile(properties.getProperty(PATTERN.getPropertyName()));
-    this.dateIndex = Integer.parseInt(properties.getProperty(DATE_INDEX.getPropertyName()));
-    this.threadNameIndex = Integer.parseInt(properties.getProperty(THREAD_NAME_INDEX
-        .getPropertyName(), String.valueOf(-1)));
-    this.levelIndex = Integer.parseInt(properties.getProperty(LEVEL_INDEX.getPropertyName(),
-        String.valueOf(-1)));
-    this.codeLocationIndex = Integer.parseInt(properties.getProperty(CODE_LOCATION_INDEX
-        .getPropertyName(), String.valueOf(-1)));
-    this.contentIndex = Integer.parseInt(properties.getProperty(CONTENT_INDEX.getPropertyName()));
-    this.dateFormat = new SimpleDateFormat(properties.getProperty(DATE_PATTERN.getPropertyName()));
-    this.logFilePaths = logFilePaths;
-    this.logFileIdx = -1;
-  }
-
-  private void nextFile() throws IOException {
-    close();
-    reader = new BufferedReader(new InputStreamReader(new FileInputStream(logFilePaths[++logFileIdx])));
-  }
-
-  private String nextLine() throws IOException {
-    String line = reader.readLine();
-    while (line == null) {
-      if (logFileIdx + 1 < logFilePaths.length) {
-        nextFile();
-        line = reader.readLine();
-      } else {
-        return null;
-      }
-    }
-    return line;
-  }
-
-  private Matcher nextMatchedLineMatcher() throws IOException {
-    String line = nextLine();
-    if (line == null) {
-      return null;
-    }
-
-    boolean matched = false;
-    Matcher matcher = null;
-    while (!matched) {
-      matcher = pattern.matcher(line);
-      if (!matcher.matches()) {
-        logger.debug("Unrecognizable log: {}, pattern: {}", line, matcher.pattern().toString());
-        line = nextLine();
-        if (line == null) {
-          return null;
-        }
-      } else {
-        matched = true;
-      }
-    }
-    return matcher;
-  }
-
-  @Override
-  public LogEntry next() throws IOException {
-
-    Matcher matcher;
-    while ((matcher = nextMatchedLineMatcher()) != null) {
-      try {
-        Date date = dateFormat.parse(matcher.group(dateIndex));
-        String threadName = null;
-        if (threadNameIndex > 0) {
-          threadName = matcher.group(threadNameIndex).trim();
-        }
-        LogLevel logLevel = LogLevel.DEBUG;
-        if (levelIndex > 0) {
-          logLevel = LogLevel.valueOf(matcher.group(levelIndex).trim());
-        }
-        CodeLocation codeLocation = null;
-        if (codeLocationIndex > 0) {
-          String[] codeLocationStr = matcher.group(codeLocationIndex).split(":");
-          if (codeLocationStr.length > 1) {
-            codeLocation = new CodeLocation(codeLocationStr[0].trim(), Integer.parseInt
-                (codeLocationStr[1]));
-          } else {
-            codeLocation = new CodeLocation(codeLocationStr[0].trim(), -1);
-          }
-        }
-        String content = matcher.group(contentIndex).trim();
-        return new LogEntry(date, threadName, logLevel, codeLocation, content);
-      } catch (Exception e) {
-        logger.warn("Malformed log {}", matcher.group(0), e);
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public void close() throws IOException {
-    if (reader != null) {
-      reader.close();
-    }
-  }
-
-  @Override
-  public void reset() throws IOException {
-    close();
-    logFileIdx = 0;
-    reader = new BufferedReader(new InputStreamReader(new FileInputStream(logFilePaths[0])));
-  }
-
-  enum PatternProperties {
-    PATTERN("pattern"), DATE_INDEX("date_index"), THREAD_NAME_INDEX("thread_name_index"),
-    LEVEL_INDEX("level_index"), CODE_LOCATION_INDEX("code_location_index"), CONTENT_INDEX
-        ("content_index"), DATE_PATTERN("date_pattern");
-
-    private String propertyName;
-
-    PatternProperties(String propertyName) {
-      this.propertyName = propertyName;
-    }
-
-    public String getPropertyName() {
-      return propertyName;
-    }
-  }
-}
\ No newline at end of file
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
deleted file mode 100644
index cee2b71..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/TimeSeriesStatistics.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual;
-
-import java.io.IOException;
-import java.io.Writer;
-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[] {
-      "name", "count", "meanInterval", "maxInterval", "minInterval", "meanVal", "maxVal", "minVal", "valSum"
-  };
-
-  private String name;
-  private int size = 0;
-  private double meanInterval = 0.0;
-  private long maxInterval = Long.MIN_VALUE;
-  private long minInterval = Long.MAX_VALUE;
-  private double meanVal = 0.0;
-  private double maxVal = Double.MIN_VALUE;
-  private double minVal = Double.MAX_VALUE;
-  private double valSum = 0.0;
-  
-  private Object[] statisticArray;
-
-  TimeSeriesStatistics(TimeSeries timeSeries) {
-    Date lastDate = null;
-    name = (String) timeSeries.getKey();
-    for (int i = 0; i < timeSeries.getItemCount(); i++) {
-      TimeSeriesDataItem dataItem = timeSeries.getDataItem(i);
-      Date currDate = dataItem.getPeriod().getStart();
-      double value = dataItem.getValue().doubleValue();
-      if (lastDate == null) {
-        lastDate = currDate;
-      } else {
-        long interval = currDate.getTime() - lastDate.getTime();
-        lastDate = currDate;
-        meanInterval = (meanInterval * size + interval) / (size + 1);
-        maxInterval = maxInterval < interval ? interval : maxInterval;
-        minInterval = minInterval < interval ? minInterval : interval;
-      }
-      meanVal = (meanVal * size + value) / (size + 1);
-      maxVal = maxVal < value ? value : maxVal;
-      minVal = minVal < value ? minVal : value;
-      valSum += value;
-      size ++;
-    }
-  }
-
-  public String getName() {
-    return name;
-  }
-
-  public int getSize() {
-    return size;
-  }
-
-  public Object[] toArray() {
-    if (statisticArray != null) {
-      return statisticArray;
-    }
-    statisticArray = new Object[HEADER.length];
-    int i = 0;
-    statisticArray[i++] = name;
-    statisticArray[i++] = size;
-    statisticArray[i++] = meanInterval;
-    statisticArray[i++] = maxInterval;
-    statisticArray[i++] = minInterval;
-    statisticArray[i++] = meanVal;
-    statisticArray[i++] = maxVal;
-    statisticArray[i++] = minVal;
-    statisticArray[i] = valSum;
-    return statisticArray;
-  }
-
-  public static void serializeHeader(Writer writer) throws IOException {
-    writer.write(String.join(",", HEADER) + "\n");
-  }
-  
-  public void serialize(Writer writer) throws IOException {
-    Object[] statArray = toArray();
-    StringBuilder builder = new StringBuilder(statArray[0].toString());
-    for (int i = 1; i < statArray.length; i++) {
-      builder.append(",").append(statArray[i]);
-    }
-    builder.append("\n");
-    writer.write(builder.toString());
-  }
-}
\ No newline at end of file
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
deleted file mode 100644
index bc6e7ab..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/VisualUtils.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual;
-
-public class VisualUtils {
-
-  private VisualUtils() {
-    throw new UnsupportedOperationException("Initializing a util class");
-  }
-
-  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]);
-      }
-      return ints;
-    }
-    return null;
-  }
-
-  public static String intArrayToString(int[] ints) {
-    if (ints == null) {
-      return null;
-    }
-    StringBuilder builder = new StringBuilder(String.valueOf(ints[0]));
-    for (int i = 1; i < ints.length; i ++) {
-      builder.append(",").append(ints[i]);
-    }
-    return builder.toString();
-  }
-
-  public static boolean strsContains(String[] strings, String target) {
-    for (String str : strings) {
-      if (str.equals(target)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  public static boolean intsContains(int[] ints, int target) {
-    for (int i : ints) {
-      if (i == target) {
-        return true;
-      }
-    }
-    return false;
-  }
-}
\ No newline at end of file
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
deleted file mode 100644
index 8ee4179..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/VisualizationPlan.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual;
-
-import static org.apache.iotdb.db.tools.logvisual.VisualizationPlan.PlanProperties.*;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedWriter;
-import java.io.FileInputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-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
-
-    TODO-LogVisualizer: support expression computation like; sum(measurement1 * measurement2)
-    TODO-LogVisualizer: add tag filter
- */
-public class VisualizationPlan {
-  // optional, this will be used as the title of the figure.
-  private String name = "untitled";
-
-  // required, a regex that will capture the logs to be analyzed, the interesting values
-  // (measurements and group-by tags) should be surrounded with bracelets e.g.:
-  //  contentPattern = location:(.*) temperature:(.*) pressure:(.*)
-  private Pattern contentPattern;
-  // the following 3 are optional, if not set, then it means this plan only cares whether this
-  // event happens or not and draws a scatter plot, other wise it will capture the given
-  // measurements and draw timeseries plots. Only numeric measurements are supported currently.
-  // if one of first 2 is set, the other must be set
-  // comma-separated
-  // e.g.:
-  //  measurementPositions = 2,3
-  //  legends = temperature,pressure
-  //  tagPositions = 1
-  //  then the logs will be grouped-by their locations and for each group, there will be two
-  //  timeseries describing temperature and pressure respectively
-  private int[] measurementPositions;
-  private String[] legends;
-  private int[] tagPositions;
-
-  private LogFilter logFilter;
-
-  // where the plan is stored
-  private String planFilePath;
-
-  public VisualizationPlan() {
-    logFilter = new LogFilter();
-  }
-
-  VisualizationPlan(String planFilePath) throws IOException {
-    // the plan file is a property file
-    this.planFilePath = planFilePath;
-    Properties properties = new Properties();
-    try (FileInputStream reader = new FileInputStream(planFilePath);
-        BufferedInputStream bufferedInputStream = new BufferedInputStream(reader)) {
-      properties.load(bufferedInputStream);
-    }
-
-    this.name = properties.getProperty(NAME.getPropertyName(), "untitled");
-    String patternStr = properties.getProperty(CONTENT_PATTERN.getPropertyName());
-    if (patternStr == null) {
-      throw new IOException("Bad plan, content pattern unset");
-    }
-    this.contentPattern = Pattern.compile(patternStr);
-
-    measurementPositions = VisualUtils.parseIntArray(properties.getProperty(MEASUREMENT_POSITIONS
-        .getPropertyName()));
-
-    String legendStr = properties.getProperty(LEGENDS.getPropertyName());
-    if (legendStr != null) {
-      legends = legendStr.split(",");
-    }
-
-    if (measurementPositions != null) {
-      if (legends == null || legends.length != measurementPositions.length) {
-        throw new IOException("Bad plan, the number of legends is different from the number of "
-            + "measurements");
-      }
-    }
-
-    tagPositions = VisualUtils.parseIntArray(properties.getProperty(TAG_POSITIONS.getPropertyName()));
-
-    logFilter = new LogFilter(properties);
-  }
-
-  /**
-   * parse the content in a LogEntry using contentPattern and store the parsed tags and measurements
-   * 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 content and the remaining are the groups
-      matchedValues[i - 1] = matcher.group(i);
-    }
-    if (tagPositions != null) {
-      List<String> tags = new ArrayList<>();
-      for (int pos : tagPositions) {
-        tags.add(matchedValues[pos-1]);
-      }
-      logEntry.setTags(tags);
-    }
-    if (measurementPositions != null) {
-      List<Double> measurements = new ArrayList<>();
-      for (int pos : measurementPositions) {
-        measurements.add(Double.parseDouble(matchedValues[pos-1]));
-      }
-      logEntry.setMeasurements(measurements);
-    }
-  }
-
-  public String getName() {
-    return name;
-  }
-
-  public Pattern getContentPattern() {
-    return contentPattern;
-  }
-
-  public int[] getMeasurementPositions() {
-    return measurementPositions;
-  }
-
-  public String[] getLegends() {
-    return legends;
-  }
-
-  public int[] getTagPositions() {
-    return tagPositions;
-  }
-
-  public LogFilter getLogFilter() {
-    return logFilter;
-  }
-
-  public void setName(String name) {
-    this.name = name;
-  }
-
-  public void setContentPattern(Pattern contentPattern) {
-    this.contentPattern = contentPattern;
-  }
-
-  public void setMeasurementPositions(int[] measurementPositions) {
-    this.measurementPositions = measurementPositions;
-  }
-
-  public void setLegends(String[] legends) {
-    this.legends = legends;
-  }
-
-  public void setTagPositions(int[] tagPositions) {
-    this.tagPositions = tagPositions;
-  }
-  
-  public void setPlanFilePath(String planFilePath) {
-    this.planFilePath = planFilePath;
-  }
-
-  public String getPlanFilePath() {
-    return planFilePath;
-  }
-
-  enum PlanProperties {
-    NAME("name"), CONTENT_PATTERN("content_pattern"), MEASUREMENT_POSITIONS(
-        "measurement_positions"),
-    LEGENDS("legends"), TAG_POSITIONS("tag_positions");
-
-    private String propertyName;
-
-    PlanProperties(String propertyName) {
-      this.propertyName = propertyName;
-    }
-
-    public String getPropertyName() {
-      return propertyName;
-    }
-  }
-
-  @Override
-  public String toString() {
-    return name;
-  }
-
-  public void saveAsFile() throws IOException {
-    Properties properties = saveAsProperties();
-    logFilter.saveIntoProperties(properties);
-    try (FileWriter fileWriter = new FileWriter(planFilePath);
-        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {
-      properties.store(bufferedWriter, "");
-    }
-  }
-
-  private Properties saveAsProperties() {
-    Properties properties = new Properties();
-    properties.put(PlanProperties.NAME.getPropertyName(), name);
-    properties.put(PlanProperties.CONTENT_PATTERN.getPropertyName(), contentPattern.pattern());
-    if (measurementPositions != null) {
-      properties.put(PlanProperties.MEASUREMENT_POSITIONS.getPropertyName(), VisualUtils.intArrayToString
-          (measurementPositions));
-    }
-    if (legends != null) {
-      properties.put(PlanProperties.LEGENDS.getPropertyName(), String.join(",", legends));
-    }
-    if (tagPositions != null) {
-      properties.put(PlanProperties.TAG_POSITIONS.getPropertyName(), VisualUtils.intArrayToString(tagPositions));
-    }
-    return properties;
-  }
-}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/conf/GuiPropertyKeys.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/conf/GuiPropertyKeys.java
deleted file mode 100644
index 4006bea..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/conf/GuiPropertyKeys.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.conf;
-
-/**
- * GuiPropertyKeys holds the keys of properties that store the paths chosen by the user the last
- * time he used this tool's gui for convenience.
- */
-public enum GuiPropertyKeys {
-  /**
-   * 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;
-
-  GuiPropertyKeys(String key) {
-    this.key = key;
-  }
-
-  public String getKey() {
-    return key;
-  }
-}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/exceptions/NoLogFileLoadedException.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/exceptions/NoLogFileLoadedException.java
deleted file mode 100644
index f3650cd..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/exceptions/NoLogFileLoadedException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.exceptions;
-
-public class NoLogFileLoadedException extends VisualizationException {
-
-  public NoLogFileLoadedException() {
-    super("No log file is loaded, please load a log file first");
-  }
-}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/exceptions/NoSuchPlanException.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/exceptions/NoSuchPlanException.java
deleted file mode 100644
index 17f346d..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/exceptions/NoSuchPlanException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.exceptions;
-
-public class NoSuchPlanException extends VisualizationException {
-
-  public NoSuchPlanException(String planName) {
-    super(String.format("No such plan %s", planName));
-  }
-}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/exceptions/UnmatchedContentException.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/exceptions/UnmatchedContentException.java
deleted file mode 100644
index 7e3b40a..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/exceptions/UnmatchedContentException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.exceptions;
-
-public class UnmatchedContentException extends VisualizationException {
-
-  public UnmatchedContentException(String content, String pattern) {
-    super(String.format("%s cannot match %s", content, pattern));
-  }
-}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/exceptions/VisualizationException.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/exceptions/VisualizationException.java
deleted file mode 100644
index 8e48ed6..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/exceptions/VisualizationException.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.exceptions;
-
-public class VisualizationException extends Exception {
-
-  public VisualizationException() {
-  }
-
-  public VisualizationException(String message) {
-    super(message);
-  }
-
-  public VisualizationException(String message, Throwable cause) {
-    super(message, cause);
-  }
-
-  public VisualizationException(Throwable cause) {
-    super(cause);
-  }
-}
\ No newline at end of file
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
deleted file mode 100644
index 7525001..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ClosableComboTab.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.gui;
-
-import java.util.Map;
-
-/**
- * ClosableComboTab is a ClosableTab with a comboBox.
- */
-abstract class ClosableComboTab extends ClosableTab {
-
-  private LabeledComboBox comboBox;
-
-  ClosableComboTab(String name, Map comboItems, TabCloseCallBack tabCloseCallBack) {
-    super(name, tabCloseCallBack);
-
-    comboBox = new LabeledComboBox(comboItems, this::onItemSelected, "Please select an item to "
-        + "view");
-    comboBox.setLocation(0, 10);
-    comboBox.setSize(650, 50);
-    add(comboBox);
-  }
-
-  abstract void onItemSelected(Object object);
-}
\ No newline at end of file
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
deleted file mode 100644
index 44a8932..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ClosableTab.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.gui;
-
-import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-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;
-
-  ClosableTab(String name, TabCloseCallBack closeCallBack) {
-    setName(name);
-    setLayout(null);
-
-    closeTabButton = new JButton("Close");
-    closeTabButton.setLocation(720, 5);
-    closeTabButton.setSize(new Dimension(70, 30));
-    closeTabButton.setFont(closeTabButton.getFont().deriveFont(10.0f));
-    add(closeTabButton);
-    closeTabButton.addActionListener(new AbstractAction() {
-      @Override
-      public void actionPerformed(ActionEvent e) {
-        closeCallBack.call(name);
-      }
-    });
-  }
-
-  public interface TabCloseCallBack {
-    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
deleted file mode 100644
index b317531..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/FileSelectionBox.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.gui;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import javax.swing.AbstractAction;
-import javax.swing.Box;
-import javax.swing.BoxLayout;
-import javax.swing.JButton;
-import javax.swing.JFileChooser;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JTextField;
-
-/**
- * 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 or directory).
- */
-class FileSelectionBox extends Box{
-
-  private JLabel panelName;
-  private JTextField filePathField;
-  private JButton selectFileButton;
-  private FilePathBoxSelectionCallBack callBack;
-  private int selectionMode;
-
-  FileSelectionBox(String name, FilePathBoxSelectionCallBack callBack, String
-      defaultFilePath, int selectionMode) {
-    super(BoxLayout.X_AXIS);
-    this.callBack = callBack;
-    this.selectionMode = selectionMode;
-
-    panelName = new JLabel(name);
-    filePathField = new JTextField("No file is selected");
-
-    filePathField.setEditable(false);
-    selectFileButton = new JButton("Select");
-    selectFileButton.addActionListener(new AbstractAction() {
-      @Override
-      public void actionPerformed(ActionEvent e) {
-        onSelectFileButtonClick();
-      }
-    });
-
-    Box vBox = Box.createVerticalBox();
-    vBox.add(panelName);
-    vBox.add(filePathField);
-
-    add(vBox);
-    add(Box.createHorizontalStrut(10));
-    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 " +
-            defaultFilePath + " does not exist");
-      } else {
-        filePathField.setText(defaultFilePath);
-        callBack.call(defaultFile);
-      }
-    }
-  }
-
-  private void onSelectFileButtonClick() {
-    JFileChooser fileChooser = new JFileChooser();
-    fileChooser.setFileSelectionMode(selectionMode);
-    File currentFile = new File(filePathField.getText());
-    if (currentFile.exists()) {
-      if (currentFile.isDirectory()) {
-        fileChooser.setCurrentDirectory(currentFile);
-      } else {
-        fileChooser.setCurrentDirectory(currentFile.getParentFile());
-      }
-    }
-
-    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());
-    }
-  }
-
-  interface FilePathBoxSelectionCallBack {
-    void call(File chosenFile);
-  }
-}
\ No newline at end of file
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
deleted file mode 100644
index e587a7f..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LabeledComboBox.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.gui;
-
-import java.util.Map;
-import java.util.Vector;
-import javax.swing.Box;
-import javax.swing.BoxLayout;
-import javax.swing.ComboBoxModel;
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-
-/**
- * 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;
-
-  LabeledComboBox(Map<K, V> itemMap, ComboSelectedCallback callback, String labelText) {
-    super(BoxLayout.Y_AXIS);
-
-    JLabel label = new JLabel(labelText);
-    add(label);
-
-    Vector vector = new Vector(itemMap.keySet());
-    vector.sort(null);
-    comboBoxModel = new DefaultComboBoxModel(vector);
-    comboBox = new JComboBox(comboBoxModel);
-    comboBox.setSelectedIndex(-1);
-
-    add(comboBox);
-
-    comboBox.addItemListener(e -> {
-      K key = (K) e.getItem();
-      callback.call(itemMap.get(key));
-    });
-  }
-
-  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
deleted file mode 100644
index 43174d1..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LoadLogBox.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.gui;
-
-import java.awt.event.ActionEvent;
-import java.io.IOException;
-import javax.swing.AbstractAction;
-import javax.swing.Box;
-import javax.swing.BoxLayout;
-import javax.swing.JButton;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import org.apache.iotdb.db.tools.logvisual.LogVisualizer;
-
-/**
- * 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;
-
-  LoadLogBox(LogVisualizer visualizer) {
-    super(BoxLayout.Y_AXIS);
-    this.visualizer = visualizer;
-
-    status = new JLabel("No logs are loaded");
-    loadLogButton = new JButton("Load logs");
-    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/LogVisualizationGui.java b/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LogVisualizationGui.java
deleted file mode 100644
index be634c3..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/LogVisualizationGui.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.gui;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import javax.swing.JFrame;
-import javax.swing.JOptionPane;
-import javax.swing.JTabbedPane;
-import javax.swing.WindowConstants;
-import org.apache.iotdb.db.tools.logvisual.LogVisualizer;
-import org.apache.iotdb.db.tools.logvisual.TimeSeriesStatistics;
-import org.jfree.chart.JFreeChart;
-
-/**
- * LogVisualizationGui provides a graphic way to manipulate visualization plans and view the
- * results of visualization.
- *
- * TODO-LogVisualizer: improve the layout and display
- */
-public class LogVisualizationGui {
-
-  /**
-   * if a config file is not provided, this will be used as a default config file to remember the
-   * paths that were chosen for the default paths of the next start-up.
-   */
-  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 plots of the visualized logs and the other (the
-   * ResultStatisticTab) contains a table showing the statistics of the observed logs.
-   * They will be stored 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 the next time the user uses this tool,
-   * he will not need to set the paths again.
-   */
-  private String propertyFilePath;
-  private Properties properties;
-
-  private LogVisualizationGui(String propertyFilePath) throws IOException {
-    properties = new Properties();
-    if (propertyFilePath == null) {
-      propertyFilePath = DEFAULT_CONFIG;
-    }
-    this.propertyFilePath = propertyFilePath;
-    File propertyFile = new File(propertyFilePath);
-    if (propertyFile.exists()) {
-      try (FileInputStream fileInputStream = new FileInputStream(propertyFilePath);
-      BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream)){
-        properties.load(bufferedInputStream);
-      }
-    }
-
-    this.visualizer = new LogVisualizer();
-    // this is a lie, it does not feel decorated
-    JFrame.setDefaultLookAndFeelDecorated(true);
-    mainFrame = new JFrame("Log Visualizer");
-    mainFrame.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
-    mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
-    mainFrame.setResizable(false);
-
-    tabbedPane = new JTabbedPane();
-    mainPanel = new MainPanel(visualizer, this::onPlanExecuted, properties, this::onPropertyChange);
-    tabbedPane.add(mainPanel, "Main");
-
-    mainFrame.add(tabbedPane);
-
-    mainFrame.setVisible(true);
-  }
-
-  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);
-    if (oldPlotTab != null) {
-      tabbedPane.remove(oldPlotTab);
-    }
-    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);
-    ResultStatisticTab oldTableTab = resultTablePanels.get(tabName);
-    if (oldTableTab != null) {
-      tabbedPane.remove(oldTableTab);
-    }
-    resultTablePanels.put(tabName, resultStatisticTab);
-    tabbedPane.add(resultStatisticTab);
-  }
-
-  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)) {
-      properties.store(bufferedWriter,"");
-    } catch (IOException e) {
-      JOptionPane.showMessageDialog(mainPanel, "Cannot save property files: " + e.getMessage());
-    }
-  }
-
-  public interface PropertyChangeCallback {
-    void call(String key, String value);
-  }
-
-  private void onTabClose(String tabName) {
-    ClosableTab tab = resultTablePanels.remove(tabName);
-    if (tab != null) {
-      tabbedPane.remove(tab);
-      return;
-    }
-    tab = resultPlotPanels.remove(tabName);
-    if (tab != null) {
-      tabbedPane.remove(tab);
-    }
-  }
-
-  public static void main(String[] args) throws IOException {
-    String propertyFilePath = null;
-    if (args.length > 0) {
-      propertyFilePath = args[0];
-    }
-    LogVisualizationGui gui = new LogVisualizationGui(propertyFilePath);
-  }
-
-
-}
\ No newline at end of file
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
deleted file mode 100644
index e740dce..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/MainPanel.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.gui;
-
-import java.io.File;
-import java.util.Properties;
-import javax.swing.JFileChooser;
-import javax.swing.JPanel;
-import org.apache.iotdb.db.tools.logvisual.LogVisualizer;
-import org.apache.iotdb.db.tools.logvisual.conf.GuiPropertyKeys;
-import org.apache.iotdb.db.tools.logvisual.gui.LogVisualizationGui.PropertyChangeCallback;
-import org.apache.iotdb.db.tools.logvisual.gui.PlanBox.ExecutePlanCallback;
-
-/**
- * MainPanel provides components that enable the user to choose log files 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 visualization 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;
-
-  MainPanel(LogVisualizer logVisualizer, ExecutePlanCallback executePlanCallback,
-      Properties properties, PropertyChangeCallback propertyChangeCallback) {
-    this.visualizer = logVisualizer;
-    this.propertyChangeCallback = propertyChangeCallback;
-
-    setLayout(null);
-
-    logFileSelectionBox = new FileSelectionBox("LogFilePath", this::onLogFileSelected,
-        properties.getProperty(GuiPropertyKeys.DEFAULT_LOG_FILE_PATH.getKey()), JFileChooser.FILES_AND_DIRECTORIES);
-    logFileSelectionBox.setLocation(0, 0);
-    logFileSelectionBox.setSize(380, 40);
-
-    parserPropertyBox = new FileSelectionBox("ParserPropertyFilePath",
-        this::onParserPropertySelected, properties.getProperty(GuiPropertyKeys
-        .DEFAULT_PARSER_FILE_PATH.getKey()), JFileChooser.FILES_ONLY);
-    parserPropertyBox.setLocation(0, 45);
-    parserPropertyBox.setSize(380, 40);
-
-    loadLogBox = new LoadLogBox(logVisualizer);
-    loadLogBox.setLocation(450, 0);
-    loadLogBox.setSize(300, 50);
-
-    planBox = new PlanBox(logVisualizer, executePlanCallback, properties.getProperty(GuiPropertyKeys
-        .DEFAULT_PLAN_PATH.getKey()), propertyChangeCallback);
-    planBox.setLocation(0, 100);
-    planBox.setSize(750, 430);
-
-    add(logFileSelectionBox);
-    add(parserPropertyBox);
-    add(loadLogBox);
-    add(planBox);
-  }
-
-  private void onLogFileSelected(File logFile) {
-    visualizer.setLogFile(logFile);
-    propertyChangeCallback.call(GuiPropertyKeys.DEFAULT_LOG_FILE_PATH.getKey(), logFile.getPath());
-  }
-
-  private void onParserPropertySelected(File parserPropertyFile) {
-    visualizer.setParserPropertyFile(parserPropertyFile);
-    propertyChangeCallback.call(GuiPropertyKeys.DEFAULT_PARSER_FILE_PATH.getKey(), parserPropertyFile
-        .getPath());
-  }
-}
\ No newline at end of file
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
deleted file mode 100644
index 2882d70..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/PlanBox.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.gui;
-
-import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-import javax.swing.Box;
-import javax.swing.BoxLayout;
-import javax.swing.DefaultListModel;
-import javax.swing.JButton;
-import javax.swing.JFileChooser;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JOptionPane;
-import javax.swing.JScrollPane;
-import javax.swing.ListSelectionModel;
-import javax.swing.event.ListSelectionEvent;
-import org.apache.iotdb.db.tools.logvisual.LogVisualizer;
-import org.apache.iotdb.db.tools.logvisual.TimeSeriesStatistics;
-import org.apache.iotdb.db.tools.logvisual.VisualizationPlan;
-import org.apache.iotdb.db.tools.logvisual.conf.GuiPropertyKeys;
-import org.apache.iotdb.db.tools.logvisual.exceptions.VisualizationException;
-import org.apache.iotdb.db.tools.logvisual.gui.LogVisualizationGui.PropertyChangeCallback;
-import org.jfree.chart.JFreeChart;
-
-/**
- * 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;
-  private JButton exportResultButton;
-
-  // 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;
-
-  PlanBox(LogVisualizer visualizer, ExecutePlanCallback executePlanCallback, String defaultPlanPath,
-      PropertyChangeCallback propertyChangeCallback) {
-    super(BoxLayout.X_AXIS);
-
-    this.visualizer = visualizer;
-    this.executePlanCallback = executePlanCallback;
-    this.propertyChangeCallback = propertyChangeCallback;
-
-    panelName = new JLabel("Visualization plans");
-    loadPlanButton = new JButton("Load plan");
-    executePlanButton = new JButton("Execute plan");
-    savePlanButton = new JButton("Save plan");
-    createPlanButton = new JButton("Create plan");
-    deletePlanButton = new JButton("Delete plan");
-    exportResultButton = new JButton("Export result");
-    panelName.setAlignmentX(CENTER_ALIGNMENT);
-    loadPlanButton.setAlignmentX(CENTER_ALIGNMENT);
-    executePlanButton.setAlignmentX(CENTER_ALIGNMENT);
-    savePlanButton.setAlignmentX(CENTER_ALIGNMENT);
-    createPlanButton.setAlignmentX(CENTER_ALIGNMENT);
-    deletePlanButton.setAlignmentX(CENTER_ALIGNMENT);
-    exportResultButton.setAlignmentX(CENTER_ALIGNMENT);
-
-    planListModel = new DefaultListModel<>();
-    planList = new JList<>(planListModel);
-    planList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-    scrollPane = new JScrollPane(planList);
-    add(scrollPane);
-    add(Box.createHorizontalStrut(10));
-
-    Box vBox = Box.createVerticalBox();
-    vBox.add(panelName);
-    vBox.add(loadPlanButton);
-    vBox.add(Box.createVerticalStrut(5));
-    vBox.add(savePlanButton);
-    vBox.add(Box.createVerticalStrut(5));
-    vBox.add(createPlanButton);
-    vBox.add(Box.createVerticalStrut(5));
-    vBox.add(deletePlanButton);
-    vBox.add(Box.createVerticalStrut(5));
-    vBox.add(executePlanButton);
-    vBox.add(Box.createVerticalStrut(5));
-    vBox.add(exportResultButton);
-    vBox.add(Box.createGlue());
-    add(vBox);
-
-    planDetailPanel = new PlanDetailPanel();
-    planDetailPanel.setPreferredSize(new Dimension(400, 300));
-    add(planDetailPanel);
-
-    planList.addListSelectionListener(this::onPlanSelectionChanged);
-    loadPlanButton.addActionListener(this::onLoadPlan);
-    executePlanButton.addActionListener(this::onExecutePlan);
-    savePlanButton.addActionListener(this::onPlanSave);
-    createPlanButton.addActionListener(this::onCreatePlan);
-    deletePlanButton.addActionListener(this::onDeletePlan);
-    exportResultButton.addActionListener(this::onExportResult);
-
-    // cannot export until some plan is executed
-    exportResultButton.setEnabled(false);
-
-    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.getMessage());
-      }
-    }
-  }
-
-  private void onLoadPlan(ActionEvent e) {
-    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++) {
-            builder.append(";").append(chosenFiles[i].getPath());
-          }
-          propertyChangeCallback.call(GuiPropertyKeys.DEFAULT_PLAN_PATH.getKey(), builder.toString());
-        }
-      } catch (IOException e1) {
-        JOptionPane.showMessageDialog(this, "Cannot load plan: " + e1.getMessage());
-      }
-    }
-  }
-
-  private void updatePlan(Collection<VisualizationPlan> plans) {
-    planListModel.clear();
-    for (VisualizationPlan plan : plans) {
-      planListModel.addElement(plan);
-    }
-  }
-
-  private void onExecutePlan(ActionEvent e) {
-    VisualizationPlan plan = (VisualizationPlan) planList.getSelectedValue();
-    if (plan == null) {
-      return;
-    }
-    try {
-      visualizer.executePlan(plan);
-    } catch (VisualizationException e1) {
-      JOptionPane.showMessageDialog(this, "Cannot execute plan: " + e1.getMessage());
-      return;
-    }
-    // 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);
-    exportResultButton.setEnabled(true);
-    JOptionPane.showMessageDialog(this,
-        String.format("Plan is successfully executed, found %d log groups", visualizer.getGroupNum()));
-  }
-
-  private void onPlanSelectionChanged(ListSelectionEvent e) {
-    VisualizationPlan plan = (VisualizationPlan) planList.getSelectedValue();
-    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();
-      // the name of the file will also be the name of the plan
-      String planName = chosenFile.getName();
-      if (!validateNewPlanName(planName)) {
-        JOptionPane.showMessageDialog(this, String.format("A plan named %s alread exists",
-            planName));
-        return;
-      }
-      plan.setName(planName);
-      plan.setPlanFilePath(chosenFile.getPath());
-      // 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);
-    }
-  }
-
-  private boolean validateNewPlanName(String planName) {
-    for (int i = 0; i < planListModel.getSize(); i++) {
-      if (planListModel.get(i).getName().equals(planName)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  private void onDeletePlan(ActionEvent e) {
-    VisualizationPlan plan = (VisualizationPlan) planList.getSelectedValue();
-    if (plan == null) {
-      return;
-    }
-
-    int status = JOptionPane.showConfirmDialog(this, "Do you really want to delete this plan? "
-        + "(Cannot be undone)", "confirm", JOptionPane.YES_NO_OPTION);
-    if (status == JOptionPane.YES_OPTION) {
-      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);
-    }
-  }
-
-  private void onExportResult(ActionEvent e) {
-    JFileChooser fileChooser = new JFileChooser();
-    fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
-    // let the user choose plan files or directories that contain visualization plans
-    int status = fileChooser.showOpenDialog(this);
-    if (status == JFileChooser.APPROVE_OPTION) {
-      File distDir = fileChooser.getSelectedFile();
-      try {
-        visualizer.saveResults(distDir.getPath());
-        JOptionPane.showMessageDialog(this, "Export successfully");
-      } catch (VisualizationException e1) {
-        JOptionPane.showMessageDialog(this,"Cannot export results:" + e1.getMessage());
-      }
-    }
-  }
-
-  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);
-  }
-
-}
\ No newline at end of file
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
deleted file mode 100644
index f348e88..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/PlanDetailPanel.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.gui;
-
-import java.text.SimpleDateFormat;
-import java.util.regex.Pattern;
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.JOptionPane;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-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 JTextField nameField = new JTextField();
-  private JTextField patternField = new JTextField();
-  private JTextField measurementsField = new JTextField();
-  private JTextField legendsField = new JTextField();
-  private JTextField tagField = new JTextField();
-  private JTextField levelField = new JTextField();
-  private JTextField threadNameField = new JTextField();
-  private JTextField classNameField = new JTextField();
-  private JTextField lineNumField = new JTextField();
-  private JTextField datePatternField = new JTextField();
-  private JTextField startDateField = new JTextField();
-  private JTextField endDateField = new JTextField();
-
-  PlanDetailPanel() {
-    super(null, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
-    setBorder(BorderFactory.createTitledBorder("Plan detail"));
-
-    nameField.setBorder(BorderFactory.createTitledBorder("Plan name"));
-    patternField.setBorder(BorderFactory.createTitledBorder("Content Pattern"));
-    measurementsField.setBorder(BorderFactory.createTitledBorder("Measurement positions"));
-    legendsField.setBorder(BorderFactory.createTitledBorder("Legends"));
-    tagField.setBorder(BorderFactory.createTitledBorder("Tag positions"));
-    levelField.setBorder(BorderFactory.createTitledBorder("Log level"));
-    threadNameField.setBorder(BorderFactory.createTitledBorder("Allowed thread names"));
-    classNameField.setBorder(BorderFactory.createTitledBorder("Allowed class names"));
-    lineNumField.setBorder(BorderFactory.createTitledBorder("Allowed line numbers"));
-    datePatternField.setBorder(BorderFactory.createTitledBorder("Date pattern"));
-    startDateField.setBorder(BorderFactory.createTitledBorder("Start date"));
-    endDateField.setBorder(BorderFactory.createTitledBorder("End date"));
-
-    Box box = Box.createVerticalBox();
-
-    box.add(nameField);
-    box.add(patternField);
-    box.add(measurementsField);
-    box.add(legendsField);
-    box.add(tagField);
-    box.add(levelField);
-    box.add(threadNameField);
-    box.add(classNameField);
-    box.add(lineNumField);
-    box.add(datePatternField);
-    box.add(startDateField);
-    box.add(endDateField);
-
-    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();
-  }
-
-  private void resetFields() {
-    nameField.setText("");
-    patternField.setText("");
-    measurementsField.setText("");
-    legendsField.setText("");
-    tagField.setText("");
-    levelField.setText("");
-    threadNameField.setText("");
-    classNameField.setText("");
-    lineNumField.setText("");
-    datePatternField.setText("");
-    startDateField.setText("");
-    endDateField.setText("");
-  }
-
-  private void updateFields() {
-    resetFields();
-    if (plan == null) {
-      return;
-    }
-    nameField.setText(plan.getName());
-    patternField.setText(plan.getContentPattern().pattern());
-
-    if (plan.getMeasurementPositions() != null) {
-      measurementsField.setText(VisualUtils.intArrayToString(plan.getMeasurementPositions()));
-    }
-    if (plan.getLegends() != null) {
-      legendsField.setText(String.join(",", plan.getLegends()));
-    }
-    if (plan.getTagPositions() != null) {
-      tagField.setText(VisualUtils.intArrayToString(plan.getTagPositions()));
-    }
-    levelField.setText(plan.getLogFilter().getMinLevel().name());
-    if (plan.getLogFilter().getThreadNameWhiteList() != null) {
-      threadNameField.setText(String.join(",", plan.getLogFilter().getThreadNameWhiteList()));
-    }
-    if (plan.getLogFilter().getClassNameWhiteList() != null) {
-      classNameField.setText(String.join(",", plan.getLogFilter().getClassNameWhiteList()));
-    }
-    if (plan.getLogFilter().getLineNumWhiteList() != null) {
-      lineNumField.setText(VisualUtils.intArrayToString(plan.getLogFilter().getLineNumWhiteList()));
-    }
-    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()));
-      }
-      if (plan.getLogFilter().getEndDate() != null) {
-        endDateField.setText(datePatten.format(plan.getLogFilter().getEndDate()));
-      }
-    }
-  }
-
-  /**
-   * Update the current displayed plan after it is modified amd save it to a file.
-   */
-  public void updatePlan() {
-    if (plan == null) {
-      return;
-    }
-
-    String name = nameField.getText();
-    String contentPattern = patternField.getText();
-    String measurementPositions = measurementsField.getText();
-    String legends = legendsField.getText();
-    String tagPositions = tagField.getText();
-    String logLevel = levelField.getText();
-    String allowedThreads = threadNameField.getText();
-    String allowedClasses = classNameField.getText();
-    String allowedLineNums = lineNumField.getText();
-    String datePattern = datePatternField.getText();
-    String startDate = startDateField.getText();
-    String endDate = endDateField.getText();
-
-    // validate the fields
-    if (name.matches("\\s*")) {
-      JOptionPane.showMessageDialog(this, "Name cannot be empty");
-      return;
-    }
-    if (contentPattern.matches("\\s*")) {
-      JOptionPane.showMessageDialog(this, "Content pattern cannot be empty");
-      return;
-    }
-    if (measurementPositions.matches("\\s*")) {
-      measurementPositions = null;
-    }
-    if (legends.matches("\\s*")) {
-      legends = null;
-    }
-    if (tagPositions.matches("\\s*")) {
-      tagPositions = null;
-    }
-    if (logLevel.matches("\\s*")) {
-      logLevel = LogLevel.DEBUG.name();
-    }
-    if (allowedThreads.matches("\\s*")) {
-      allowedThreads = null;
-    }
-    if (allowedClasses.matches("\\s*")) {
-      allowedClasses = null;
-    }
-    if (allowedLineNums.matches("\\s*")) {
-      allowedLineNums = null;
-    }
-    if (datePattern.matches("\\s*")) {
-      datePattern = null;
-    }
-    if (startDate.matches("\\s*")) {
-      startDate = null;
-    }
-    if (endDate.matches("\\s*")) {
-      endDate = null;
-    }
-    if ((startDate != null || endDate != null) && datePattern == null) {
-      JOptionPane.showMessageDialog(this, "Date pattern cannot be empty if either start date or"
-          + " end date is not empty");
-      return;
-    }
-
-    try {
-      plan.setName(name);
-      plan.setContentPattern(Pattern.compile(contentPattern));
-      plan.setMeasurementPositions(VisualUtils.parseIntArray(measurementPositions));
-      plan.setLegends(legends != null ? legends.split(",") : null);
-      plan.setTagPositions(VisualUtils.parseIntArray(tagPositions));
-      plan.getLogFilter().setClassNameWhiteList(allowedClasses != null ? allowedClasses.split(",")
-          : null);
-      plan.getLogFilter().setThreadNameWhiteList(allowedThreads != null ? allowedThreads.split(","
-          + "") : null);
-      plan.getLogFilter().setLineNumWhiteList(VisualUtils.parseIntArray(allowedLineNums));
-      plan.getLogFilter().setMinLevel(LogLevel.valueOf(logLevel));
-      SimpleDateFormat simpleDateFormat = datePattern != null ? new SimpleDateFormat(datePattern) :
-          null;
-      plan.getLogFilter().setDatePattern(simpleDateFormat);
-      plan.getLogFilter().setStartDate(startDate != null && simpleDateFormat != null? simpleDateFormat
-          .parse(startDate) : null);
-      plan.getLogFilter().setEndDate(endDate != null && simpleDateFormat != null ? simpleDateFormat
-          .parse(endDate) : null);
-
-      plan.saveAsFile();
-    } catch (Exception e) {
-      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
deleted file mode 100644
index 8c31aca..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ResultPlotTab.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.gui;
-
-import java.awt.GridBagLayout;
-import java.util.Map;
-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;
-
-  ResultPlotTab(String planName, Map<String, JFreeChart> charts, TabCloseCallBack closeCallBack) {
-    super(planName, charts, closeCallBack);
-
-    chartPanel = new ChartPanel(null);
-    chartPanel.setBorder(BorderFactory.createTitledBorder("Plot area"));
-    chartPanel.setLayout(new GridBagLayout());
-    chartPanel.setLocation(0, 60);
-    chartPanel.setSize(800, 480);
-    add(chartPanel);
-  }
-
-  void onItemSelected(Object chart){
-    chartPanel.setChart((JFreeChart) chart);
-  }
-}
\ No newline at end of file
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
deleted file mode 100644
index a8544d0..0000000
--- a/server/src/main/java/org/apache/iotdb/db/tools/logvisual/gui/ResultStatisticTab.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.iotdb.db.tools.logvisual.gui;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import javax.swing.Box;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.table.DefaultTableModel;
-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;
-  private JTable table;
-
-  ResultStatisticTab(String planName, Map<String, List<TimeSeriesStatistics>>
-      timeseriesStatistics, TabCloseCallBack closeCallBack) {
-    super(planName, closeCallBack);
-
-    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);
-    add(scrollPane);
-
-    Object[] header = TimeSeriesStatistics.HEADER;
-    List<TimeSeriesStatistics> allStatistics = new ArrayList<>();
-    for (List<TimeSeriesStatistics> seriesStatistics : timeseriesStatistics.values()) {
-      allStatistics.addAll(seriesStatistics);
-    }
-    allStatistics.sort(Comparator.comparing(TimeSeriesStatistics::getName));
-    Object[][] data = new Object[allStatistics.size()][];
-    for (int i = 0; i < allStatistics.size(); i++) {
-      data[i] = allStatistics.get(i).toArray();
-    }
-    tableModel = new DefaultTableModel(data, header);
-    table.setModel(tableModel);
-    // enable sort by column
-    table.setRowSorter(new TableRowSorter<>(tableModel));
-  }
-}
\ No newline at end of file
diff --git a/site/src/main/.vuepress/config.js b/site/src/main/.vuepress/config.js
index 6c613aa..17df1fc 100644
--- a/site/src/main/.vuepress/config.js
+++ b/site/src/main/.vuepress/config.js
@@ -276,7 +276,6 @@ var config = {
 							['6-System Tools/2-Memory Estimation Tool','Memory Estimation Tool'],
 							['6-System Tools/3-JMX Tool','JMX Tool'],
 							['6-System Tools/4-Watermark Tool','Watermark Tool'],
-							['6-System Tools/5-Log Visualizer','Log Visualizer'],
 							['6-System Tools/6-Query History Visualization Tool','Query History Visualization Tool'],
 							['6-System Tools/7-Monitor and Log Tools','Monitor and Log Tools']
 						]
@@ -370,7 +369,6 @@ var config = {
 							['System Tools/Memory Estimation Tool','Memory Estimation Tool'],
 							['System Tools/JMX Tool','JMX Tool'],
 							['System Tools/Watermark Tool','Watermark Tool'],
-							['System Tools/Log Visualizer','Log Visualizer'],
 							['System Tools/Query History Visualization Tool','Query History Visualization Tool'],
 							['System Tools/Monitor and Log Tools','Monitor and Log Tools'],
 							['System Tools/Load External Tsfile','Load External Tsfile']
@@ -697,7 +695,6 @@ var config = {
 							['6-System Tools/2-Memory Estimation Tool','内存预估'],
 							['6-System Tools/3-JMX Tool','JMX工具'],
 							['6-System Tools/4-Watermark Tool','水印工具'],
-							['6-System Tools/5-Log Visualizer','日志可视化工具'],
 							['6-System Tools/6-Query History Visualization Tool','查询历史可视化工具'],
 							['6-System Tools/7-Monitor and Log Tools','监控与日志工具']
 						]
@@ -791,7 +788,6 @@ var config = {
 							['System Tools/Memory Estimation Tool','内存预估'],
 							['System Tools/JMX Tool','JMX工具'],
 							['System Tools/Watermark Tool','水印工具'],
-							['System Tools/Log Visualizer','日志可视化工具'],
 							['System Tools/Query History Visualization Tool','查询历史可视化工具'],
 							['System Tools/Monitor and Log Tools','监控与日志工具'],
 							['System Tools/Load External Tsfile','加载外部tsfile文件']