blob: ecdc1e43f7adae53cb2b032d6a4ae3d0755e2454 [file] [log] [blame]
Eric Lie7c4cab2011-01-05 14:39:19 -08001# 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
3# found in the LICENSE file.
4
5import logging, os, re
6import common
7from constants import CLEANUP_LOGS_PAUSED_FILE
8from autotest_lib.client.bin import utils
9from autotest_lib.client.common_lib import error
10
11class LogReader(object):
12 """
13 A class to read system log files.
14 """
15
Eric Li288db742011-03-31 10:21:26 -070016 def __init__(self, filename='/var/log/messages', include_rotated_logs=True):
Eric Lie7c4cab2011-01-05 14:39:19 -080017 self._start_line = 1
18 self._filename = filename
Eric Li288db742011-03-31 10:21:26 -070019 self._include_rotated_logs = include_rotated_logs
Eric Lie7c4cab2011-01-05 14:39:19 -080020 if not os.path.exists(CLEANUP_LOGS_PAUSED_FILE):
21 raise error.TestError('LogReader created without ' +
22 CLEANUP_LOGS_PAUSED_FILE)
23
24
Eric Li288db742011-03-31 10:21:26 -070025 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
Eric Lie7c4cab2011-01-05 14:39:19 -080046 def set_start_by_regexp(self, index, regexp):
47 """Set the start of logs based on a regular expression.
48
49 @param index: line matching regexp to start at, earliest log at 0.
50 Negative numbers indicate matches since end of log.
51 """
52 regexp_compiled = re.compile(regexp)
Eric Lie7c4cab2011-01-05 14:39:19 -080053 starts = []
54 line_number = 1
Eric Li288db742011-03-31 10:21:26 -070055 for line in self.read_all_logs():
Eric Lie7c4cab2011-01-05 14:39:19 -080056 if regexp_compiled.match(line):
57 starts.append(line_number)
58 line_number += 1
59 if index < -len(starts):
60 self._start_line = 1
61 elif index >= len(starts):
Eric Li288db742011-03-31 10:21:26 -070062 self._start_line = line_number
Eric Lie7c4cab2011-01-05 14:39:19 -080063 else:
64 self._start_line = starts[index]
65
66
67 def set_start_by_reboot(self, index):
68 """ Set the start of logs (must be system log) based on reboot.
69
70 @param index: reboot to start at, earliest log at 0. Negative
71 numbers indicate reboots since end of log.
72 """
73 return self.set_start_by_regexp(index,
74 r'.*000\] Linux version \d')
75
76
Eric Li288db742011-03-31 10:21:26 -070077 def set_start_by_current(self, relative=0):
Eric Lie7c4cab2011-01-05 14:39:19 -080078 """ Set start of logs based on current last line.
79
80 @param relative: line relative to current to start at. 1 means
81 to start the log after this line.
82 """
Eric Li288db742011-03-31 10:21:26 -070083 count = self._start_line + relative
84 for line in self.read_all_logs(start=self._start_line):
85 count += 1
86 self._start_line = count
Eric Lie7c4cab2011-01-05 14:39:19 -080087
88
89 def get_logs(self):
90 """ Get logs since the start line.
91
92 Start line is set by set_start_* functions or
93 since the start of the file if none were called.
94
95 @return string of contents of file since start line.
96 """
Eric Li288db742011-03-31 10:21:26 -070097 logs = []
98 for line in self.read_all_logs(start=self._start_line):
99 logs.append(line)
100 return '\n'.join(logs)
101
Eric Lie7c4cab2011-01-05 14:39:19 -0800102
103 def can_find(self, string):
104 """ Try to find string in the logs.
105
106 @return boolean indicating if we found the string.
107 """
Eric Li288db742011-03-31 10:21:26 -0700108 return string in self.read_all_logs(start=self._start_line)
Eric Lie7c4cab2011-01-05 14:39:19 -0800109
110
111class LogRotationPauser(object):
112 """
113 Class to control when logs are rotated from either server or client.
114
115 Assumes all setting of CLEANUP_LOGS_PAUSED_FILE is done by this class
116 and that all calls to begin and end are properly
117 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.
119 We do support redundant calls to the same class, such as
120 [ a.begin(), a.begin(), a.end() ].
121 """
122 def __init__(self, host=None):
123 self._host = host
124 self._begun = False
125 self._is_nested = True
126
127
128 def _run(self, command, *args, **dargs):
129 if self._host:
130 return self._host.run(command, *args, **dargs).exit_status
131 else:
132 return utils.system(command, *args, **dargs)
133
134
135 def begin(self):
136 """Make sure that log rotation is disabled."""
137 if self._begun:
138 return
139 print "in begin " + str(self._begun)
140 self._is_nested = (self._run(('[ -r %s ]' %
141 CLEANUP_LOGS_PAUSED_FILE),
142 ignore_status=True) == 0)
143 print "in begin is nested: " + str(self._is_nested)
144 if self._is_nested:
145 print logging.__file__
146 logging.info('File %s was already present' %
147 CLEANUP_LOGS_PAUSED_FILE)
148 print 1
149 else:
150 self._run('touch ' + CLEANUP_LOGS_PAUSED_FILE)
151 print 2
152 self._begun = True
153
154
155 def end(self):
156 print "in end" + str(self._begun)
157 assert self._begun
158 if not self._is_nested:
159 self._run('rm -f ' + CLEANUP_LOGS_PAUSED_FILE)
160 else:
161 logging.info('Leaving existing %s file' % CLEANUP_LOGS_PAUSED_FILE)
162 self._begun = False