blob: 8a3d00b46771d95a20d4cc4962bff013230a3dc9 [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 2019, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Helper util libraries for parsing logcat logs."""
import asyncio
import re
from datetime import datetime
from typing import Optional, Pattern
# local import
import lib.print_utils as print_utils
def parse_logcat_datetime(timestamp: str) -> Optional[datetime]:
"""Parses the timestamp of logcat.
Params:
timestamp: for example "2019-07-01 16:13:55.221".
Returns:
a datetime of timestamp with the year now.
"""
try:
# Match the format of logcat. For example: "2019-07-01 16:13:55.221",
# because it doesn't have year, set current year to it.
timestamp = datetime.strptime(timestamp,
'%Y-%m-%d %H:%M:%S.%f')
return timestamp
except ValueError as ve:
print_utils.debug_print('Invalid line: ' + timestamp)
return None
def _is_time_out(timeout: datetime, line: str) -> bool:
"""Checks if the timestamp of this line exceeds the timeout.
Returns:
true if the timestamp exceeds the timeout.
"""
# Get the timestampe string.
cur_timestamp_str = ' '.join(re.split(r'\s+', line)[0:2])
timestamp = parse_logcat_datetime(cur_timestamp_str)
if not timestamp:
return False
return timestamp > timeout
async def _blocking_wait_for_logcat_pattern(timestamp: datetime,
pattern: Pattern,
timeout: datetime) -> Optional[str]:
# Show the year in the timestampe.
logcat_cmd = 'adb logcat -v UTC -v year -v threadtime -T'.split()
logcat_cmd.append(str(timestamp))
print_utils.debug_print('[LOGCAT]:' + ' '.join(logcat_cmd))
# Create subprocess
process = await asyncio.create_subprocess_exec(
*logcat_cmd,
# stdout must a pipe to be accessible as process.stdout
stdout=asyncio.subprocess.PIPE)
while (True):
# Read one line of output.
data = await process.stdout.readline()
line = data.decode('utf-8').rstrip()
# 2019-07-01 14:54:21.946 27365 27392 I ActivityTaskManager: Displayed
# com.android.settings/.Settings: +927ms
# TODO: Detect timeouts even when there is no logcat output.
if _is_time_out(timeout, line):
print_utils.debug_print('DID TIMEOUT BEFORE SEEING ANYTHING ('
'timeout={timeout} seconds << {pattern} '
'>>'.format(timeout=timeout, pattern=pattern))
return None
if pattern.match(line):
print_utils.debug_print(
'WE DID SEE PATTERN << "{}" >>.'.format(pattern))
return line
def blocking_wait_for_logcat_pattern(timestamp: datetime,
pattern: Pattern,
timeout: datetime) -> Optional[str]:
"""Selects the line that matches the pattern and within the timeout.
Returns:
the line that matches the pattern and within the timeout.
"""
loop = asyncio.get_event_loop()
result = loop.run_until_complete(
_blocking_wait_for_logcat_pattern(timestamp, pattern, timeout))
return result