From 4fe144d274308e8794ed8c363a9a5904e6b5e27a Mon Sep 17 00:00:00 2001 From: Andrew Stanton Date: Thu, 6 Jun 2013 19:28:40 -0400 Subject: [PATCH] Adds a couple of useful options such as adjusting poll time with execute time --- tail.py | 49 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/tail.py b/tail.py index c9e4fc2..c16eddd 100644 --- a/tail.py +++ b/tail.py @@ -25,10 +25,11 @@ import os import sys import time +from cStringIO import StringIO class Tail(object): ''' Represents a tail command. ''' - def __init__(self, tailed_file): + def __init__(self, tailed_file, max_line_length=float("inf")): ''' Initiate a Tail instance. Check for file validity, assigns callback function to standard out. @@ -38,25 +39,38 @@ def __init__(self, tailed_file): self.check_file_validity(tailed_file) self.tailed_file = tailed_file self.callback = sys.stdout.write + self.max_line_length=max_line_length - def follow(self, s=1): + def follow(self, s=1, poll_time=.01): ''' Do a tail follow. If a callback function is registered it is called with every new line. Else printed to standard out. Arguments: s - Number of seconds to wait between each iteration; Defaults to 1. ''' - - with open(self.tailed_file) as file_: - # Go to the end of file - file_.seek(0,2) + readBuffer = StringIO() + with open(self.tailed_file, 'rb') as file_: + file_.seek(0, os.SEEK_END) while True: - curr_position = file_.tell() - line = file_.readline() - if not line: - file_.seek(curr_position) - else: + readBuffer.write(file_.read()) + readBuffer.seek(0) + complete = True + for line in readBuffer: + if not line.endswith(os.linesep): + complete = False + break + self.callback(line) - time.sleep(s) + time.sleep(s) + + # Catch the slop if the last line isn't complete + readBuffer.truncate(0) + if not complete: + if len(line) > self.max_line_length: + raise TailError("Line exceeds maximum allowed line length") + + readBuffer.write(line) + + time.sleep(poll_time) def register_callback(self, func): ''' Overrides default callback function to provided function. ''' @@ -71,8 +85,17 @@ def check_file_validity(self, file_): if os.path.isdir(file_): raise TailError("File '%s' is a directory" % (file_)) -class TailError(Exception): +class TailError(IOError): def __init__(self, msg): self.message = msg def __str__(self): return self.message + +if __name__ == '__main__': + if len(sys.argv) < 2: + print "Usage: python tail.py " + sys.exit(1) + + tail = Tail(sys.argv[1]) + tail.follow(0) +