media/webrtc/trunk/build/android/adb_logcat_printer.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rwxr-xr-x

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 #!/usr/bin/env python
michael@0 2 #
michael@0 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 4 # Use of this source code is governed by a BSD-style license that can be
michael@0 5 # found in the LICENSE file.
michael@0 6
michael@0 7 """Shutdown adb_logcat_monitor and print accumulated logs.
michael@0 8
michael@0 9 To test, call './adb_logcat_printer.py <base_dir>' where
michael@0 10 <base_dir> contains 'adb logcat -v threadtime' files named as
michael@0 11 logcat_<deviceID>_<sequenceNum>
michael@0 12
michael@0 13 The script will print the files to out, and will combine multiple
michael@0 14 logcats from a single device if there is overlap.
michael@0 15
michael@0 16 Additionally, if a <base_dir>/LOGCAT_MONITOR_PID exists, the script
michael@0 17 will attempt to terminate the contained PID by sending a SIGINT and
michael@0 18 monitoring for the deletion of the aforementioned file.
michael@0 19 """
michael@0 20
michael@0 21 import cStringIO
michael@0 22 import logging
michael@0 23 import os
michael@0 24 import re
michael@0 25 import signal
michael@0 26 import sys
michael@0 27 import time
michael@0 28
michael@0 29
michael@0 30 # Set this to debug for more verbose output
michael@0 31 LOG_LEVEL = logging.INFO
michael@0 32
michael@0 33
michael@0 34 def CombineLogFiles(list_of_lists, logger):
michael@0 35 """Splices together multiple logcats from the same device.
michael@0 36
michael@0 37 Args:
michael@0 38 list_of_lists: list of pairs (filename, list of timestamped lines)
michael@0 39 logger: handler to log events
michael@0 40
michael@0 41 Returns:
michael@0 42 list of lines with duplicates removed
michael@0 43 """
michael@0 44 cur_device_log = ['']
michael@0 45 for cur_file, cur_file_lines in list_of_lists:
michael@0 46 # Ignore files with just the logcat header
michael@0 47 if len(cur_file_lines) < 2:
michael@0 48 continue
michael@0 49 common_index = 0
michael@0 50 # Skip this step if list just has empty string
michael@0 51 if len(cur_device_log) > 1:
michael@0 52 try:
michael@0 53 line = cur_device_log[-1]
michael@0 54 # Used to make sure we only splice on a timestamped line
michael@0 55 if re.match('^\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} ', line):
michael@0 56 common_index = cur_file_lines.index(line)
michael@0 57 else:
michael@0 58 logger.warning('splice error - no timestamp in "%s"?', line.strip())
michael@0 59 except ValueError:
michael@0 60 # The last line was valid but wasn't found in the next file
michael@0 61 cur_device_log += ['***** POSSIBLE INCOMPLETE LOGCAT *****']
michael@0 62 logger.info('Unable to splice %s. Incomplete logcat?', cur_file)
michael@0 63
michael@0 64 cur_device_log += ['*'*30 + ' %s' % cur_file]
michael@0 65 cur_device_log.extend(cur_file_lines[common_index:])
michael@0 66
michael@0 67 return cur_device_log
michael@0 68
michael@0 69
michael@0 70 def FindLogFiles(base_dir):
michael@0 71 """Search a directory for logcat files.
michael@0 72
michael@0 73 Args:
michael@0 74 base_dir: directory to search
michael@0 75
michael@0 76 Returns:
michael@0 77 Mapping of device_id to a sorted list of file paths for a given device
michael@0 78 """
michael@0 79 logcat_filter = re.compile('^logcat_(\w+)_(\d+)$')
michael@0 80 # list of tuples (<device_id>, <seq num>, <full file path>)
michael@0 81 filtered_list = []
michael@0 82 for cur_file in os.listdir(base_dir):
michael@0 83 matcher = logcat_filter.match(cur_file)
michael@0 84 if matcher:
michael@0 85 filtered_list += [(matcher.group(1), int(matcher.group(2)),
michael@0 86 os.path.join(base_dir, cur_file))]
michael@0 87 filtered_list.sort()
michael@0 88 file_map = {}
michael@0 89 for device_id, _, cur_file in filtered_list:
michael@0 90 if not device_id in file_map:
michael@0 91 file_map[device_id] = []
michael@0 92
michael@0 93 file_map[device_id] += [cur_file]
michael@0 94 return file_map
michael@0 95
michael@0 96
michael@0 97 def GetDeviceLogs(log_filenames, logger):
michael@0 98 """Read log files, combine and format.
michael@0 99
michael@0 100 Args:
michael@0 101 log_filenames: mapping of device_id to sorted list of file paths
michael@0 102 logger: logger handle for logging events
michael@0 103
michael@0 104 Returns:
michael@0 105 list of formatted device logs, one for each device.
michael@0 106 """
michael@0 107 device_logs = []
michael@0 108
michael@0 109 for device, device_files in log_filenames.iteritems():
michael@0 110 logger.debug('%s: %s', device, str(device_files))
michael@0 111 device_file_lines = []
michael@0 112 for cur_file in device_files:
michael@0 113 with open(cur_file) as f:
michael@0 114 device_file_lines += [(cur_file, f.read().splitlines())]
michael@0 115 combined_lines = CombineLogFiles(device_file_lines, logger)
michael@0 116 # Prepend each line with a short unique ID so it's easy to see
michael@0 117 # when the device changes. We don't use the start of the device
michael@0 118 # ID because it can be the same among devices. Example lines:
michael@0 119 # AB324: foo
michael@0 120 # AB324: blah
michael@0 121 device_logs += [('\n' + device[-5:] + ': ').join(combined_lines)]
michael@0 122 return device_logs
michael@0 123
michael@0 124
michael@0 125 def ShutdownLogcatMonitor(base_dir, logger):
michael@0 126 """Attempts to shutdown adb_logcat_monitor and blocks while waiting."""
michael@0 127 try:
michael@0 128 monitor_pid_path = os.path.join(base_dir, 'LOGCAT_MONITOR_PID')
michael@0 129 with open(monitor_pid_path) as f:
michael@0 130 monitor_pid = int(f.readline())
michael@0 131
michael@0 132 logger.info('Sending SIGTERM to %d', monitor_pid)
michael@0 133 os.kill(monitor_pid, signal.SIGTERM)
michael@0 134 i = 0
michael@0 135 while True:
michael@0 136 time.sleep(.2)
michael@0 137 if not os.path.exists(monitor_pid_path):
michael@0 138 return
michael@0 139 if not os.path.exists('/proc/%d' % monitor_pid):
michael@0 140 logger.warning('Monitor (pid %d) terminated uncleanly?', monitor_pid)
michael@0 141 return
michael@0 142 logger.info('Waiting for logcat process to terminate.')
michael@0 143 i += 1
michael@0 144 if i >= 10:
michael@0 145 logger.warning('Monitor pid did not terminate. Continuing anyway.')
michael@0 146 return
michael@0 147
michael@0 148 except (ValueError, IOError, OSError):
michael@0 149 logger.exception('Error signaling logcat monitor - continuing')
michael@0 150
michael@0 151
michael@0 152 def main(base_dir, output_file):
michael@0 153 log_stringio = cStringIO.StringIO()
michael@0 154 logger = logging.getLogger('LogcatPrinter')
michael@0 155 logger.setLevel(LOG_LEVEL)
michael@0 156 sh = logging.StreamHandler(log_stringio)
michael@0 157 sh.setFormatter(logging.Formatter('%(asctime)-2s %(levelname)-8s'
michael@0 158 ' %(message)s'))
michael@0 159 logger.addHandler(sh)
michael@0 160
michael@0 161 try:
michael@0 162 # Wait at least 5 seconds after base_dir is created before printing.
michael@0 163 #
michael@0 164 # The idea is that 'adb logcat > file' output consists of 2 phases:
michael@0 165 # 1 Dump all the saved logs to the file
michael@0 166 # 2 Stream log messages as they are generated
michael@0 167 #
michael@0 168 # We want to give enough time for phase 1 to complete. There's no
michael@0 169 # good method to tell how long to wait, but it usually only takes a
michael@0 170 # second. On most bots, this code path won't occur at all, since
michael@0 171 # adb_logcat_monitor.py command will have spawned more than 5 seconds
michael@0 172 # prior to called this shell script.
michael@0 173 try:
michael@0 174 sleep_time = 5 - (time.time() - os.path.getctime(base_dir))
michael@0 175 except OSError:
michael@0 176 sleep_time = 5
michael@0 177 if sleep_time > 0:
michael@0 178 logger.warning('Monitor just started? Sleeping %.1fs', sleep_time)
michael@0 179 time.sleep(sleep_time)
michael@0 180
michael@0 181 assert os.path.exists(base_dir), '%s does not exist' % base_dir
michael@0 182 ShutdownLogcatMonitor(base_dir, logger)
michael@0 183 separator = '\n' + '*' * 80 + '\n\n'
michael@0 184 for log in GetDeviceLogs(FindLogFiles(base_dir), logger):
michael@0 185 output_file.write(log)
michael@0 186 output_file.write(separator)
michael@0 187 with open(os.path.join(base_dir, 'eventlog')) as f:
michael@0 188 output_file.write('\nLogcat Monitor Event Log\n')
michael@0 189 output_file.write(f.read())
michael@0 190 except:
michael@0 191 logger.exception('Unexpected exception')
michael@0 192
michael@0 193 logger.info('Done.')
michael@0 194 sh.flush()
michael@0 195 output_file.write('\nLogcat Printer Event Log\n')
michael@0 196 output_file.write(log_stringio.getvalue())
michael@0 197
michael@0 198 if __name__ == '__main__':
michael@0 199 if len(sys.argv) == 1:
michael@0 200 print 'Usage: %s <base_dir>' % sys.argv[0]
michael@0 201 sys.exit(1)
michael@0 202 sys.exit(main(sys.argv[1], sys.stdout))

mercurial