blob: d013efa6c335bdcc94a453c30588016b0cce69b7 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2017 The Fuchsia Authors
#
# Use of this source code is governed by a MIT-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT
"""
This tool will color the lines from loglistener
Example usage #1:
# Colorize log lines, with all messages from the same thread in the same color
loglistener | scripts/colorize_logs -t
Example usage #2:
# Colorize log lines, with all messages from the same process in the same color
loglistener | scripts/colorize_logs
Example usage #3:
# Print the colorization of log.txt to stdout
# Identical to `scripts/colorize_logs < log.txt`
scripts/colorize_logs log.txt
Example usage #4:
# Colorize all ERROR and INFO lines in log.txt
scripts/colorize_logs -r ERROR -r INFO log.txt
Example usage #5:
# Colorize all lines with drv='<something>' in log.txt with distinct colors
# for each <something>
scripts/colorize_logs -r "drv='[^']*'" log.txt
"""
import argparse
import re
import sys
BASE_COLORS = [
#'\033[40m', # black
'\033[91m', # red
'\033[92m', # green
'\033[93m', # yellow
'\033[94m', # blue
'\033[95m', # magenta
'\033[66m', # cyan
#'\033[47m', # white
]
RESET_BG = '\033[49m'
RESET_FG = '\033[39m'
class ColorAssigner(object):
def __init__(self, colors):
self.lru = list(colors)
self.task_colors = { }
def get_bg_color(self, task_id):
if task_id not in self.task_colors:
c = self.lru.pop(0)
self.task_colors[task_id] = c
else:
c = self.task_colors[task_id]
self.lru.remove(c)
self.lru.append(c)
return c
PROCESS_RE = r'^\[\d+\.\d+] (\d+)[\.:]\d+> .*$'
THREAD_RE = r'^\[\d+\.\d+] (\d+[\.:]\d+)> .*$'
def main():
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("--process", "-p", dest="patterns", action="append_const",
const=PROCESS_RE, help="Color code by process (default)")
parser.add_argument("--thread", "-t", dest="patterns", action="append_const",
const=THREAD_RE, help="Color code by thread")
parser.add_argument("--regex", "-r", dest="patterns", action="append",
help="Color by matching regexp")
parser.add_argument("input", nargs='?', action="store", default=None,
help="The file to colorize. Defaults to stdin")
args = parser.parse_args()
if args.input:
f = open(args.input, 'r')
else:
f = sys.stdin
# If no patterns were specified, use the process pattern.
if not args.patterns:
args.patterns = [PROCESS_RE]
# Define the identifier extractor. It should be in group 1.
patterns = []
for pattern in args.patterns:
regex = re.compile(pattern)
if not regex.groups:
# if there's no group, wrap the pattern
regex = re.compile(r'^.*(' + pattern + r').*$')
patterns.append(regex)
assigner = ColorAssigner(BASE_COLORS);
while True:
line = f.readline()
if not line:
break
line = line.strip()
matched = False
for line_re in patterns:
m = line_re.match(line)
if m:
matched = True
task_id = m.group(1)
color = assigner.get_bg_color(task_id)
# Use join to avoid python putting a space between each value being
# printed.
print ''.join([color, line, RESET_BG, RESET_FG])
sys.stdout.flush()
break
if not matched:
print line
sys.stdout.flush()
if __name__ == '__main__':
main()