diff --git a/oslo_log/cmds/convert_json.py b/oslo_log/cmds/convert_json.py old mode 100644 new mode 100755 index 5fcfe32d..bed6ad74 --- a/oslo_log/cmds/convert_json.py +++ b/oslo_log/cmds/convert_json.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at @@ -16,15 +17,16 @@ import argparse import collections import functools import sys +import time from oslo_serialization import jsonutils from oslo_utils import importutils import six -termcolor = importutils.try_import('termcolor') - from oslo_log import log +termcolor = importutils.try_import('termcolor') + _USE_COLOR = False @@ -33,9 +35,29 @@ def main(): global _USE_COLOR args = parse_args() _USE_COLOR = args.color - formatter = functools.partial(console_format, args.prefix, args.locator) - for line in reformat_json(args.file, formatter): - print(line) + formatter = functools.partial( + console_format, + args.prefix, + args.locator, + loggers=args.loggers, + levels=args.levels, + ) + if args.lines: + # Read backward until we find all of our newline characters + # or reach the beginning of the file + args.file.seek(0, 2) + newlines = 0 + pos = args.file.tell() + while newlines <= args.lines and pos > 0: + pos = pos - 1 + args.file.seek(pos) + if args.file.read(1) == '\n': + newlines = newlines + 1 + try: + for line in reformat_json(args.file, formatter, args.follow): + print(line) + except KeyboardInterrupt: + sys.exit(0) def parse_args(): @@ -55,6 +77,21 @@ def parse_args(): parser.add_argument("-c", "--color", action='store_true', default=False, help="Color log levels (requires `termcolor`)") + parser.add_argument("-f", "--follow", + action='store_true', default=False, + help="Continue parsing new data until" + " KeyboardInterrupt") + parser.add_argument("-n", "--lines", + required=False, type=int, + help="Last N number of records to view." + " (May show less than N records when used" + " in conjuction with --loggers or --levels)") + parser.add_argument("--loggers", + nargs='*', default=[], + help="only return results matching given logger(s)") + parser.add_argument("--levels", + nargs='*', default=[], + help="Only return lines matching given log level(s)") args = parser.parse_args() if args.color and not termcolor: raise ImportError("Coloring requested but `termcolor` is not" @@ -85,12 +122,16 @@ def warn(prefix, msg): return "%s: %s" % (colorise('exc', prefix), msg) -def reformat_json(fh, formatter): +def reformat_json(fh, formatter, follow=False): # using readline allows interactive stdin to respond to every line while True: line = fh.readline() if not line: - break + if follow: + time.sleep(0.1) + continue + else: + break line = line.strip() if not line: continue @@ -103,11 +144,19 @@ def reformat_json(fh, formatter): yield out_line -def console_format(prefix, locator, record): +def console_format(prefix, locator, record, loggers=[], levels=[]): # Provide an empty string to format-specifiers the record is # missing, instead of failing. Doesn't work for non-string # specifiers. record = collections.defaultdict(str, record) + # skip if the record doesn't match a logger we are looking at + if loggers: + name = record.get('name') + if not any(name.startswith(n) for n in loggers): + return + if levels: + if record.get('levelname') not in levels: + return levelname = record.get('levelname') if levelname: record['levelname'] = colorise(levelname) @@ -130,7 +179,7 @@ def console_format(prefix, locator, record): tb = record.get('traceback') if tb: - for tb_line in tb.splitlines(): + for tb_line in tb: yield ' '.join([prefix, tb_line])