Index: client/cros/log_reader.py |
diff --git a/client/cros/log_reader.py b/client/cros/log_reader.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cc1f636071f845d2772c130a6db49bcb30c4813b |
--- /dev/null |
+++ b/client/cros/log_reader.py |
@@ -0,0 +1,136 @@ |
+# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+import logging, os, re |
+import common |
+from constants import CLEANUP_LOGS_PAUSED_FILE |
+from autotest_lib.client.bin import utils |
+from autotest_lib.client.common_lib import error |
+ |
+class LogReader(object): |
+ """ |
+ A class to read system log files. |
+ """ |
+ |
+ def __init__(self, filename='/var/log/messages'): |
+ self._start_line = 1 |
+ self._filename = filename |
+ if not os.path.exists(CLEANUP_LOGS_PAUSED_FILE): |
+ raise error.TestError('LogReader created without ' + |
+ CLEANUP_LOGS_PAUSED_FILE) |
+ |
+ |
+ def set_start_by_regexp(self, index, regexp): |
+ """Set the start of logs based on a regular expression. |
+ |
+ @param index: line matching regexp to start at, earliest log at 0. |
+ Negative numbers indicate matches since end of log. |
+ """ |
+ regexp_compiled = re.compile(regexp) |
+ file_handle = open(self._filename, 'r') |
+ starts = [] |
+ line_number = 1 |
+ for line in file_handle: |
+ if regexp_compiled.match(line): |
+ starts.append(line_number) |
+ line_number += 1 |
+ if index < -len(starts): |
+ self._start_line = 1 |
+ elif index >= len(starts): |
+ self.set_start_by_current() |
+ else: |
+ self._start_line = starts[index] |
+ |
+ |
+ def set_start_by_reboot(self, index): |
+ """ Set the start of logs (must be system log) based on reboot. |
+ |
+ @param index: reboot to start at, earliest log at 0. Negative |
+ numbers indicate reboots since end of log. |
+ """ |
+ return self.set_start_by_regexp(index, |
+ r'.*000\] Linux version \d') |
+ |
+ |
+ def set_start_by_current(self, relative=1): |
+ """ Set start of logs based on current last line. |
+ |
+ @param relative: line relative to current to start at. 1 means |
+ to start the log after this line. |
+ """ |
+ lines = utils.system_output('wc -l %s' % self._filename) |
+ self._start_line = int(lines.split(' ')[0]) + relative |
+ |
+ |
+ def get_logs(self): |
+ """ Get logs since the start line. |
+ |
+ Start line is set by set_start_* functions or |
+ since the start of the file if none were called. |
+ |
+ @return string of contents of file since start line. |
+ """ |
+ return utils.system_output('tail -n +%d %s' % |
+ (self._start_line, self._filename)) |
+ |
+ def can_find(self, string): |
+ """ Try to find string in the logs. |
+ |
+ @return boolean indicating if we found the string. |
+ """ |
+ return string in self.get_logs() |
+ |
+ |
+class LogRotationPauser(object): |
+ """ |
+ Class to control when logs are rotated from either server or client. |
+ |
+ Assumes all setting of CLEANUP_LOGS_PAUSED_FILE is done by this class |
+ and that all calls to begin and end are properly |
+ nested. For instance, [ a.begin(), b.begin(), b.end(), a.end() ] is |
+ supported, but [ a.begin(), b.begin(), a.end(), b.end() ] is not. |
+ We do support redundant calls to the same class, such as |
+ [ a.begin(), a.begin(), a.end() ]. |
+ """ |
+ def __init__(self, host=None): |
+ self._host = host |
+ self._begun = False |
+ self._is_nested = True |
+ |
+ |
+ def _run(self, command, *args, **dargs): |
+ if self._host: |
+ return self._host.run(command, *args, **dargs).exit_status |
+ else: |
+ return utils.system(command, *args, **dargs) |
+ |
+ |
+ def begin(self): |
+ """Make sure that log rotation is disabled.""" |
+ if self._begun: |
+ return |
+ print "in begin " + str(self._begun) |
+ self._is_nested = (self._run(('[ -r %s ]' % |
+ CLEANUP_LOGS_PAUSED_FILE), |
+ ignore_status=True) == 0) |
+ print "in begin is nested: " + str(self._is_nested) |
+ if self._is_nested: |
+ print logging.__file__ |
+ logging.info('File %s was already present' % |
+ CLEANUP_LOGS_PAUSED_FILE) |
+ print 1 |
+ else: |
+ self._run('touch ' + CLEANUP_LOGS_PAUSED_FILE) |
+ print 2 |
+ self._begun = True |
+ |
+ |
+ def end(self): |
+ print "in end" + str(self._begun) |
+ assert self._begun |
+ if not self._is_nested: |
+ self._run('rm -f ' + CLEANUP_LOGS_PAUSED_FILE) |
+ else: |
+ logging.info('Leaving existing %s file' % CLEANUP_LOGS_PAUSED_FILE) |
+ self._begun = False |