-#!/usr/bin/env python
+#!/usr/bin/env python3
'''
-Does tail -f on log files in a given directory.
-The display is in chronological order of the logged lines,
+Does tail -f on log files in a given directory.
+The display is in chronological order of the logged lines,
given that the first column of log files is timestamp.
It can be altered to fit other formats too
'''
class mtail:
- subversion_id = "$Id$"
-
default_time_format = "%H:%M:%S"
-
+
def __init__ (self, args ):
-
+
# internal structure for tracking changes
self.files = {}
# parse command-line args : will set options and args
self.parse_args(args)
- # initialize
+ # initialize
self.scan_files()
def parse_args (self, args):
usage = """usage: %prog [options] file-or-dir ...
-example:
+example:
# %prog -e '*access*' /var/log"""
- parser=OptionParser(usage=usage,version=self.subversion_id)
+ parser=OptionParser(usage=usage)
# tail_period
parser.add_option("-p","--period", type="int", dest="tail_period", default=1,
help="Files check period in seconds")
parser.add_option("-r","--raw", action="store_true", dest="show_time", default=True,
help="Suppresses time display")
- # note for exclusion patterns
+ # note for exclusion patterns
parser.add_option("-e","--exclude", action="append", dest="excludes", default=[],
help="Exclusion pattern -- can be specified multiple times applies on files not explicitly mentioned on the command-line")
help="Shortcut for monitoring server-side SFA log files")
# verbosity
- parser.add_option("-v","--verbose", action="store_true", dest="verbose", default=False,
+ parser.add_option("-v","--verbose", action="store_true", dest="verbose", default=False,
help="Run in verbose mode")
(self.options, self.args) = parser.parse_args(args)
self.args.append("/var/log/httpd/sfa_access_log")
if self.options.verbose:
- print 'Version:',self.subversion_id
- print 'Options:',self.options
- print 'Arguments:',self.args
+ print('Options:',self.options)
+ print('Arguments:',self.args)
def file_size (self,filename):
try:
return os.stat(filename)[6]
except:
- print "WARNING: file %s has vanished"%filename
+ print("WARNING: file %s has vanished"%filename)
return 0
-
+
def number_files (self):
return len(self.files)
def scan_files (self) :
if self.options.verbose:
- print 'entering scan_files, files=',self.files
+ print('entering scan_files, files=',self.files)
# mark entries in files as pre-existing
for key in self.files:
filenames = []
for arg in self.args:
if self.options.verbose:
- print 'scan_files -- Considering arg',arg
+ print('scan_files -- Considering arg',arg)
if os.path.isfile (arg):
filenames += [ arg ]
elif os.path.isdir (arg) :
filenames += self.walk (arg)
else:
- print "mtail : no such file or directory %s -- ignored"%arg
+ print("mtail : no such file or directory %s -- ignored"%arg)
# updates files
for filename in filenames :
# known file
- if self.files.has_key(filename):
+ if filename in self.files:
size = self.file_size(filename)
offset = self.files[filename]['size']
if size > offset:
try:
self.format
self.show_now()
- print self.format%filename,"new file"
+ print(self.format%filename,"new file")
self.show_file_end(filename,0,self.file_size(filename))
except:
pass
self.files[filename]={'size':self.file_size(filename)}
-
- # cleanup
+
+ # cleanup
# avoid side-effects on the current loop basis
- read_filenames = self.files.keys()
+ read_filenames = list(self.files.keys())
for filename in read_filenames:
- if self.files[filename].has_key('old-file'):
+ if 'old-file' in self.files[filename]:
self.show_now()
- print self.format%filename,"file has gone"
+ print(self.format%filename,"file has gone")
del self.files[filename]
# compute margin and format
if not filenames:
- print sys.argv[0],": WARNING : no file in scope"
+ print(sys.argv[0],": WARNING : no file in scope")
self.format="%s"
else:
if len(filenames)==1:
self.margin=max(*[len(f) for f in filenames])
self.format="%%%ds"%self.margin
if self.options.verbose:
- print 'Current set of files:',filenames
+ print('Current set of files:',filenames)
def tail_files (self):
if self.options.verbose:
- print 'tail_files'
+ print('tail_files')
for filename in self.files:
size = self.file_size(filename)
offset = self.files[filename]['size']
def show_now (self):
if self.options.show_time:
label=time.strftime(self.options.time_format,time.localtime())
- print label,
+ print(label, end=' ')
def show_file_end (self, filename, offset, size):
try:
file.seek(offset)
line=file.read(size-offset)
self.show_now()
- print self.format%filename,'----------------------------------------'
- print line
+ print(self.format%filename,'----------------------------------------')
+ print(line)
file.close()
def show_file_when_size_decreased (self, filename, offset, size):
- print self.format%filename,'---------- file size decreased ---------',
+ print(self.format%filename,'---------- file size decreased ---------', end=' ')
if self.options.verbose:
- print 'size during last check',offset,'current size',size
+ print('size during last check',offset,'current size',size)
else:
- print ''
+ print('')
# get all files under a directory
def walk ( self, root ):
import fnmatch, os, string
-
+
# initialize
result = []
self.option_parser.print_help()
sys.exit(1)
counter = 0
-
+
fdin = sys.stdin.fileno()
while True:
## hit the period ?
for char in typed:
if char.lower() in ['l']: os.system("clear")
elif char.lower() in ['m']:
- for i in range(3) : print 60 * '='
+ for i in range(3) : print(60 * '=')
elif char.lower() in ['q']: sys.exit(0)
elif char.lower() in ['h']:
- print """l: refresh page
+ print("""l: refresh page
m: mark
q: quit
-h: help"""
-
+h: help""")
+
###
if __name__ == '__main__':
mtail (sys.argv[1:]).run()