Home | History | Annotate | Download | only in server
      1 #!/usr/bin/python
      2 
      3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 """ Return the time difference between two logfile entries
      8 """
      9 
     10 import logging
     11 import optparse
     12 import os
     13 import re
     14 import sys
     15 import time
     16 
     17 logger = logging.getLogger('log_time_diff')
     18 handler = logging.StreamHandler(file('/dev/stderr', 'w'))
     19 formatter = logging.Formatter('\tlog_time_diff: %(levelname)s\t%(message)s')
     20 handler.setFormatter(formatter)
     21 logger.addHandler(handler)
     22 
     23 
     24 class StampParser(object):
     25     saved_msgs = '/var/tmp/messages.autotest_start'
     26     def __init__(self, from_str, to_str, start = None):
     27         self.from_re = re.compile(from_str)
     28         self.to_re = re.compile(to_str)
     29         self.start_line = None
     30         self.end_line = None
     31         if start:
     32             self.start = self.syslog_to_float(start)
     33         else:
     34             if os.path.exists(self.saved_msgs):
     35                 for line in file(self.saved_msgs):
     36                     pass
     37                 self.start = self.syslog_to_float(line.split(' ')[0])
     38 
     39     def parse_file(self, filename):
     40         for line in file(filename):
     41             if self.from_re.search(line):
     42                 self.end_line = None
     43                 self.start_line = line
     44             if self.to_re.search(line):
     45                 self.end_line = line
     46 
     47     def syslog_to_float(self, syslog_time):
     48         # Lines end up like 2011-05-13T07:38:05.238129-07:00 ...
     49         date, sep, fraction = syslog_time.partition('.')
     50         int_time = time.mktime(time.strptime(date, '%Y-%m-%dT%H:%M:%S'))
     51         return float('%d.%s' % (int_time, re.split('[+-]', fraction)[0]))
     52 
     53     def results(self):
     54         if not self.start_line or not self.end_line:
     55             logger.error('Could not find strings in file')
     56             return '-'
     57 
     58         logger.debug('Start line: %s', self.start_line)
     59         logger.debug('End line: %s', self.end_line)
     60 
     61         syslog_from = self.start_line.split(' ')[0]
     62         syslog_from_time = self.syslog_to_float(syslog_from)
     63         if self.start and syslog_from_time < self.start:
     64             logger.error('Search string only appears before start time!')
     65             return '-'
     66 
     67         from_match = re.search('kernel:\s*\[\s*([0-9.]*)', self.start_line)
     68         to_match = re.search('kernel:\s*\[\s*([0-9.]*)', self.end_line)
     69         if from_match and to_match:
     70             # Lines end up like <syslog time> host kernel: [1307112.080338] ...
     71             logger.info('Using kernel timestamp %s %s' %
     72                          (from_match.group(1), to_match.group(1)))
     73             from_time = float(from_match.group(1))
     74             to_time = float(to_match.group(1))
     75         else:
     76             syslog_to = self.end_line.split(' ')[0]
     77             logger.info('Using syslog timestamp %s %s' %
     78                          (syslog_from, syslog_to))
     79             from_time = syslog_from_time
     80             to_time = self.syslog_to_float(syslog_to)
     81         return (to_time - from_time)
     82 
     83 
     84 def main(argv):
     85     parser = optparse.OptionParser('Usage: %prog [options...]')
     86     parser.add_option('--from', dest='from_str',
     87                       help='First regexp to search for')
     88     parser.add_option('--to', dest='to_str',
     89                       help='Second regexp to search for')
     90     parser.add_option('--file', dest='file', default='/var/log/messages',
     91                       help='File to search for regexps in')
     92     parser.add_option('--no-rotate', dest='no_rotate', action='store_true',
     93                       help='Do not search in file.1 for the same expression')
     94     parser.add_option('--start', dest='start',
     95                       help='Do not accept events that start before this time')
     96     parser.add_option('--debug', dest='debug', action='store_true',
     97                       help='Show extra verbose messages')
     98     (options, args) = parser.parse_args(argv[1:])
     99 
    100     if not options.from_str or not options.to_str:
    101         parser.error('Required arguments: --from=<from_re> --to=<to_re>')
    102 
    103 
    104     if options.debug:
    105         logger.setLevel(logging.DEBUG)
    106     else:
    107         logger.setLevel(logging.INFO)
    108 
    109     parser = StampParser(options.from_str, options.to_str, options.start)
    110 
    111     # If file rotation is enabled, try to parse previous file
    112     if not options.no_rotate:
    113         rotate_file = '%s.1' % options.file
    114         if os.path.exists(rotate_file):
    115             parser.parse_file(rotate_file)
    116 
    117     parser.parse_file(options.file)
    118     print parser.results()
    119 
    120 if __name__ == '__main__':
    121     main(sys.argv)
    122