class LogcatColor(object): def __init__(self, args=None): self.parse_args(args) self.width = self.get_term_width() self.config = LogcatColorConfig(self.options) self.profile = None if len(self.args) >= 1: self.profile = Profile.get_profile(self.args[0]) if self.profile: self.args = self.args[1:] if not self.profile: self.logcat_args.extend(self.args) self.format = None if self.options.format: self.format = self.options.format elif self.profile and self.profile.format: self.format = self.profile.format self.layout = self.format if self.options.plain: self.layout = "raw" def get_term_width(self): out_fd = self.output.fileno() if os.isatty(out_fd): # unpack the current terminal width / height data = fcntl.ioctl(out_fd, termios.TIOCGWINSZ, '1234') height, width = struct.unpack('hh', data) else: # store a large width when the output of this script is being piped width = 2000 return width def parse_args(self, args=None): parser = optparse.OptionParser() # logcat-color options parser.add_option("--config", dest="config", default=None, help="path to logcat-color config file (default: ~/.logcat-config)") parser.add_option("--plain", action="store_true", dest="plain", default=False, help="apply profiles and filters, but don't colorize / format" + " output (useful for logging to a file)") parser.add_option("--no-wrap", action="store_false", dest="wrap", default=None, help="don't wrap console text into a column " + "(makes for better copy/paste)") parser.add_option("--stay-connected", action="store_true", default=None, dest="stay_connected", help="keep logcat-color running when the " "device disconnects, and automatically " "wait for the device to reconnect") parser.add_option("-i", "--input", metavar="FILE", dest="input", default=None, help="read input from FILE, instead of starting adb. this is " + "equivalent to piping FILE to logcat-color. (default: start " + "adb, and read from it's stdout)") parser.add_option("-o", "--output", metavar="FILE", dest="output", default=None, help="write output to FILE (default: stdout)") # ADB options parser.add_option("-d", "--device", action="store_const", dest="adb_device", const="device", help="connect to the only plugged-in device") parser.add_option("-e", "--emulator", action="store_const", dest="adb_device", const="emulator", help="connect to the only running emulator") parser.add_option("-s", "--serial-number", dest="adb_device", help="connect to a specific device by it's serial number") # Logcat options # See http://developer.android.com/guide/developing/tools/logcat.html # We can't support -d / -s since we use them for ADB above, but we # provide long-form options in case they are needed parser.add_option("-b", "--buffer", action="append", dest="buffers", help="loads an alternate log buffer for viewing, such as event or" + " radio") parser.add_option("-c", "--clear", action="append_const", dest="logcat_args", const="-c", help="clears (flushes) the entire log and exits") parser.add_option("--dump", action="append_const", dest="logcat_args", const="-d", help="dumps the log to the screen and exits") parser.add_option("-f", "--file", dest="file", default=None, help="writes log message output to <file>. the default is stdout") parser.add_option("-g", "--print-size", action="append_const", dest="logcat_args", const="-g", help="prints the size of the specified log buffer and exits") parser.add_option("-n", "--max-rotated-logs", dest="max_rotated_logs", type="int", help="sets the maximum number of rotated logs. requires the -r" + " option (default: 4)") parser.add_option("-r", "--rotate", dest="rotate_kbytes", type="int", help="rotates the log file every <rotate_kbytes> of output." + " requires the -f option (default: 16)") parser.add_option("--silent", action="append_const", dest="logcat_args", const="-s", help="sets the default filter spec to silent") parser.add_option("-v", "--format", dest="format", default=None, help="sets the output format for log messages. possible formats:" + " brief, process, tag, raw, time, threadtime, long" + " (default: brief)") (options, args) = parser.parse_args(args) self.options = options self.args = args if options.config and not os.path.isfile(options.config): parser.error("Config file does not exist: %s" % options.config) try: self.input = sys.stdin.buffer except AttributeError: self.input = sys.stdin if options.input: self.input = open(options.input, "rb") try: self.output = sys.stdout.buffer except AttributeError: self.output = sys.stdout if options.output: self.output = open(options.output, "wb") self.adb_device = options.adb_device self.logcat_args = options.logcat_args or [] if options.buffers: for buf in options.buffers: self.logcat_args.extend(["-b", buf]) if options.file: self.logcat_args.extend(["-f", options.file]) if options.max_rotated_logs: self.logcat_args.extend(["-n", options.max_rotated_logs]) if options.rotate_kbytes: self.logcat_args.extend(["-r", options.rotate_kbytes]) def get_adb_args(self): adb = "adb" # Let the system find adb on the PATH if "ADB" in os.environ: adb = os.environ["ADB"] config_adb = self.config.get_adb() if config_adb: adb = config_adb adb_args = [adb] if not self.adb_device and self.profile: emulator = self.profile.emulator if emulator: self.adb_device = \ emulator if type(emulator) is str else "emulator" device = self.profile.device if device: self.adb_device = device if type(device) is str else "device" if self.adb_device == "emulator": adb_args.append("-e") elif self.adb_device == "device": adb_args.append("-d") elif self.adb_device: adb_args.extend(["-s", self.adb_device]) return adb_args def get_logcat_args(self): logcat_args = self.logcat_args[:] if self.format: # put format in front in case custom filters are used logcat_args[0:0] = ["-v", self.format] if self.profile: buffers = self.profile.buffers if buffers: for b in buffers: logcat_args.extend(["-b", b]) return logcat_args def start_logcat(self): adb_command = self.get_adb_args() adb_command.append("logcat") adb_command.extend(self.get_logcat_args()) try: self.input = Popen(adb_command, stdout=PIPE).stdout except OSError as e: if e.errno == errno.ENOENT: print( 'Error, adb could not be found using: "%s"\n' \ 'To fix this: \n' \ ' 1) Add the directory containing adb to your PATH\n' \ ' 2) Set the ADB environment variable\n' \ ' 3) Set "adb" in ~/.logcat-color' % adb_command[0], file=sys.stderr) else: print('Could not run ADB: %s' % str(e), file=sys.stderr) sys.exit(e.errno) def init_reader(self): LogcatReader(self.input, self.config, profile=self.profile, format=self.format, layout=self.layout, writer=self.output, width=self.width) def start(self): # if someone is piping, use stdin as input. if not, invoke adb logcat if self.input.isatty(): self.start_logcat() self.init_reader() def loop(self): try: self.start() while True: asyncore.loop() if not self.config.get_stay_connected(): break self.wait_for_device() self.start_logcat() self.init_reader() except KeyboardInterrupt: pass WAIT_FOR_DEVICE = Fore.WHITE + Back.BLACK + Style.DIM + \ "--- Waiting for device" + Style.RESET_ALL + \ Fore.BLUE + Back.BLACK + Style.DIM + " %s" + Style.RESET_ALL + \ Fore.WHITE + Back.BLACK + Style.DIM + "---" + Style.RESET_ALL def wait_for_device(self): command = self.get_adb_args() command.append("wait-for-device") device_str = "" if self.adb_device: device_str = "\"%s\" " % self.adb_device print(self.WAIT_FOR_DEVICE % device_str) check_call(command)