OLD | NEW |
1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import logging, os, re | 5 import logging, os, re |
6 import common | 6 import common |
7 from constants import CLEANUP_LOGS_PAUSED_FILE | 7 from constants import CLEANUP_LOGS_PAUSED_FILE |
8 from autotest_lib.client.bin import utils | 8 from autotest_lib.client.bin import utils |
9 from autotest_lib.client.common_lib import error | 9 from autotest_lib.client.common_lib import error |
10 | 10 |
11 class LogReader(object): | 11 class LogReader(object): |
12 """ | 12 """ |
13 A class to read system log files. | 13 A class to read system log files. |
14 """ | 14 """ |
15 | 15 |
16 def __init__(self, filename='/var/log/messages', include_rotated_logs=True): | 16 def __init__(self, filename='/var/log/messages'): |
17 self._start_line = 1 | 17 self._start_line = 1 |
18 self._filename = filename | 18 self._filename = filename |
19 self._include_rotated_logs = include_rotated_logs | |
20 if not os.path.exists(CLEANUP_LOGS_PAUSED_FILE): | 19 if not os.path.exists(CLEANUP_LOGS_PAUSED_FILE): |
21 raise error.TestError('LogReader created without ' + | 20 raise error.TestError('LogReader created without ' + |
22 CLEANUP_LOGS_PAUSED_FILE) | 21 CLEANUP_LOGS_PAUSED_FILE) |
23 | 22 |
24 | 23 |
25 def read_all_logs(self, start=1): | |
26 """Read all content from log files. | |
27 | |
28 Generator function. | |
29 Return an iterator on the content of files. | |
30 """ | |
31 log_files = [] | |
32 line_number = 1 | |
33 if self._include_rotated_logs: | |
34 log_files.extend(utils.system_output( | |
35 'ls -tr1 %s.*' % self._filename, | |
36 ignore_status=True).splitlines()) | |
37 log_files.append(self._filename) | |
38 for log_file in log_files: | |
39 f = open(log_file) | |
40 for line in f: | |
41 if line_number >= start: | |
42 yield line | |
43 line_number += 1 | |
44 | |
45 | |
46 def set_start_by_regexp(self, index, regexp): | 24 def set_start_by_regexp(self, index, regexp): |
47 """Set the start of logs based on a regular expression. | 25 """Set the start of logs based on a regular expression. |
48 | 26 |
49 @param index: line matching regexp to start at, earliest log at 0. | 27 @param index: line matching regexp to start at, earliest log at 0. |
50 Negative numbers indicate matches since end of log. | 28 Negative numbers indicate matches since end of log. |
51 """ | 29 """ |
52 regexp_compiled = re.compile(regexp) | 30 regexp_compiled = re.compile(regexp) |
| 31 file_handle = open(self._filename, 'r') |
53 starts = [] | 32 starts = [] |
54 line_number = 1 | 33 line_number = 1 |
55 for line in self.read_all_logs(): | 34 for line in file_handle: |
56 if regexp_compiled.match(line): | 35 if regexp_compiled.match(line): |
57 starts.append(line_number) | 36 starts.append(line_number) |
58 line_number += 1 | 37 line_number += 1 |
59 if index < -len(starts): | 38 if index < -len(starts): |
60 self._start_line = 1 | 39 self._start_line = 1 |
61 elif index >= len(starts): | 40 elif index >= len(starts): |
62 self._start_line = line_number | 41 self.set_start_by_current() |
63 else: | 42 else: |
64 self._start_line = starts[index] | 43 self._start_line = starts[index] |
65 | 44 |
66 | 45 |
67 def set_start_by_reboot(self, index): | 46 def set_start_by_reboot(self, index): |
68 """ Set the start of logs (must be system log) based on reboot. | 47 """ Set the start of logs (must be system log) based on reboot. |
69 | 48 |
70 @param index: reboot to start at, earliest log at 0. Negative | 49 @param index: reboot to start at, earliest log at 0. Negative |
71 numbers indicate reboots since end of log. | 50 numbers indicate reboots since end of log. |
72 """ | 51 """ |
73 return self.set_start_by_regexp(index, | 52 return self.set_start_by_regexp(index, |
74 r'.*000\] Linux version \d') | 53 r'.*000\] Linux version \d') |
75 | 54 |
76 | 55 |
77 def set_start_by_current(self, relative=0): | 56 def set_start_by_current(self, relative=1): |
78 """ Set start of logs based on current last line. | 57 """ Set start of logs based on current last line. |
79 | 58 |
80 @param relative: line relative to current to start at. 1 means | 59 @param relative: line relative to current to start at. 1 means |
81 to start the log after this line. | 60 to start the log after this line. |
82 """ | 61 """ |
83 count = self._start_line + relative | 62 lines = utils.system_output('wc -l %s' % self._filename) |
84 for line in self.read_all_logs(start=self._start_line): | 63 self._start_line = int(lines.split(' ')[0]) + relative |
85 count += 1 | |
86 self._start_line = count | |
87 | 64 |
88 | 65 |
89 def get_logs(self): | 66 def get_logs(self): |
90 """ Get logs since the start line. | 67 """ Get logs since the start line. |
91 | 68 |
92 Start line is set by set_start_* functions or | 69 Start line is set by set_start_* functions or |
93 since the start of the file if none were called. | 70 since the start of the file if none were called. |
94 | 71 |
95 @return string of contents of file since start line. | 72 @return string of contents of file since start line. |
96 """ | 73 """ |
97 logs = [] | 74 return utils.system_output('tail -n +%d %s' % |
98 for line in self.read_all_logs(start=self._start_line): | 75 (self._start_line, self._filename)) |
99 logs.append(line) | |
100 return '\n'.join(logs) | |
101 | |
102 | 76 |
103 def can_find(self, string): | 77 def can_find(self, string): |
104 """ Try to find string in the logs. | 78 """ Try to find string in the logs. |
105 | 79 |
106 @return boolean indicating if we found the string. | 80 @return boolean indicating if we found the string. |
107 """ | 81 """ |
108 return string in self.read_all_logs(start=self._start_line) | 82 return string in self.get_logs() |
109 | 83 |
110 | 84 |
111 class LogRotationPauser(object): | 85 class LogRotationPauser(object): |
112 """ | 86 """ |
113 Class to control when logs are rotated from either server or client. | 87 Class to control when logs are rotated from either server or client. |
114 | 88 |
115 Assumes all setting of CLEANUP_LOGS_PAUSED_FILE is done by this class | 89 Assumes all setting of CLEANUP_LOGS_PAUSED_FILE is done by this class |
116 and that all calls to begin and end are properly | 90 and that all calls to begin and end are properly |
117 nested. For instance, [ a.begin(), b.begin(), b.end(), a.end() ] is | 91 nested. For instance, [ a.begin(), b.begin(), b.end(), a.end() ] is |
118 supported, but [ a.begin(), b.begin(), a.end(), b.end() ] is not. | 92 supported, but [ a.begin(), b.begin(), a.end(), b.end() ] is not. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 | 127 |
154 | 128 |
155 def end(self): | 129 def end(self): |
156 print "in end" + str(self._begun) | 130 print "in end" + str(self._begun) |
157 assert self._begun | 131 assert self._begun |
158 if not self._is_nested: | 132 if not self._is_nested: |
159 self._run('rm -f ' + CLEANUP_LOGS_PAUSED_FILE) | 133 self._run('rm -f ' + CLEANUP_LOGS_PAUSED_FILE) |
160 else: | 134 else: |
161 logging.info('Leaving existing %s file' % CLEANUP_LOGS_PAUSED_FILE) | 135 logging.info('Leaving existing %s file' % CLEANUP_LOGS_PAUSED_FILE) |
162 self._begun = False | 136 self._begun = False |
OLD | NEW |