diff --git a/bin/slaptail.py b/bin/slaptail.py new file mode 100755 index 0000000000000000000000000000000000000000..6a774d3961d9b0f3481fbb27b53a6a93dec22392 --- /dev/null +++ b/bin/slaptail.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 + +import sys +import time +import subprocess +import select +import re +import argparse + +update_every = 0.001 +log_path = '/var/log/' +log_file = 'slapd' +log_file_path = log_path + log_file +rgx = dict() +connections = dict() +rgx['conn'] = re.compile(r'conn=(?P<conn>[0-9]+) .*?=.*? (?P<closed>closed)?') + + +def sleep(start_time): + """After hard work, take a nap""" + current_time = time.perf_counter() + elapsed_time = current_time - start_time + sleep_time = update_every - elapsed_time + + if sleep_time > 0: + time.sleep(sleep_time) + + +def parse(line): + """Parse line and print""" + connect = rgx['connect'].search(line) + + if(connect): + ip = connect.group('ip') + port = connect.group('port') + connection_id = connect.group('conn') + + if connection_id not in connections: + connections[connection_id] = ip, port + + print(len(connections), ip, port, line, end='') + + else: + conn = rgx['conn'].search(line) + + if(conn): + connection_id = conn.group('conn') + + if connection_id in connections: + ip, port = connections[connection_id] + + print(len(connections), ip, port, line, end='') + + if conn.group('closed'): + del connections[connection_id] + + +def tail_input(fin): + """Open input file in tail mode""" + poll = select.poll() + poll.register(fin.stdout) + + try: + while True: + start_time = time.perf_counter() + + if poll.poll(1): + line = fin.stdout.readline().decode('utf-8') + + parse(line) + + sleep(start_time) + + except KeyboardInterrupt: + sys.stdout.flush() + pass + + +def read_input(fin): + """Read from input file""" + try: + for line in fin: + parse(line) + except KeyboardInterrupt: + sys.stdout.flush() + pass + + +def main(): + """Open file in non blocking mode and parse it""" + parser = argparse.ArgumentParser( + add_help=False, + description='Parse 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( + 'pattern', + type=str, + help='Regex pattern' + ) + 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()) + + rgx['connect'] = re.compile(''.join([r'conn=(?P<conn>[0-9]+).+?ACCEPT from IP=(?P<ip>', + arg['pattern'], r'):[0-9]+ \(IP=0\.0\.0\.0:(?P<port>[0-9]+)\)'])) + + if arg['follow']: + if arg['file']: + path = arg['file'] + else: + path = log_file_path + + fin = subprocess.Popen(['tail', '-F', path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + tail_input(fin) + + else: + if arg['file']: + with open(arg['file'], 'r') as fin: + read_input(fin) + else: + fin = sys.stdin + read_input(fin) + + sys.exit(0) + + +if __name__ == '__main__': + main() + sys.exit(0)