• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3
2# Copyright 2015 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6from __future__ import print_function
7
8import re
9import time
10
11class ChaosLogAnalyzer(object):
12    """ Class to analyze the debug logs from a chaos test . """
13
14    MESSAGE_LOG_ATTEMPT_START_RE = "Connection attempt %d"
15    NET_LOG_ATTEMPT_START_RE = "%s.*PushProfileInternal finished"
16    NET_LOG_ATTEMPT_END_RE = ".*PopProfileInternal finished"
17    LOG_TIMESTAMP_DATE_RE = "[0-9]{4}-[0-9]{2}-[0-9]{2}"
18    LOG_TIMESTAMP_TIME_RE = "[0-9]{2}:[0-9]{2}:[0-9]{2}"
19    LOG_TIMESTAMP_TIMESTAMP_RE = (
20            LOG_TIMESTAMP_DATE_RE + "T" + LOG_TIMESTAMP_TIME_RE)
21    LOG_TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%S"
22    LOG_ERROR_RE = ".*ERROR:.*"
23
24    def __init__(self, message_log, net_log, logger):
25        self._net_log = net_log
26        self._message_log = message_log
27        self._log = logger
28
29    def _find_line_in_log(self, search_pattern, log_file):
30        search_regex = re.compile(search_pattern)
31        log_file.seek(0)
32        for line in log_file:
33            if search_regex.search(line):
34                return line
35
36    def _find_line_in_message_log(self, search_pattern):
37        return self._find_line_in_log(search_pattern, self._message_log)
38
39    def _find_line_in_net_log(self, search_pattern):
40        return self._find_line_in_log(search_pattern, self._net_log)
41
42    def _extract_timestamp_from_line(self, line):
43        timestamp_re = re.compile(self.LOG_TIMESTAMP_TIMESTAMP_RE)
44        timestamp_string = timestamp_re.search(line).group(0)
45        timestamp = time.strptime(timestamp_string, self.LOG_TIMESTAMP_FORMAT)
46        return timestamp
47
48    def _extract_attempt_timestamp(self, attempt_num):
49        search_pattern = self.MESSAGE_LOG_ATTEMPT_START_RE % (int(attempt_num))
50        line = self._find_line_in_message_log(search_pattern)
51        return self._extract_timestamp_from_line(line)
52
53    def _extract_log_lines(self, log_file, start_pattern=None, end_pattern=None,
54                           stop_pattern=None, match_pattern=None):
55        start_re = None
56        stop_re = None
57        end_re = None
58        match_re = None
59        start_copy = False
60        lines = ""
61        if start_pattern:
62            start_re = re.compile(start_pattern)
63        else:
64            # If there is no specific start pattern, start copying from
65            # begining of the file.
66            start_copy = True
67        if stop_pattern:
68           stop_re = re.compile(stop_pattern)
69        if end_pattern:
70            end_re = re.compile(end_pattern)
71        if match_pattern:
72            match_re = re.compile(match_pattern)
73        log_file.seek(0)
74        for line in log_file:
75            if ((start_copy == False) and (start_re and start_re.search(line))):
76                start_copy = True
77            if ((start_copy == True) and (stop_re and stop_re.search(line))):
78                break
79            if ((start_copy == True) and
80                ((not match_re) or (match_re and match_re.search(line)))):
81                    lines += line
82            if ((start_copy == True) and (end_re and end_re.search(line))):
83                break
84        return lines
85
86    def _extract_message_log_lines(self, attempt_num):
87        self._log.log_start_section("Extracted Messages Log")
88        start = self.MESSAGE_LOG_ATTEMPT_START_RE % (int(attempt_num))
89        stop = self.MESSAGE_LOG_ATTEMPT_START_RE % (int(attempt_num) + 1)
90        lines = self._extract_log_lines(
91                self._message_log, start_pattern=start, stop_pattern=stop)
92        self._log.log_to_output_file(lines)
93
94    def _extract_net_log_lines(self, timestamp):
95        self._log.log_start_section("Extracted Net Log")
96        start = self.NET_LOG_ATTEMPT_START_RE % \
97                (time.strftime(self.LOG_TIMESTAMP_FORMAT, timestamp))
98        end = self.NET_LOG_ATTEMPT_END_RE
99        lines = self._extract_log_lines(
100                self._net_log, start_pattern=start, end_pattern=end)
101        # Let's go back 1 sec and search again
102        if lines == "":
103            timestamp_secs = time.mktime(timestamp)
104            new_timestamp = time.localtime(timestamp_secs - 1)
105            start = self.NET_LOG_ATTEMPT_START_RE % \
106                    (time.strftime(self.LOG_TIMESTAMP_FORMAT, new_timestamp))
107            lines = self._extract_log_lines(
108                    self._net_log, start_pattern=start, end_pattern=end)
109        self._log.log_to_output_file(lines)
110
111    def analyze(self, attempt_num):
112        """
113        Extracts the snippet of logs for given attempt from the Chaos log file.
114
115        @param attempt_num: Attempt number for which the logs are to be
116                            extracted.
117
118        """
119        timestamp = self._extract_attempt_timestamp(attempt_num)
120        print("Attempt started at: " + time.asctime(timestamp))
121        self._extract_message_log_lines(attempt_num)
122        self._extract_net_log_lines(timestamp)
123