this is the python3 branch, so always use python3-mod_wsgi
[myplc.git] / bin / mtail.py
index 41466cf..62af09e 100755 (executable)
@@ -1,35 +1,36 @@
-#!/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
 '''
 
 import os, sys, time
+import select
+import sys, tty, termios
+
 from optparse import OptionParser
 
 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")
@@ -43,7 +44,7 @@ example:
        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")
 
@@ -53,7 +54,7 @@ example:
                           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)
@@ -75,17 +76,16 @@ example:
             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)
 
@@ -94,7 +94,7 @@ example:
     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:
@@ -104,18 +104,18 @@ example:
        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:
@@ -133,24 +133,24 @@ example:
                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:
@@ -160,12 +160,12 @@ example:
                 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']
@@ -176,7 +176,7 @@ example:
     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:
@@ -187,21 +187,21 @@ example:
        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 = []
 
@@ -236,8 +236,9 @@ example:
            self.option_parser.print_help()
            sys.exit(1)
        counter = 0
-    
-       while 1:
+
+        fdin = sys.stdin.fileno()
+       while True:
            ## hit the period ?
            # dont do this twice at startup
            if (counter !=0 and counter % self.options.rescan_period == 0):
@@ -248,6 +249,23 @@ example:
 
            time.sleep(1)
            counter += 1
+            # react on some keys - rough but convenient
+            if os.isatty(fdin):
+                # read stdin
+                typed=[]
+                while select.select([sys.stdin,],[],[],0.0)[0]:
+                    typed.append(sys.stdin.read(1))
+#                print 'found chars',typed
+                for char in typed:
+                    if char.lower() in ['l']: os.system("clear")
+                    elif char.lower() in ['m']:
+                        for i in range(3) : print(60 * '=')
+                    elif char.lower() in ['q']: sys.exit(0)
+                    elif char.lower() in ['h']:
+                        print("""l: refresh page
+m: mark
+q: quit
+h: help""")
 
 ###
 if __name__ == '__main__':