From c0c347cf4a7c3f24b3cb88ef1d6b795bf84e35ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sven=20M=C3=A4der?= <maeder@phys.ethz.ch>
Date: Thu, 12 Apr 2018 14:38:51 +0200
Subject: [PATCH] Add input methods to tailer

---
 bin/deltalogcat.py  | 174 ++++++++++++++++++++++++++++++++++++++++++++
 bin/deltalogtail.py |  71 ------------------
 2 files changed, 174 insertions(+), 71 deletions(-)
 create mode 100755 bin/deltalogcat.py
 delete mode 100755 bin/deltalogtail.py

diff --git a/bin/deltalogcat.py b/bin/deltalogcat.py
new file mode 100755
index 0000000..47aa1e4
--- /dev/null
+++ b/bin/deltalogcat.py
@@ -0,0 +1,174 @@
+#!/usr/bin/env python3
+
+import sys
+import time
+import subprocess
+import select
+import pprint
+import json
+import argparse
+#import base64
+import lib_path
+import lib
+import dphysldap
+import tabulate
+
+update_every = 0.001
+log_path = '/var/log/ldap/'
+log_file_deltalog = log_path + 'delta.log'
+indent = 16
+
+FMT = 'plain'
+tabulate.PRESERVE_WHITESPACE = True
+
+REQ_ATTRS = frozenset({
+    'reqAuthzID',
+    'reqEntryUUID',
+    'entryCSN'
+})
+
+NODES = {
+    0: 'phd-aa1',
+    1: 'phd-aa2',
+    2: 'phd-aa3'
+}
+
+
+def getlastline(fname):
+    """Using mmap to return a copy of the last line of a file"""
+    with open(fname) as source:
+        mapping = mmap.mmap(source.fileno(), 0, prot=mmap.PROT_READ)
+    return mapping[mapping.rfind(b'\n', 0, -1)+1:]
+
+
+def sleep(start_time):
+    """After hard work, take a nap for the rest of the second"""
+    current_time = time.perf_counter()
+    elapsed_time = current_time - start_time
+    sleep_time = update_every - elapsed_time
+
+    #print('runtime {0:.3f}s, sleeping {1:.3f}s'.format(elapsed_time, sleep_time))
+
+    if sleep_time > 0:
+        time.sleep(sleep_time)
+
+
+def parse(line):
+    """Parse line and print in pretty format"""
+    req_json = line.split(' >>> ', maxsplit=1)[1]
+    req = json.loads(req_json)
+
+    sid =  int(req['attributes']['entryCSN'][0].split('#')[2])
+
+    print()
+    print('{0:<{indent}}{1}'.format('req:', req['dn'], indent=indent))
+    print('{0:<{indent}}{1}'.format('node:', NODES[sid], indent=indent))
+    print('{0:<{indent}}{1}'.format('changetype:', req['attributes']['reqType'][0], indent=indent))
+    print('{0:<{indent}}{1}'.format('entry:', req['attributes']['reqDN'][0], indent=indent))
+
+    if 'reqMod' in req['attributes']:
+        table = list()
+
+        for req_mod in req['attributes']['reqMod']:
+            row = [ ' ' * (indent - 2) ]
+            row.extend(req_mod.split(' ', maxsplit=1))
+            table.append(row)
+
+        print('modfications:')
+        print(tabulate.tabulate(table, tablefmt=FMT))
+
+        del req['attributes']['reqMod']
+
+    entry = dphysldap.Entry(req['attributes'])
+    table = list()
+    
+    for key, value in entry.items():
+        if key in REQ_ATTRS:
+            row = [ ' ' * (indent - 2), ''.join([key, ':']), str(value) ]
+            table.append(row)
+
+    print('req attrs:')
+    print(tabulate.tabulate(table, tablefmt=FMT))
+
+    print()
+    print('------------------------------------------------------------------------------------------')
+
+
+def get_input_method(arg):
+    """Determine the input method"""
+    if arg['follow']:
+        if arg['file']:
+            tail_file(arg['file'])
+        else:
+            tail_file(log_file_deltalog)
+    else:
+        if arg['file']:
+            read_file(arg['file'])
+        else:
+            read_stdin()
+
+
+def tail_file(log_file):
+    """Open the file in tail mode"""
+    fin = subprocess.Popen(['tail', '-F', log_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    poll = select.poll()
+    poll.register(fin.stdout)
+    
+    while True:
+        start_time = time.perf_counter()
+
+        if poll.poll(1):
+            line = fin.stdout.readline().decode('utf-8')
+            parse(line)
+
+        sleep(start_time)
+
+
+def read_file(log_file):
+    """Read the whole file"""
+    with open(log_file, 'r') as fin:
+        while True:
+            line = fin.readline()
+            if not line:
+                break
+            parse(line)
+
+
+def read_stdin():
+    """Read from stdin"""
+    fin = sys.stdin
+    while True:
+        line = fin.readline()
+        if not line:
+            break
+        parse(line)
+
+
+def main():
+    """Open file in non blocking mode and parse json"""
+    parser = argparse.ArgumentParser(add_help=False, description='Parse deltalog from file or stdin')
+    parser.add_argument(
+        '-f', '--follow',
+        dest='follow', action='store_const', const=True,
+        help='Output appended data as the file grows'
+    )
+    parser.add_argument(
+        'file',
+        nargs='?', type=str,
+        help='File to open'
+    )
+    parser.add_argument(
+        '-h', '--help',
+        action='help',
+        help='Show this help message and exit'
+    )
+    arg = vars(parser.parse_args())
+
+    get_input_method(arg)
+
+    sys.exit(0)
+
+
+if __name__ == '__main__':
+    main()
+    sys.exit(0)
diff --git a/bin/deltalogtail.py b/bin/deltalogtail.py
deleted file mode 100755
index 381ad56..0000000
--- a/bin/deltalogtail.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env python3
-
-import sys
-import time
-import subprocess
-import select
-import pprint
-import json
-#import base64
-
-update_every = 0.001
-log_datefmt = '%Y-%m-%d %H:%M:%S'
-log_path = '/var/log/ldap/'
-log_file_deltalog = log_path + 'delta.log'
-
-
-def getlastline(fname):
-    """Using mmap to return a copy of the last line of a file"""
-    with open(fname) as source:
-        mapping = mmap.mmap(source.fileno(), 0, prot=mmap.PROT_READ)
-    return mapping[mapping.rfind(b'\n', 0, -1)+1:]
-
-
-def sleep(start_time):
-    """After hard work, take a nap for the rest of the second"""
-    current_time = time.perf_counter()
-    elapsed_time = current_time - start_time
-    sleep_time = update_every - elapsed_time
-
-    #print('runtime {0:.3f}s, sleeping {1:.3f}s'.format(elapsed_time, sleep_time))
-
-    if sleep_time > 0:
-        time.sleep(sleep_time)
-
-
-def main():
-    """Open file in non blocking mode and parse json"""
-    f = subprocess.Popen(['tail', '-F', log_file_deltalog], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-    p = select.poll()
-    p.register(f.stdout)
-    
-    while True:
-        start_time = time.perf_counter()
-
-        if p.poll(1):
-            line = f.stdout.readline().decode('utf-8')
-            req_json = line.split(' >>> ', maxsplit=1)[1]
-            req = json.loads(req_json)
-
-            print()
-            print('req:           {}'.format(req['dn']))
-            print('changetype:    {}'.format(req['attributes']['reqType'][0]))
-            print('entry:         {}'.format(req['attributes']['reqDN'][0]))
-
-            if 'reqMod' in req['attributes']:
-                print('reqMod:')
-                pprint.pprint(req['attributes']['reqMod'], indent=14)
-                del req['attributes']['reqMod']
-
-            print('attributes:')
-            pprint.pprint(req['attributes'], indent=14)
-
-            print()
-            print('------------------------------------------------------------------------------------------')
-
-        sleep(start_time)
-
-
-if __name__ == '__main__':
-    main()
-    sys.exit(0)
-- 
GitLab