# Time 2015-01-26 17:30:16
# Author lizanle
# Description 日志帮助类
module SystemLogHelper
  class SystemLog
    class << self
      # Time 2015-01-26 17:29:17
      # Author lizanle
      # Description 分页（支持多关键字查询）
      def logo_data(page, per, search, day)
        logs = find_all_logs day
        if logs.empty? #如果返回的是空數組，就說明日誌文件不存在
          return logs
        end
        # 根据search参数来决定是否需要查询
        keywords = search
        if keywords && !keywords.strip.blank?
          # 把keywords转化成正则表达式数组
          keywords = keywords.strip.split(/\s+/).collect! { |w| Regexp.new(w, 'i') }
          # 一条记录应该匹配每个关键字 log =~ r  是对log记录进行判断是否符合r的正则表达式
          logs = logs.find_all do |log|
            keywords.all? { |r| log =~ r && !(log =~ Regexp.new("SystemLogController#",'i')) }
          end
          #用Kaminari分页
          logs = Kaminari.paginate_array(logs).page(page).per(per).collect! { |log| parse(log) }
          #将分页后的记录的搜索结果添加样式，样式中的\0是给给r占位置的。
          logs.collect! do |log|
            keywords.each { |r| log.gsub!(r, '<span class="search_results">\0</span>')  }
            log
          end

        else
          logs = Kaminari.paginate_array(logs).page(page).per(per).collect! { |log| parse(log) }
          # 过滤掉日志中日志分析请求
          logs.collect! do |log|
             log = "" if log =~ Regexp.new("SystemLogController",'i')
             log
          end
        end
        logs
      end

      # Time 2015-01-26 17:28:57
      # Author lizanle
      # Description 清除日誌
      def clear day
        if File::exists?(logfile_path day)
          File.open(logfile_path(day), 'w') do |f|
            f.print ''
          end
        else
        end
      end

      # Time 2015-01-26 17:28:49
      # Author lizanle
      # Description 讀取日誌
      private
      def find_all_logs day
        if File::exists?(logfile_path day)
          File.open(logfile_path day) do |f|
            #打开文件，并按照正则表达式切分，逆序，最新一个记录可以扔掉（因为最新的记录永远都是访问System_log)
            f.read.split("Processing").reverse[1..-1]
          end
        else
          []
        end
      end

      # Time 2015-01-26 17:28:34
      # Author lizanle
      # Description  日志文件的路径，一般在Rails.root/log下，根据环境配置
      # 依次记录到product.log development.log test.log中
      def logfile_path day
        #将日期处理成2015-01-01的形式
        unless day.nil?
          dayArr = day.split('-')
          if dayArr[1].length == 1
            dayArr[1] = "0" + dayArr[1]
          end
          if dayArr[2].length == 1
            dayArr[2] = "0" + dayArr[2]
          end
          day = dayArr.join('-')
        end
        #如果不是當天，則需要加後綴
        if !day.nil? && !day.strip.blank? && day != Time.now.strftime("%Y-%m-%d")
          File.join(Rails.root, "log", "#{Rails.env}.log.#{day.gsub('-', '')}")
        else
          File.join(Rails.root, "log", "#{Rails.env}.log")
        end
      end

      # Time 2015-01-26 17:28:22
      # Author lizanle
      # Description 替換換行符
      def parse(log)
        ERB::Util.html_escape(log.gsub(/\e\[[\d;m]+/, '')).gsub("\n", "<br/>")
      end

      # Time 2015-01-26 17:28:07
      # Author lizanle
      # Description 定义响应正则表达式 2015-01-20 11:31:13 INFO -- Completed 200 OK in 125ms (Views: 81.0ms | ActiveRecord: 2.0ms)
      def response_regex
        'Completed \d+ \w+ in (\d+)ms \(Views: (\d+\.\d+)?ms \| ActiveRecord: (\d+\.\d+)?ms\)'
      end

      # Time 2015-01-26 17:27:51
      # Author lizanle
      # Description 将一条记录中的地址主机等都分析出来
      def get_status(paragraph)
        request_regex = 'Started GET \"(\/.*)\" for ([\d]+\.[\d]+\.[\d]+\.[\d]+) at [\d]*-([\d]*-[\d]* [\d]*:[\d]*:[\d]*)'
        controller_regex = 'Processing by ([\w]+#[\w]+)'
        page_time_regex = 'Views: \d+(\.\d+)?ms'
        activeRecord_time_regex = 'ActiveRecord: \d+(\.\d+)?ms'

        #解析请求中的正则，主机，时间
        if paragraph.match(request_regex) != nil
          request_url = paragraph.match(request_regex)[1] #正则表达式中的括号能够截取成数组
          request_host = paragraph.match(request_regex)[2]
          request_at = paragraph.match(request_regex)[3]
        end

        #解析控制器
        if paragraph.match(controller_regex) != nil
          controller_name = paragraph.match(controller_regex)[1]
        end

        #解析响应时间以及计算百分比
        if paragraph.match(response_regex) != nil
          #print(paragraph.match(response_regex))
          total_time = paragraph.match(response_regex)[1]
          page_time = paragraph.match(response_regex)[2]
          activeRecord_time = paragraph.match(response_regex)[3]
          page_time_percent = page_time.to_f/(total_time.to_f)
          activeRecord_time_percent = activeRecord_time.to_f/(total_time.to_f)
        else
        end
        #将解析结果当做一条记录数组返回
        request_status = [request_url, request_host, request_at,
                          controller_name, total_time, page_time, page_time_percent, activeRecord_time, activeRecord_time_percent]
        request_status
      end

      # Time 2015-01-26 16:41:51
      # Author lizanle
      # Description 分析日志
      public
      def analysis day
        csv = Array.new
        #如果文件不存在，则直接返回空数组
        if File::exists?(logfile_path day)
          File.open(logfile_path(day), "r:utf-8") do |file|
            paragraph = ""
            begin_flag = false
            # 对每一行进行判断
            file.each do |line|
              # 以"Started GET "开头为一个paragraph
              #print(line.match('[\d]*-([\d]*-[\d]* [\d]*:[\d]*:[\d]*) INFO -- Started GET ') == nil)
              if (line.match('[\d]*-([\d]*-[\d]* [\d]*:[\d]*:[\d]*) \w+ -- Started GET ') != nil)
                if !begin_flag
                  begin_flag = true
                  paragraph.concat(line)
                else
                  # 另一个paragraph的开头
                  if (paragraph.match(response_regex) != nil)
                    csv << get_status(paragraph)
                  end
                  begin_flag = true
                  paragraph = line
                end
              else
                if begin_flag
                  paragraph.concat(line)
                else
                end
              end
            end
          end
        end
        csv
      end
    end
  end
end

