Index: /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/monitor_log/DataController.py
===================================================================
--- /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/monitor_log/DataController.py	(revision 0)
+++ /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/monitor_log/DataController.py	(working copy)
@@ -0,0 +1,70 @@
+import re
+from datetime import datetime, timedelta
+import os
+
+class DataController():
+    def __init__(self):
+        self.directory_to_extract_to = os.path.join(os.getcwd(), "tmp")
+    def get_data_list(self, content, pattern=r"\[([^]]*GMT[^]]*)\]\nthis ssl module debug info:\n\/ca\/bin\/anetstat -p ssl :\nssl statistics:\nTotal:\n[\s](\d+) connection attempts[\n|\s|\w]*(\d+) successful handshakes[\n|\s|\w]*(\d+) active connections"):
+        """
+        the return type is a list of tuple.
+        for each tuple, the content is 
+        time, connectioin_attempts, successful_handshakes and active_connections in order.
+
+        """
+        data_list = re.findall(pattern, content, re.DOTALL)
+        return data_list
+
+
+
+    def fill_miss_data(self, fisrt_time, fisrt_value, second_time, second_value, cur_time, strategy="fill_last"):
+        # fill miss data by different strategy
+        # the default method is only copy the last one
+
+        if strategy not in ["fill_last", "interpolate"]:
+            # throw exception
+            return -1
+        if strategy=="fill_last":
+            return second_value
+        if strategy=="interpolate":
+            return self.interpolate_by_min(fisrt_time, fisrt_value, second_time, second_value, cur_time)
+    def interpolate_by_min(self, fisrt_time, fisrt_value, second_time, second_value, cur_time):
+        # given timedate object to calculate the value
+        # formula y = y2+(y2-y1)/(x2-x1)*(x-x2)
+        delta_x2_x1 = (second_time-fisrt_time).seconds // 60
+        delta_x_x2 = (cur_time-second_time).seconds // 60
+        y = int(second_value) + (int(second_value)-int(fisrt_value))//delta_x2_x1*delta_x_x2
+        return y
+    def format_data(self, data_list):
+        '''
+        data_list: list[tuple(time, connection attempts, successful handshakes, active connections)]
+        make each element in data_list formated
+        make time second to zero
+        fill the missing data
+        '''
+        res_list = []
+        # initialize first two data
+        second_data_time = datetime.strptime(data_list[1][0], '%a %b %d %H:%M:%S GMT %Y')
+        second_data_time = second_data_time.replace(second=0)
+        first_data_time = second_data_time - timedelta(minutes=1)
+        print("first_data_time", first_data_time)
+        print("second_data_time", second_data_time)
+        res_list.append((first_data_time, int(data_list[0][1]), int(data_list[0][2]),  int(data_list[0][3])))
+        res_list.append((second_data_time, int(data_list[1][1]), int(data_list[1][2]),  int(data_list[1][3])))
+        data_list.pop(0) # pop the first element
+        data_list.pop(0) # pop the second element
+        while data_list:
+            cur_data_time = res_list[-1][0] + timedelta(minutes=1)
+            print("cur_data_time", cur_data_time, datetime.strptime(data_list[0][0], '%a %b %d %H:%M:%S GMT %Y').replace(second=0))
+            if cur_data_time == datetime.strptime(data_list[0][0], '%a %b %d %H:%M:%S GMT %Y').replace(second=0):
+                # no skip data, this is consecutive time by minute
+                res_list.append((cur_data_time, int(data_list[0][1]), int(data_list[0][2]),  int(data_list[0][3])))
+                data_list.pop(0)
+            else:
+                # there is a skipped data, do interpolate to fill the data
+                res_list.append((cur_data_time,
+                self.fill_miss_data(res_list[-2][0], int(res_list[-2][1]), res_list[-1][0], int(res_list[-1][1]), cur_data_time),
+                self.fill_miss_data(res_list[-2][0], int(res_list[-2][2]), res_list[-1][0], int(res_list[-1][2]), cur_data_time),
+                self.fill_miss_data(res_list[-2][0], int(res_list[-2][3]), res_list[-1][0], int(res_list[-1][3]), cur_data_time),
+                ))
+        return res_list
\ No newline at end of file
Index: /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/monitor_log/MonitorFileController.py
===================================================================
--- /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/monitor_log/MonitorFileController.py	(revision 0)
+++ /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/monitor_log/MonitorFileController.py	(working copy)
@@ -0,0 +1,52 @@
+import re
+import os
+import gzip
+import shutil
+
+class MonitorFileController():
+    def __init__(self, log_dir, directory_to_extract_to):
+        self.directory_to_extract_to = directory_to_extract_to
+        self.log_dir = log_dir
+    def get_gz_file_path(self):
+        log_path_list = []
+        for f in os.listdir(self.log_dir):
+            if re.search("monitor.out", f):
+                log_path_list.append(os.path.join(self.log_dir, f))
+        if not log_path_list:
+            print("not found monitor file in ", self.log_dir)
+        log_path_list.sort()
+        return log_path_list
+
+    def unzip_file(self, log_path_list):
+        '''unzip file to self.directory_to_extract_to
+        return the list of unzipped file path
+        '''
+        unzip_file_list = []
+        # generate directory where unzip file to
+        directory_to_extract_to = self.directory_to_extract_to
+        if not os.path.exists(directory_to_extract_to):
+            os.mkdir(directory_to_extract_to)
+
+        for file_path in log_path_list:
+            file_name = file_path.split("/")[-1] # extract file name from path
+            file_name = ".".join(file_name.split(".")[:2]) # remove extention
+            if ".gz" in file_path: 
+                # unzip zip file to @/tmp
+                with gzip.open(file_path, 'rb') as f_in:
+                    with open(os.path.join(directory_to_extract_to, file_name), 'wb') as f_out:
+                        shutil.copyfileobj(f_in, f_out)
+            else:
+                # move unzipped file to @/tmp
+                shutil.copy(file_path, directory_to_extract_to)
+            unzip_file_list.append(os.path.join(self.directory_to_extract_to, file_name))
+        return unzip_file_list
+
+    def read_file(self, file_path ="./monitor.out1"):
+        # Read the content of the file
+        with open(file_path, 'r') as file:
+            input_string = file.read()
+        # input_string = input_string.encode('utf-8')
+        return input_string
+    def delete_tmp_dir(self):
+        if os.path.exists(self.directory_to_extract_to):
+            shutil.rmtree(self.directory_to_extract_to)
\ No newline at end of file
Index: /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/monitor_log/SSLStatFacade.py
===================================================================
--- /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/monitor_log/SSLStatFacade.py	(revision 0)
+++ /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/monitor_log/SSLStatFacade.py	(working copy)
@@ -0,0 +1,87 @@
+import re
+from datetime import datetime, timedelta
+import os
+import gzip
+import shutil
+from MonitorFileController import MonitorFileController
+from DataController import DataController
+
+class SSLStatFacade():
+    def __init__(self, from_time, gz_directory="/var/crash"):
+        self.gz_directory = gz_directory
+        self.start_time = self.get_start_time(from_time)
+        self.directory_to_extract_to = os.path.join(os.getcwd(), "tmp", "sslmonitor")
+        self.format_data_list = None
+    def get_data(self):
+        '''
+        This use facade design pattern.
+        the return type is a list of tuple.
+        for each tuple, the content is 
+        time, connectioin_attempts, successful_handshakes and active_connections in order.
+        '''
+        # step1 unzip all files
+        file_controller = MonitorFileController(self.gz_directory, self.directory_to_extract_to)
+        log_path_list = file_controller.get_gz_file_path()
+        # extract data
+        data_controller = DataController()
+        data_list = []
+        is_enough_log_file = False
+        while not is_enough_log_file:
+            # for each log file, check if there is enogh log data by current datetime
+            log_file_path = file_controller.unzip_file([log_path_list.pop(0)])[0]
+            content = file_controller.read_file(file_path=log_file_path)
+            data_list = data_controller.get_data_list(content) + data_list
+            # check if log data is enough or not
+            cur_fisrt_datetime = datetime.strptime(data_list[0][0], '%a %b %d %H:%M:%S GMT %Y')
+            finish_strip = False
+            if cur_fisrt_datetime < self.start_time:
+                is_enough_log_file = True
+                # you can do binary search to make it faster here
+                for i in range(len(data_list)):
+                    if self.start_time < datetime.strptime(data_list[i][0], '%a %b %d %H:%M:%S GMT %Y'):
+                        # strip data list
+                        data_list = data_list[i:]
+                        break
+        self.format_data_list = data_controller.format_data(data_list)
+
+        file_controller.delete_tmp_dir()
+
+        return self.format_data_list
+
+    def get_start_time(self, from_time):
+        '''
+        from_time is string type, which might be now-1h, now-2h, now-6h, now-1d, now-1w, or now-1M
+        return datetime object based on from_time
+        '''
+        current_date_time = datetime.now()
+        period = from_time.split("-")[1]
+        match = re.match(r'(\d+)[hdwM]+', period)
+        period_number = int(match.group(1))
+        if "h" in period:
+            return current_date_time - timedelta(hours=period_number)
+        elif "d" in period:
+            return current_date_time - timedelta(days=period_number)
+        elif "w" in period:
+            return current_date_time - timedelta(weeks=period_number)
+        elif "M" in period:
+            # there is no consideration for the condition 29, 30, 31 days in a month
+            return current_date_time - timedelta(days=30*period_number)
+
+    def get_connection_attempts_data(self):
+        if self.format_data_list==None:
+            self.get_data()
+        return [(data[0], data[1]) for data in self.format_data_list]
+    def get_successful_handshakes_data(self):
+        if self.format_data_list==None:
+            self.get_data()
+        return [(data[0], data[2]) for data in self.format_data_list]
+    def get_active_connections_data(self):
+        if self.format_data_list==None:
+            self.get_data()
+        return [(data[0], data[3]) for data in self.format_data_list]
+if __name__=="__main__":
+    # example
+    sslStat = SSLStatFacade("now-1h", gz_directory="/ca/webui/htdocs/new")
+    connection_attempts_list = sslStat.get_connection_attempts_data()
+    for e in connection_attempts_list:
+        print(e)
Index: /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/monitor_log/__init__.py	(added)
===================================================================
--- /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/monitor_log/__init__.py	(revision 0)
+++ /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/monitor_log/__init__.py	(revision 0)
Index: /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/report.py
===================================================================
--- /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/report.py	(revision 38370)
+++ /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/hive/report.py	(working copy)
@@ -18,6 +18,7 @@
 from hive.model.legacycli import cli_parse, RegexParser, EasyParser, MATCHALL, MATCHONE
 from hive.utils import local_equirement
 import random, time, csv, codecs
+from hive.monitor_log.SSLStatFacade import SSLStatFacade
 
 TIMEFORMAT='%Y-%m-%d %X'
 chart_path = "/var/crash/statmon/"
@@ -67,7 +68,7 @@
     story.append(Paragraph(ptext, styles["alibaba"]))
     d = Draw_a_Line()
     story.append(d)
-
+    
     table_header = [unicode(_('Time'))]
     chart_ins = Line(height=370, is_animation=False)
     for each in chart_item:
@@ -636,7 +637,6 @@
     ptext = '<font size="16">' + unicode(_("System Status")) + '</font>'
     story.append(Paragraph(ptext, styles["alibaba"]))
     story.append(Spacer(1, 12))
-    
     if "cpu_usage" in system_list:
         graph_item = [{
             "item_name" : unicode(_("CPU Usage")),
@@ -645,7 +645,7 @@
         }]
         table_data = zip(system_data_dic['time'], system_data_dic['cpu_usage'])
         story = Draw_Line_Chart(unicode(_("CPU Usage(%)")), env, styles, story, system_data_dic['time'], graph_item, table_data)
-        
+
     if "mem_usage" in system_list:
         graph_item = [{
             "item_name" : unicode(_("System Memory")),
@@ -843,7 +843,6 @@
     ptext = '<font size="12">' + unicode(_("SSL Virtual Host Status")) + '</font>'
     story.append(Paragraph(ptext, styles["alibaba"]))
     story.append(Spacer(1, 12))
-    
     for each_vh in slb_vh_dic:
         ssl_vhost_dic = get_ssl_vh_sql(from_time, to_time,each_vh)
         if "vh_cc" in slb_vh_dic[each_vh]:
@@ -867,7 +866,31 @@
             
             table_data = zip(ssl_vhost_dic['time'], net_in_table, net_out_table)
             story = Draw_Line_Chart(unicode(_("Throughput"))+"(%s)"%each_vh, env, styles, story, ssl_vhost_dic['time'], graph_item, table_data, yaxis_name)
-        
+        if "mentioned_statistics" in slb_vh_dic[each_vh]:
+            sslStat = SSLStatFacade(from_time, gz_directory="/var/crash")
+            ssl_data = sslStat.get_data()
+            time_list = [e[0] for e in ssl_data]
+            connection_attempts_list = [e[1] for e in ssl_data]
+            successful_handshakes_data = [e[2] for e in ssl_data]
+            active_connections_data = [e[3] for e in ssl_data]
+            graph_item = [{
+                "item_name" : unicode(_("connection attempts")),
+                "table_item_name" : unicode(_("connection attempts")),
+                "item_value" : connection_attempts_list
+            },
+            {
+                "item_name" : unicode(_("successful handshakes")),
+                "table_item_name" : unicode(_("successful handshakes")),
+                "item_value" : successful_handshakes_data
+            },
+            {
+                "item_name" : unicode(_("active connections")),
+                "table_item_name" : unicode(_("active connections")),
+                "item_value" : active_connections_data
+            }
+            ]
+            table_data = zip(time_list, connection_attempts_list, successful_handshakes_data, active_connections_data)
+            story = Draw_Line_Chart(unicode(_("total ssl statistics")), env, styles, story, time_list, graph_item, table_data)
     return story
 
 def generateSSLRHostReport(from_time, to_time, slb_rh_dic, env, styles, story):
@@ -1282,6 +1305,16 @@
         cw.writerow([unicode(_('Throughput'))])
         cw.writerow([unicode(_('Time')), unicode(_('Inbound(bps)')), unicode(_('Outbound(bps)'))])
         cw.writerows(zip(ssl_vhost_dic['time'], value_format_1024_table(ssl_vhost_dic['net_in_list']), value_format_1024_table(ssl_vhost_dic['net_out_list'])))
+    if 'mentioned_statistics' in slb_vh_list[vh_name]:
+        sslStat = SSLStatFacade(from_time, gz_directory="/var/crash")
+        ssl_data = sslStat.get_data()
+        time_list = [e[0] for e in ssl_data]
+        connection_attempts_list = [e[1] for e in ssl_data]
+        successful_handshakes_data = [e[2] for e in ssl_data]
+        active_connections_data = [e[3] for e in ssl_data]
+        cw.writerow([unicode(_('total ssl statistics'))])
+        cw.writerow([unicode(_('Time')), unicode(_('connection attempts')), unicode(_('successful handshakes')), unicode(_('active connections'))])
+        cw.writerows(zip(time_list, connection_attempts_list, successful_handshakes_data, active_connections_data))
     return cw
 
 def generateSSLRHostCSV(cw, from_time, to_time, rh_name, slb_rh_list):
@@ -1731,6 +1764,14 @@
               "label": unicode(_('Throughput'))
             }]
         })
+    vh_list.append({
+        "value": "individual_virtual_host",
+        "label": unicode(_("Individual virtual host")) ,
+        "children": [{
+            "value": 'mentioned_statistics',
+            "label": unicode(_('mentioned statistics'))
+        }]
+    })
     return vh_list
 
 def get_ssl_real_list():
