mirror of
https://github.com/imcarlost/pidcat-repl.git
synced 2026-08-08 23:17:43 -04:00
Initial import.
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
PID Cat
|
||||
=======
|
||||
|
||||
An update to Jeff Sharkey's excellent [logcat color script][1] which only shows
|
||||
log entries for processes from a specific application package.
|
||||
|
||||
During application development you often want to only display log messages
|
||||
coming from your app. Unfortunately, because the process ID changes every time
|
||||
you deploy to the phone it becomes a challenge to grep for the right thing.
|
||||
|
||||
This script solves that problem by filtering by application package. Supply the
|
||||
target pacakge as the sole argument to the python script and enjoy a more
|
||||
convenient development process.
|
||||
|
||||
./pidcat.py com.oprah.bees.android
|
||||
|
||||
|
||||
Here is an example of the output when running for Twitter and Google Plus
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[1]: http://jsharkey.org/blog/2009/04/22/modifying-the-android-logcat-stream-for-full-color-debugging/
|
||||
@@ -0,0 +1,191 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
'''
|
||||
Copyright 2009, The Android Open Source Project
|
||||
|
||||
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
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
'''
|
||||
|
||||
# Script to highlight adb logcat output for console
|
||||
# Written by Jeff Sharkey, http://jsharkey.org/
|
||||
# Piping detection and popen() added by other Android team members
|
||||
# Package name restriction by Jake Wharton, http://jakewharton.com
|
||||
|
||||
import os, sys, re, fcntl, termios, struct
|
||||
from StringIO import StringIO
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print 'Target package name required.'
|
||||
print
|
||||
print 'Usage: %s com.example.foo' % sys.argv[0]
|
||||
sys.exit(1)
|
||||
package = sys.argv[1]
|
||||
|
||||
# unpack the current terminal width/height
|
||||
data = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234')
|
||||
HEIGHT, WIDTH = struct.unpack('hh',data)
|
||||
|
||||
TAG_WIDTH = 22
|
||||
HEADER_SIZE = TAG_WIDTH + 1 + 3 + 1 # space, level, space
|
||||
|
||||
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
|
||||
|
||||
def colorize(message, fg=None, bg=None):
|
||||
ret = ''
|
||||
codes = []
|
||||
if fg is not None: codes.append('3%d' % fg)
|
||||
if bg is not None: codes.append('10%d' % bg)
|
||||
if codes:
|
||||
ret += '\033[%sm' % ';'.join(codes)
|
||||
ret += message
|
||||
if codes:
|
||||
ret += '\033[0m'
|
||||
return ret
|
||||
|
||||
def indent_wrap(message):
|
||||
wrap_area = WIDTH - HEADER_SIZE
|
||||
messagebuf = StringIO()
|
||||
current = 0
|
||||
while current < len(message):
|
||||
next = min(current + wrap_area, len(message))
|
||||
messagebuf.write(message[current:next])
|
||||
if next < len(message):
|
||||
messagebuf.write('\n%s' % (' ' * HEADER_SIZE))
|
||||
current = next
|
||||
return messagebuf.getvalue()
|
||||
|
||||
|
||||
LAST_USED = [RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN]
|
||||
KNOWN_TAGS = {
|
||||
'dalvikvm': WHITE,
|
||||
'Process': WHITE,
|
||||
'ActivityManager': WHITE,
|
||||
'ActivityThread': WHITE,
|
||||
'AndroidRuntime': CYAN,
|
||||
'jdwp': WHITE,
|
||||
}
|
||||
|
||||
def allocate_color(tag):
|
||||
# this will allocate a unique format for the given tag
|
||||
# since we dont have very many colors, we always keep track of the LRU
|
||||
if tag not in KNOWN_TAGS:
|
||||
KNOWN_TAGS[tag] = LAST_USED[0]
|
||||
color = KNOWN_TAGS[tag]
|
||||
if color in LAST_USED:
|
||||
LAST_USED.remove(color)
|
||||
LAST_USED.append(color)
|
||||
return color
|
||||
|
||||
|
||||
RULES = {
|
||||
#re.compile(r"([\w\.@]+)=([\w\.@]+)"): r"%s\1%s=%s\2%s" % (format(fg=BLUE), format(fg=GREEN), format(fg=BLUE), format(reset=True)),
|
||||
}
|
||||
|
||||
TAGTYPES = {
|
||||
'V': colorize(' V ', fg=WHITE, bg=BLACK),
|
||||
'D': colorize(' D ', fg=BLACK, bg=BLUE),
|
||||
'I': colorize(' I ', fg=BLACK, bg=GREEN),
|
||||
'W': colorize(' W ', fg=BLACK, bg=YELLOW),
|
||||
'E': colorize(' E ', fg=BLACK, bg=RED),
|
||||
}
|
||||
|
||||
PID_START = re.compile(r'^Start proc ([a-zA-Z0-9._]+) for ([a-z]+ [^:]+): pid=(\d+) uid=(\d+) gids=(.*)\r?$')
|
||||
PID_KILL = re.compile(r'^Killing (\d+):([a-zA-Z0-9._]+)/[^:]+: (.*)\r?$')
|
||||
PID_DEATH = re.compile(r'^No longer want ([a-zA-Z0-9._]+) \(pid (\d+)\): .*\r?$')
|
||||
LOG_LINE = re.compile(r'^([A-Z])/([^\(]+)\( *(\d+)\): (.*)\r?$')
|
||||
|
||||
input = os.popen('adb logcat')
|
||||
pid = None
|
||||
|
||||
while True:
|
||||
try:
|
||||
line = input.readline()
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
|
||||
log_line = LOG_LINE.match(line)
|
||||
if not log_line is None:
|
||||
level, tag, owner, message = log_line.groups()
|
||||
|
||||
start = PID_START.match(message)
|
||||
if start is not None:
|
||||
line_package, target, line_pid, line_uid, line_gids = start.groups()
|
||||
|
||||
if line_package == package:
|
||||
pid = line_pid
|
||||
|
||||
linebuf = StringIO()
|
||||
linebuf.write('\n' * 3)
|
||||
linebuf.write(colorize(' ' * (HEADER_SIZE - 1), bg=WHITE))
|
||||
linebuf.write(' Starting for %s\n' % target)
|
||||
linebuf.write(colorize(' ' * (HEADER_SIZE - 1), bg=WHITE))
|
||||
linebuf.write(' PID: %s UID: %s GIDs: %s' % (line_pid, line_uid, line_gids))
|
||||
linebuf.write('\n')
|
||||
|
||||
print linebuf.getvalue()
|
||||
|
||||
kill = PID_KILL.match(message)
|
||||
if kill is not None:
|
||||
line_pid, line_package, reason = kill.groups()
|
||||
if 'ActivityManager' == tag and pid == line_pid and package == line_package:
|
||||
pid = None
|
||||
|
||||
linebuf = StringIO()
|
||||
linebuf.write('\n')
|
||||
linebuf.write(colorize(' ' * (HEADER_SIZE - 1), bg=RED))
|
||||
linebuf.write(' Killing because %s' % reason)
|
||||
linebuf.write('\n' * 3)
|
||||
|
||||
print linebuf.getvalue()
|
||||
|
||||
death = PID_DEATH.match(message)
|
||||
if death is not None:
|
||||
line_package, line_pid = death.groups()
|
||||
if 'ActivityManager' == tag and pid == line_pid and package == line_package:
|
||||
pid = None
|
||||
|
||||
linebuf = StringIO()
|
||||
linebuf.write('\n')
|
||||
linebuf.write(colorize(' ' * (HEADER_SIZE - 1), bg=RED))
|
||||
linebuf.write(' No longer wanted')
|
||||
linebuf.write('\n' * 3)
|
||||
|
||||
print linebuf.getvalue()
|
||||
|
||||
if pid is None or owner != pid:
|
||||
continue
|
||||
|
||||
linebuf = StringIO()
|
||||
|
||||
# right-align tag title and allocate color if needed
|
||||
tag = tag.strip()
|
||||
color = allocate_color(tag)
|
||||
tag = tag[-TAG_WIDTH:].rjust(TAG_WIDTH)
|
||||
linebuf.write(colorize(tag, fg=color))
|
||||
linebuf.write(' ')
|
||||
|
||||
# write out level colored edge
|
||||
if level not in TAGTYPES: break
|
||||
linebuf.write(TAGTYPES[level])
|
||||
linebuf.write(' ')
|
||||
|
||||
# format tag message using rules
|
||||
for matcher in RULES:
|
||||
replace = RULES[matcher]
|
||||
message = matcher.sub(replace, message)
|
||||
|
||||
linebuf.write(indent_wrap(message))
|
||||
line = linebuf.getvalue()
|
||||
|
||||
print line
|
||||
if len(line) == 0: break
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
Reference in New Issue
Block a user