Created
September 7, 2016 16:57
-
-
Save dunkelstern/1d34459e9f6b7747363584b8469419d8 to your computer and use it in GitHub Desktop.
ScribeJS commandline logfile dumper and filtering tool (python 3)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import json | |
import argparse | |
import itertools | |
import time | |
from dateutil.parser import parse | |
import datetime | |
# date parser | |
class ParseDate(argparse.Action): | |
def __init__(self, option_strings, dest, nargs=None, **kwargs): | |
super().__init__(option_strings, dest, **kwargs) | |
def __call__(self, parser, namespace, values, option_string=None): | |
setattr(namespace, self.dest, parse(values)) | |
# simple follow iterator | |
def follow(fp): | |
fp.seek(0,2) # Go to the end of the file | |
while True: | |
line = fp.readline() | |
if not line: | |
time.sleep(1) # Sleep briefly | |
continue | |
yield line | |
# argument parser setup | |
parser = argparse.ArgumentParser(description='Show a ScribeJS logfile.') | |
parser.add_argument( | |
'-t', '--tag', | |
type=str, | |
action='append', | |
nargs=1, | |
help='only show log lines with this tag' | |
) | |
parser.add_argument( | |
'--from', | |
type=str, | |
action=ParseDate, | |
nargs=1, | |
dest='from_date', | |
help='earliest date to show' | |
) | |
parser.add_argument( | |
'--to', | |
type=str, | |
action=ParseDate, | |
nargs=1, | |
dest='to_date', | |
help='latest date to show' | |
) | |
parser.add_argument( | |
'--type', | |
type=str, | |
nargs=1, | |
dest='type', | |
help='type of log messages to show (log|error|info)' | |
) | |
parser.add_argument( | |
'--file', | |
type=str, | |
nargs=1, | |
action='append', | |
dest='file_filter', | |
help='only show log entries from that file' | |
) | |
parser.add_argument( | |
'-c', '--color', | |
action='store_true', | |
help='if this flag is set display original colored ScribeJS output' | |
) | |
parser.add_argument( | |
'-f', '--follow', | |
action='store_true', | |
dest='follow', | |
help='follow the log output while the file is written to (like tail -f)' | |
) | |
parser.add_argument( | |
'file', | |
nargs='*', | |
type=str, | |
help='file to process' | |
) | |
args = parser.parse_args() | |
if args.tag: # flatmap tag list | |
args.tag = list(itertools.chain(*args.tag)) | |
if args.file_filter: # flatmap file filter list | |
args.file_filter = list(itertools.chain(*args.file_filter)) | |
# bail out on invalid parameter combinations | |
if args.follow and len(args.file) > 1: | |
print("You cannot follow multiple files currently!") | |
exit(1) | |
for file in args.file: | |
# if we're going to show multiple files display file headers | |
if len(args.file) > 1: | |
print(40 * '-') | |
print(file) | |
print(40 * '-') | |
# open the file | |
with open(file, 'r') as fp: | |
# determine if we follow the file or just dump it completely | |
iterator = fp | |
if args.follow: | |
iterator = follow(fp) | |
# iterate over lines | |
for line in iterator: | |
# parse object | |
j = json.loads(line) | |
display = True | |
# apply type filter | |
if args.type: | |
display = (j['type'] == args.type[0]) | |
# apply tag filter (tags are _OR_) | |
if args.tag and display: | |
display = False | |
for tag in j['context']['tags']: | |
if tag in args.tag: | |
display = True | |
break | |
# apply from and to date filters | |
t = datetime.datetime.utcfromtimestamp(j['context']['time']/1000) | |
if args.from_date and display: | |
display = t > args.from_date | |
if args.to_date and display: | |
display = t < args.to_date | |
# apply file name filter | |
if args.file_filter and display: | |
display = False | |
for file_filter in args.file_filter: | |
if j['context']['location']['filename'] == file_filter: | |
display = True | |
break | |
# all filters determined we want to display the line? | |
if display: | |
# if the user chose --color, we just dump the original line with fixed indents | |
if args.color: | |
indent = len(j['contextString']) | |
esc = j['contextString'].count('\u001b') | |
indent -= esc * 5 | |
print(j['message'].replace('\n', '\n' + (indent * ' '))) | |
else: | |
# user did not want color, build a log line ourselves | |
indent = 20 | |
tags = '' | |
# exclude tags the user filtered for as they have to be there | |
for tag in j['context']['tags']: | |
if not args.tag or tag not in args.tag: | |
tags += ' [' + tag + ']' | |
indent += len(tags) | |
# fix indent | |
msg = j['argsString'].replace('\n', '\n' + (indent * ' ')) | |
# print log line | |
print('{:%Y-%m-%d %H:%M:%S}{} {}'.format(t, tags, msg)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment