diff --git a/sky/packages/sky/lib/sky_tool b/sky/packages/sky/lib/sky_tool index 1e78345fe..51101165e 100755 --- a/sky/packages/sky/lib/sky_tool +++ b/sky/packages/sky/lib/sky_tool @@ -9,6 +9,7 @@ import errno import hashlib import json import logging +import multiprocessing import os import platform import random @@ -146,6 +147,46 @@ def _url_for_path(port, root, path): return 'http://localhost:%s/%s' % (port, relative_path) +class SkyLogs(object): + def add_subparser(self, subparsers): + logs_parser = subparsers.add_parser('logs', + help='Show logs for running Sky apps') + logs_parser.set_defaults(func=self.run) + + def run(self, args, pids): + android_log_reader = None + ios_dev_log_reader = None + ios_sim_log_reader = None + + android = AndroidDevice() + if android.is_connected(): + android_log_reader = android.logs() + + if IOSDevice.is_connected(): + ios_dev_log_reader = IOSDevice.logs() + + if IOSSimulator.is_connected(): + ios_sim_log_reader = IOSSimulator.logs() + + if android_log_reader is not None: + try: + android_log_reader.join() + except KeyboardInterrupt: + pass + + if ios_dev_log_reader is not None: + try: + ios_dev_log_reader.join() + except KeyboardInterrupt: + pass + + if ios_sim_log_reader is not None: + try: + ios_sim_log_reader.join() + except KeyboardInterrupt: + pass + + class InstallSky(object): def add_subparser(self, subparsers): install_parser = subparsers.add_parser('install', @@ -447,6 +488,27 @@ class AndroidDevice(object): logging.info(' '.join(cmd)) subprocess.check_output(cmd) + def logs(self): + def do_logs(): + cmd = [ + self.adb_path, + 'logcat', + '-s', + 'sky', + 'chromium', + ] + logging.info(' '.join(cmd)) + log_process = subprocess.Popen(cmd, bufsize=1, stdout=subprocess.PIPE) + while True: + try: + sys.stdout.write('ANDROID: ' + log_process.stdout.readline()) + sys.stdout.flush() + except KeyboardInterrupt: + break + log_reader = multiprocessing.Process(target=do_logs) + log_reader.daemon = True + log_reader.start() + return log_reader class IOSDevice(object): @@ -540,6 +602,27 @@ class IOSDevice(object): except subprocess.CalledProcessError: pass + @classmethod + def logs(cls): + def do_logs(): + cmd = [ + 'idevicesyslog', + ] + logging.info(' '.join(cmd)) + log_process = subprocess.Popen(cmd, stdout=subprocess.PIPE) + while True: + try: + log_line = log_process.stdout.readline() + if re.match(r'.*SkyShell.*', log_line) is not None: + sys.stdout.write('IOS DEV: ' + log_line) + sys.stdout.flush() + except KeyboardInterrupt: + break + log_reader = multiprocessing.Process(target=do_logs) + log_reader.daemon = True + log_reader.start() + return log_reader + class IOSSimulator(object): @classmethod @@ -548,6 +631,10 @@ class IOSSimulator(object): return False return cls.get_simulator_device_id() is not None + @classmethod + def is_connected(cls): + return cls.is_booted() + _device_id = None @classmethod def get_simulator_device_id(cls): @@ -635,6 +722,29 @@ class IOSSimulator(object): def needs_install(cls, args): return cls.is_booted() + @classmethod + def logs(cls): + def do_logs(): + cmd = [ + 'tail', + '-f', + os.path.expanduser('~/Library/Logs/CoreSimulator/' + cls.get_simulator_device_id() + '/system.log'), + ] + logging.info(' '.join(cmd)) + log_process = subprocess.Popen(cmd, stdout=subprocess.PIPE) + while True: + try: + log_line = log_process.stdout.readline() + if re.match(r'.*SkyShell.*', log_line) is not None: + sys.stdout.write('IOS SIM: ' + log_line) + sys.stdout.flush() + except KeyboardInterrupt: + break + log_reader = multiprocessing.Process(target=do_logs) + log_reader.daemon = True + log_reader.start() + return log_reader + @classmethod def fork_install_app(cls, ios_app_path): cmd = [ @@ -1045,7 +1155,7 @@ class SkyShellRunner(object): subparsers = parser.add_subparsers(help='sub-command help') - for command in [InstallSky(), StartSky(), StopSky(), StartListening(), StartTracing(), StopTracing(), IOSSimulator()]: + for command in [SkyLogs(), InstallSky(), StartSky(), StopSky(), StartListening(), StartTracing(), StopTracing(), IOSSimulator()]: command.add_subparser(subparsers) args = parser.parse_args()