1
0
mirror of https://github.com/ARM-software/devlib.git synced 2025-02-12 07:58:07 +00:00

Merge pull request #166 from valschneider/logcat-monitor

Logcat monitor
This commit is contained in:
setrofim 2017-09-11 18:41:02 +01:00 committed by GitHub
commit 0e9221f58e
3 changed files with 191 additions and 1 deletions

View File

@ -14,7 +14,7 @@ from devlib.module import get_module
from devlib.platform import Platform from devlib.platform import Platform
from devlib.exception import TargetError, TargetNotRespondingError, TimeoutError from devlib.exception import TargetError, TargetNotRespondingError, TimeoutError
from devlib.utils.ssh import SshConnection from devlib.utils.ssh import SshConnection
from devlib.utils.android import AdbConnection, AndroidProperties, adb_command, adb_disconnect from devlib.utils.android import AdbConnection, AndroidProperties, LogcatMonitor, adb_command, adb_disconnect
from devlib.utils.misc import memoized, isiterable, convert_new_lines, merge_lists from devlib.utils.misc import memoized, isiterable, convert_new_lines, merge_lists
from devlib.utils.misc import ABI_MAP, get_cpu_name, ranges_to_list, escape_double_quotes from devlib.utils.misc import ABI_MAP, get_cpu_name, ranges_to_list, escape_double_quotes
from devlib.utils.types import integer, boolean, bitmask, identifier, caseless_string from devlib.utils.types import integer, boolean, bitmask, identifier, caseless_string
@ -1156,6 +1156,9 @@ class AndroidTarget(Target):
def clear_logcat(self): def clear_logcat(self):
adb_command(self.adb_name, 'logcat -c', timeout=30) adb_command(self.adb_name, 'logcat -c', timeout=30)
def get_logcat_monitor(self, regexps=None):
return LogcatMonitor(self, regexps)
def adb_kill_server(self, timeout=30): def adb_kill_server(self, timeout=30):
adb_command(self.adb_name, 'kill-server', timeout) adb_command(self.adb_name, 'kill-server', timeout)

58
devlib/trace/logcat.py Normal file
View File

@ -0,0 +1,58 @@
import os
import re
import shutil
from devlib.trace import TraceCollector
from devlib.utils.android import LogcatMonitor
class LogcatCollector(TraceCollector):
def __init__(self, target, regexps=None):
super(LogcatCollector, self).__init__(target)
self.regexps = regexps
self._collecting = False
self._prev_log = None
def reset(self):
"""
Clear Collector data but do not interrupt collection
"""
if not self._monitor:
return
if self._collecting:
self._monitor.clear_log()
elif self._prev_log:
os.remove(self._prev_log)
self._prev_log = None
def start(self):
"""
Start collecting logcat lines
"""
self._monitor = LogcatMonitor(self.target, self.regexps)
if self._prev_log:
# Append new data collection to previous collection
self._monitor.start(self._prev_log)
else:
self._monitor.start()
self._collecting = True
def stop(self):
"""
Stop collecting logcat lines
"""
if not self._collecting:
raise RuntimeError('Logcat monitor not running, nothing to stop')
self._monitor.stop()
self._collecting = False
self._prev_log = self._monitor.logfile
def get_trace(self, outfile):
"""
Output collected logcat lines to designated file
"""
# copy self._monitor.logfile to outfile
shutil.copy(self._monitor.logfile, outfile)

View File

@ -24,6 +24,9 @@ import time
import subprocess import subprocess
import logging import logging
import re import re
import threading
import tempfile
import Queue
from collections import defaultdict from collections import defaultdict
from devlib.exception import TargetError, HostError, DevlibError from devlib.exception import TargetError, HostError, DevlibError
@ -508,3 +511,129 @@ def _check_env():
platform_tools = _env.platform_tools platform_tools = _env.platform_tools
adb = _env.adb adb = _env.adb
aapt = _env.aapt aapt = _env.aapt
class LogcatMonitor(threading.Thread):
FLUSH_SIZE = 1000
@property
def logfile(self):
return self._logfile
def __init__(self, target, regexps=None):
super(LogcatMonitor, self).__init__()
self.target = target
self._stopped = threading.Event()
self._match_found = threading.Event()
self._sought = None
self._found = None
self._lines = Queue.Queue()
self._datalock = threading.Lock()
self._regexps = regexps
def start(self, outfile=None):
if outfile:
self._logfile = outfile
else:
fd, self._logfile = tempfile.mkstemp()
os.close(fd)
logger.debug('Logging to {}'.format(self._logfile))
super(LogcatMonitor, self).start()
def run(self):
self.target.clear_logcat()
logcat_cmd = 'logcat'
# Join all requested regexps with an 'or'
if self._regexps:
regexp = '{}'.format('|'.join(self._regexps))
if len(self._regexps) > 1:
regexp = '({})'.format(regexp)
logcat_cmd = '{} -e {}'.format(logcat_cmd, regexp)
logger.debug('logcat command ="{}"'.format(logcat_cmd))
self._logcat = self.target.background(logcat_cmd)
while not self._stopped.is_set():
line = self._logcat.stdout.readline(1024)
self._add_line(line)
def stop(self):
# Popen can be stuck on readline() so send it a SIGKILL
self._logcat.terminate()
self._stopped.set()
self.join()
self._flush_lines()
def _add_line(self, line):
self._lines.put(line)
if self._sought and re.match(self._sought, line):
self._found = line
self._match_found.set()
if self._lines.qsize() >= self.FLUSH_SIZE:
self._flush_lines()
def _flush_lines(self):
with self._datalock:
with open(self._logfile, 'a') as fh:
while not self._lines.empty():
fh.write(self._lines.get())
def clear_log(self):
with self._datalock:
while not self._lines.empty():
self._lines.get()
with open(self._logfile, 'w') as fh:
pass
def get_log(self):
"""
Return the list of lines found by the monitor
"""
self._flush_lines()
with self._datalock:
with open(self._logfile, 'r') as fh:
res = [line for line in fh]
return res
def search(self, regexp, timeout=30):
"""
Search a line that matches a regexp in the logcat log
"""
res = []
self._flush_lines()
with self._datalock:
with open(self._logfile, 'r') as fh:
for line in fh:
if re.match(regexp, line):
res.append(line)
# Found some matches, return them
if len(res) > 0:
return res
# Did not find any match, wait for one to pop up
self._sought = regexp
found = self._match_found.wait(timeout)
self._match_found.clear()
self._sought = None
if found:
return [self._found]
else:
raise RuntimeError('Logcat monitor timeout ({}s)'.format(timeout))