| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | 2 # Use of this source code is governed by a BSD-style license that can be | 
|  | 3 # found in the LICENSE file. | 
|  | 4 | 
|  | 5 # pylint: disable=unused-argument | 
|  | 6 | 
|  | 7 import collections | 
|  | 8 import itertools | 
|  | 9 import logging | 
|  | 10 import subprocess | 
|  | 11 import tempfile | 
|  | 12 import time | 
|  | 13 import re | 
|  | 14 | 
|  | 15 from pylib.device import adb_wrapper | 
|  | 16 from pylib.device import decorators | 
|  | 17 from pylib.device import device_errors | 
|  | 18 | 
|  | 19 | 
|  | 20 class LogcatMonitor(object): | 
|  | 21 | 
|  | 22   _THREADTIME_RE_FORMAT = ( | 
|  | 23       r'(?P<date>\S*) +(?P<time>\S*) +(?P<proc_id>%s) +(?P<thread_id>%s) +' | 
|  | 24       r'(?P<log_level>%s) +(?P<component>%s) *: +(?P<message>%s)$') | 
|  | 25 | 
|  | 26   def __init__(self, adb, clear=True, filter_specs=None): | 
|  | 27     """Create a LogcatMonitor instance. | 
|  | 28 | 
|  | 29     Args: | 
|  | 30       adb: An instance of adb_wrapper.AdbWrapper. | 
|  | 31       clear: If True, clear the logcat when monitoring starts. | 
|  | 32       filter_specs: An optional list of '<tag>[:priority]' strings. | 
|  | 33     """ | 
|  | 34     if isinstance(adb, adb_wrapper.AdbWrapper): | 
|  | 35       self._adb = adb | 
|  | 36     else: | 
|  | 37       raise ValueError('Unsupported type passed for argument "device"') | 
|  | 38     self._clear = clear | 
|  | 39     self._filter_specs = filter_specs | 
|  | 40     self._logcat_out = None | 
|  | 41     self._logcat_out_file = None | 
|  | 42     self._logcat_proc = None | 
|  | 43 | 
|  | 44   @decorators.WithTimeoutAndRetriesDefaults(10, 0) | 
|  | 45   def WaitFor(self, success_regex, failure_regex=None, timeout=None, | 
|  | 46               retries=None): | 
|  | 47     """Wait for a matching logcat line or until a timeout occurs. | 
|  | 48 | 
|  | 49     This will attempt to match lines in the logcat against both |success_regex| | 
|  | 50     and |failure_regex| (if provided). Note that this calls re.search on each | 
|  | 51     logcat line, not re.match, so the provided regular expressions don't have | 
|  | 52     to match an entire line. | 
|  | 53 | 
|  | 54     Args: | 
|  | 55       success_regex: The regular expression to search for. | 
|  | 56       failure_regex: An optional regular expression that, if hit, causes this | 
|  | 57         to stop looking for a match. Can be None. | 
|  | 58       timeout: timeout in seconds | 
|  | 59       retries: number of retries | 
|  | 60 | 
|  | 61     Returns: | 
|  | 62       A match object if |success_regex| matches a part of a logcat line, or | 
|  | 63       None if |failure_regex| matches a part of a logcat line. | 
|  | 64     Raises: | 
|  | 65       CommandFailedError on logcat failure (NOT on a |failure_regex| match). | 
|  | 66       CommandTimeoutError if no logcat line matching either |success_regex| or | 
|  | 67         |failure_regex| is found in |timeout| seconds. | 
|  | 68       DeviceUnreachableError if the device becomes unreachable. | 
|  | 69     """ | 
|  | 70     if isinstance(success_regex, basestring): | 
|  | 71       success_regex = re.compile(success_regex) | 
|  | 72     if isinstance(failure_regex, basestring): | 
|  | 73       failure_regex = re.compile(failure_regex) | 
|  | 74 | 
|  | 75     logging.debug('Waiting %d seconds for "%s"', timeout, success_regex.pattern) | 
|  | 76 | 
|  | 77     # NOTE This will continue looping until: | 
|  | 78     #  - success_regex matches a line, in which case the match object is | 
|  | 79     #    returned. | 
|  | 80     #  - failure_regex matches a line, in which case None is returned | 
|  | 81     #  - the timeout is hit, in which case a CommandTimeoutError is raised. | 
|  | 82     for l in self._adb.Logcat(filter_specs=self._filter_specs): | 
|  | 83       m = success_regex.search(l) | 
|  | 84       if m: | 
|  | 85         return m | 
|  | 86       if failure_regex and failure_regex.search(l): | 
|  | 87         return None | 
|  | 88 | 
|  | 89   def FindAll(self, message_regex, proc_id=None, thread_id=None, log_level=None, | 
|  | 90               component=None): | 
|  | 91     """Finds all lines in the logcat that match the provided constraints. | 
|  | 92 | 
|  | 93     Args: | 
|  | 94       message_regex: The regular expression that the <message> section must | 
|  | 95         match. | 
|  | 96       proc_id: The process ID to match. If None, matches any process ID. | 
|  | 97       thread_id: The thread ID to match. If None, matches any thread ID. | 
|  | 98       log_level: The log level to match. If None, matches any log level. | 
|  | 99       component: The component to match. If None, matches any component. | 
|  | 100 | 
|  | 101     Yields: | 
|  | 102       A match object for each matching line in the logcat. The match object | 
|  | 103       will always contain, in addition to groups defined in |message_regex|, | 
|  | 104       the following named groups: 'date', 'time', 'proc_id', 'thread_id', | 
|  | 105       'log_level', 'component', and 'message'. | 
|  | 106     """ | 
|  | 107     if proc_id is None: | 
|  | 108       proc_id = r'\d+' | 
|  | 109     if thread_id is None: | 
|  | 110       thread_id = r'\d+' | 
|  | 111     if log_level is None: | 
|  | 112       log_level = r'[VDIWEF]' | 
|  | 113     if component is None: | 
|  | 114       component = r'[^\s:]+' | 
|  | 115     threadtime_re = re.compile( | 
|  | 116         type(self)._THREADTIME_RE_FORMAT % ( | 
|  | 117             proc_id, thread_id, log_level, component, message_regex)) | 
|  | 118 | 
|  | 119     for line in self._adb.Logcat(dump=True, logcat_format='threadtime'): | 
|  | 120       m = re.match(threadtime_re, line) | 
|  | 121       if m: | 
|  | 122         yield m | 
|  | 123 | 
|  | 124   def Start(self): | 
|  | 125     """Starts the logcat monitor. | 
|  | 126 | 
|  | 127     Clears the logcat if |clear| was set in |__init__|. | 
|  | 128     """ | 
|  | 129     if self._clear: | 
|  | 130       self._adb.Logcat(clear=True) | 
|  | 131 | 
|  | 132   def __enter__(self): | 
|  | 133     """Starts the logcat monitor.""" | 
|  | 134     self.Start() | 
|  | 135     return self | 
|  | 136 | 
|  | 137   def __exit__(self, exc_type, exc_val, exc_tb): | 
|  | 138     """Stops the logcat monitor.""" | 
|  | 139     pass | 
| OLD | NEW | 
|---|