blob: cc1f636071f845d2772c130a6db49bcb30c4813b [file] [log] [blame]
# 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