From 9e8d971e4f0cb25dbf9b03e0e427d82092018e63 Mon Sep 17 00:00:00 2001 From: Mike Wallace Date: Sat, 7 Feb 2015 10:35:23 -0500 Subject: [PATCH 1/2] - Added Verbose mode which prints out debug information - Added key listener. This required changing the input to rawmode, and adding '\r' to print calls - C, c and Space will clear the screen. More can be added - Added time stamps to the beginning and ending of application run. --- pidcat.py | 92 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 78 insertions(+), 14 deletions(-) diff --git a/pidcat.py b/pidcat.py index c275313..1442c5a 100755 --- a/pidcat.py +++ b/pidcat.py @@ -20,12 +20,15 @@ # Originally written by Jeff Sharkey, http://jsharkey.org/ # Piping detection and popen() added by other Android team members # Package filtering and output improvements by Jake Wharton, http://jakewharton.com +# Verbose mode, input key listener and time stamps added by Mike Wallace, http://www.risesoftware.com import argparse import sys import re import subprocess from subprocess import PIPE +import os +import threading LOG_LEVELS = 'VDIWEF' LOG_LEVELS_MAP = dict([(LOG_LEVELS[i], i) for i in range(len(LOG_LEVELS))]) @@ -41,10 +44,16 @@ parser.add_argument('-c', '--clear', dest='clear_logcat', action='store_true', help='Clear the entire log before running.') parser.add_argument('-t', '--tag', dest='tag', action='append', help='Filter output by specified tag(s)') parser.add_argument('-i', '--ignore-tag', dest='ignored_tag', action='append', help='Filter output by ignoring specified tag(s)') +parser.add_argument('--verbose', dest='verbose', action='store_true', help='Shows all logcat lines and some script debub info') args = parser.parse_args() min_level = LOG_LEVELS_MAP[args.min_level.upper()] +VERBOSE = args.verbose + +if not args.package : + print "Warning: No package name provided" + # Store the names of packages for which to match all processes. catchall_package = filter(lambda package: package.find(":") == -1, args.package) # Store the name of processes to match exactly. @@ -75,6 +84,41 @@ def termcolor(fg=None, bg=None): def colorize(message, fg=None, bg=None): return termcolor(fg, bg) + message + RESET +# Defining the getch() function. Will use msvcrt's in Windows, and raw keystrokes in Linux +try: + from msvcrt import getch +except ImportError: + def getch(): + """Gets a single character from STDIO.""" + import sys + import tty + import termios + fd = sys.stdin.fileno() + old = termios.tcgetattr(fd) + try: + tty.setraw(fd) + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old) + + return ch + +class KeyEventThread(threading.Thread): + def run(self): + while True: + key = getch() + value = ord(key) + if value == 32 or value == 67 or value == 99: + # clear screen on 'c', 'C', or space + os.system("clear") + # Print this line so that the user knows they are still in adb + linebuf = colorize(' ' * (header_size - 1), bg=WHITE) + linebuf += ' Cleared. adb is running...' + print(linebuf) + elif ord(key) == 3: # Ctrl-C + adb.terminate() + exit() + def indent_wrap(message): if width == -1: return message @@ -86,7 +130,7 @@ def indent_wrap(message): next = min(current + wrap_area, len(message)) messagebuf += message[current:next] if next < len(message): - messagebuf += '\n' + messagebuf += '\r\n' messagebuf += ' ' * header_size current = next return messagebuf @@ -140,12 +184,12 @@ def allocate_color(tag): 'F': colorize(' F ', fg=BLACK, bg=RED), } -PID_START = re.compile(r'^.*: Start proc ([a-zA-Z0-9._:]+) for ([a-z]+ [^:]+): pid=(\d+) uid=(\d+) gids=(.*)$') +PID_START = re.compile(r'^.*(\d+:\d+:\d+).*: Start proc ([a-zA-Z0-9._:]+) for ([a-z]+ [^:]+): pid=(\d+) uid=(\d+) gids=(.*)$') PID_START_DALVIK = re.compile(r'^E/dalvikvm\(\s*(\d+)\): >>>>> ([a-zA-Z0-9._:]+) \[ userId:0 \| appId:(\d+) \]$') PID_KILL = re.compile(r'^Killing (\d+):([a-zA-Z0-9._:]+)/[^:]+: (.*)$') PID_LEAVE = re.compile(r'^No longer want ([a-zA-Z0-9._:]+) \(pid (\d+)\): .*$') PID_DEATH = re.compile(r'^Process ([a-zA-Z0-9._:]+) \(pid (\d+)\) has died.?$') -LOG_LINE = re.compile(r'^([A-Z])/(.+?)\( *(\d+)\): (.*?)$') +LOG_LINE = re.compile(r'^.*(\d+:\d+:\d+).* ([A-Z])/(.+?)\( *(\d+)\): (.*?)$') BUG_LINE = re.compile(r'.*nativeGetEnabledTags.*') BACKTRACE_LINE = re.compile(r'^#(.*?)pc\s(.*?)$') @@ -157,6 +201,11 @@ def allocate_color(tag): if args.use_emulator: adb_command.append('-e') adb_command.append('logcat') +adb_command.append('-v') +adb_command.append('time') + +if VERBOSE == True: + print "adb_command " + str(adb_command) # Clear log before starting logcat if args.clear_logcat: @@ -182,6 +231,13 @@ def poll(self): last_tag = None app_pid = None +if VERBOSE == True: + print "adb is runnnig..." + +# Start the thread that checks for keystrokes +keythread = KeyEventThread() +keythread.start() + def match_packages(token): if len(args.package) == 0: return True @@ -216,8 +272,8 @@ def parse_death(tag, message): def parse_start_proc(line): start = PID_START.match(line) if start is not None: - line_package, target, line_pid, line_uid, line_gids = start.groups() - return line_package, target, line_pid, line_uid, line_gids + log_time, line_package, target, line_pid, line_uid, line_gids = start.groups() + return log_time, line_package, target, line_pid, line_uid, line_gids start = PID_START_DALVIK.match(line) if start is not None: line_pid, line_package, line_uid = start.groups() @@ -232,6 +288,9 @@ def parse_start_proc(line): if len(line) == 0: break + if VERBOSE == True: + print line, "\r" + bug_line = BUG_LINE.match(line) if bug_line is not None: continue @@ -240,31 +299,36 @@ def parse_start_proc(line): if log_line is None: continue - level, tag, owner, message = log_line.groups() + log_time, level, tag, owner, message = log_line.groups() start = parse_start_proc(line) if start: - line_package, target, line_pid, line_uid, line_gids = start + log_time, line_package, target, line_pid, line_uid, line_gids = start if match_packages(line_package): pids.add(line_pid) app_pid = line_pid - linebuf = '\n' + linebuf = '\r\n' linebuf += colorize(' ' * (header_size - 1), bg=WHITE) - linebuf += indent_wrap(' Process %s created for %s\n' % (line_package, target)) + linebuf += indent_wrap(' Process %s created for %s\r\n' % (line_package, target)) linebuf += colorize(' ' * (header_size - 1), bg=WHITE) - linebuf += ' PID: %s UID: %s GIDs: %s' % (line_pid, line_uid, line_gids) - linebuf += '\n' + linebuf += ' PID: %s UID: %s GIDs: %s\r\n' % (line_pid, line_uid, line_gids) + linebuf += colorize(' ' * (header_size - 1), bg=WHITE) + linebuf += ' Start time: %s' % log_time + linebuf += '\r' print(linebuf) last_tag = None # Ensure next log gets a tag printed dead_pid, dead_pname = parse_death(tag, message) if dead_pid: pids.remove(dead_pid) - linebuf = '\n' + linebuf = '\r\n' linebuf += colorize(' ' * (header_size - 1), bg=RED) linebuf += ' Process %s (PID: %s) ended' % (dead_pname, dead_pid) - linebuf += '\n' + linebuf += '\r\n' + linebuf += colorize(' ' * (header_size - 1), bg=RED) + linebuf += ' End time: %s' % log_time + linebuf += '\r\n' print(linebuf) last_tag = None # Ensure next log gets a tag printed @@ -310,4 +374,4 @@ def parse_start_proc(line): message = matcher.sub(replace, message) linebuf += indent_wrap(message) - print(linebuf.encode('utf-8')) + print linebuf.encode('utf-8'), "\r" From 563733d05105121fc1bf254ac9ffdc14de807581 Mon Sep 17 00:00:00 2001 From: Mike Wallace Date: Wed, 18 Feb 2015 23:45:50 -0500 Subject: [PATCH 2/2] Added fixes for Jake Wharton requests. --- pidcat.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/pidcat.py b/pidcat.py index 1442c5a..fda0722 100755 --- a/pidcat.py +++ b/pidcat.py @@ -49,10 +49,10 @@ args = parser.parse_args() min_level = LOG_LEVELS_MAP[args.min_level.upper()] -VERBOSE = args.verbose +verbose = args.verbose if not args.package : - print "Warning: No package name provided" + print ("Warning: No package name provided\r") # Store the names of packages for which to match all processes. catchall_package = filter(lambda package: package.find(":") == -1, args.package) @@ -113,7 +113,7 @@ def run(self): os.system("clear") # Print this line so that the user knows they are still in adb linebuf = colorize(' ' * (header_size - 1), bg=WHITE) - linebuf += ' Cleared. adb is running...' + linebuf += ' Cleared. adb is running...\r' print(linebuf) elif ord(key) == 3: # Ctrl-C adb.terminate() @@ -204,8 +204,9 @@ def allocate_color(tag): adb_command.append('-v') adb_command.append('time') -if VERBOSE == True: - print "adb_command " + str(adb_command) +if verbose: + linebuf = "adb_command " + str(adb_command) + "\r" + print (linebuf) # Clear log before starting logcat if args.clear_logcat: @@ -231,8 +232,8 @@ def poll(self): last_tag = None app_pid = None -if VERBOSE == True: - print "adb is runnnig..." +if verbose: + print ("adb is runnnig...\r") # Start the thread that checks for keystrokes keythread = KeyEventThread() @@ -288,8 +289,9 @@ def parse_start_proc(line): if len(line) == 0: break - if VERBOSE == True: - print line, "\r" + if verbose: + linebuf = line + "\r" + print (linebuf) bug_line = BUG_LINE.match(line) if bug_line is not None: @@ -374,4 +376,7 @@ def parse_start_proc(line): message = matcher.sub(replace, message) linebuf += indent_wrap(message) - print linebuf.encode('utf-8'), "\r" + linebuf += "\r" + + #~ print (linebuf.encode('utf-8')) + print (linebuf)