Source code for tensor.logs.follower

import os

[docs]class LogFollower(object): """Provides a class for following log files between runs :param logfile: Full path to logfile :type logfile: str :param parser: Optional parser method for log lines :type parser: str """ def __init__(self, logfile, parser=None, tmp_path="/var/lib/tensor/", history=False): self.logfile = logfile self.tmp = os.path.join(tmp_path, '%s.lf' % self.logfile.lstrip('/').replace('/','-')) self.history = history self.readLast() self.parser = parser def cleanStore(self): os.unlink(self.tmp) def storeLast(self): fi = open(self.tmp, 'wt') fi.write('%s:%s' % (self.lastSize, self.lastInode)) fi.close() def readLast(self): if os.path.exists(self.tmp): fi = open(self.tmp, 'rt') ls, li = fi.read().split(':') self.lastSize = int(ls) self.lastInode = int(li) else: if self.history: self.lastSize = 0 self.lastInode = 0 else: # Don't re-read the entire file stat = os.stat(self.logfile) self.lastSize = stat.st_size self.lastInode = stat.st_ino
[docs] def get_fn(self, fn, max_lines=None): """Passes each parsed log line to `fn` This is a better idea than storing a giant log file in memory """ stat = os.stat(self.logfile) if (stat.st_ino == self.lastInode) and (stat.st_size == self.lastSize): # Nothing new return [] # Handle rollover and rotations vaguely if (stat.st_ino != self.lastInode) or (stat.st_size < self.lastSize): self.lastSize = 0 fi = open(self.logfile, 'rt') fi.seek(self.lastSize) self.lastInode = stat.st_ino lines = 0 for i in fi: lines += 1 if max_lines and (lines > max_lines): self.storeLast() fi.close() return if '\n' in i: self.lastSize += len(i) if self.parser: line = self.parser(i.strip('\n')) else: line = i.strip('\n') fn(line) self.storeLast() fi.close()
[docs] def get(self, max_lines=None): """Returns a big list of all log lines since the last run """ rows = [] self.get_fn(lambda row: rows.append(row), max_lines=max_lines) return rows