|  | #!/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() |