blob: 4e2c4fd3a20e014a1041c1b18b571ec6cd7625e8 [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 2022 The Fuchsia Authors
#
# 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.
import logging
import re
from antlion.libs.proc.process import Process
from antlion.libs.logging import log_stream
from antlion.libs.logging.log_stream import LogStyles
TIMESTAMP_REGEX = r'((?:\d+-)?\d+-\d+ \d+:\d+:\d+.\d+)'
class TimestampTracker(object):
"""Stores the last timestamp outputted by the Logcat process."""
def __init__(self):
self._last_timestamp = None
@property
def last_timestamp(self):
return self._last_timestamp
def read_output(self, message):
"""Reads the message and parses all timestamps from it."""
all_timestamps = re.findall(TIMESTAMP_REGEX, message)
if len(all_timestamps) > 0:
self._last_timestamp = all_timestamps[0]
def _get_log_level(message):
"""Returns the log level for the given message."""
if message.startswith('-') or len(message) < 37:
return logging.ERROR
else:
log_level = message[36]
if log_level in ('V', 'D'):
return logging.DEBUG
elif log_level == 'I':
return logging.INFO
elif log_level == 'W':
return logging.WARNING
elif log_level == 'E':
return logging.ERROR
return logging.NOTSET
def _log_line_func(log, timestamp_tracker):
"""Returns a lambda that logs a message to the given logger."""
def log_line(message):
timestamp_tracker.read_output(message)
log.log(_get_log_level(message), message)
return log_line
def _on_retry(serial, extra_params, timestamp_tracker):
def on_retry(_):
begin_at = '"%s"' % (timestamp_tracker.last_timestamp or 1)
additional_params = extra_params or ''
return 'adb -s %s logcat -T %s -v year %s' % (
serial, begin_at, additional_params)
return on_retry
def create_logcat_keepalive_process(serial, logcat_dir, extra_params=''):
"""Creates a Logcat Process that automatically attempts to reconnect.
Args:
serial: The serial of the device to read the logcat of.
logcat_dir: The directory used for logcat file output.
extra_params: Any additional params to be added to the logcat cmdline.
Returns:
A acts.libs.proc.process.Process object.
"""
logger = log_stream.create_logger(
'adblog_%s' % serial, log_name=serial, subcontext=logcat_dir,
log_styles=(LogStyles.LOG_DEBUG | LogStyles.TESTCASE_LOG))
process = Process('adb -s %s logcat -T 1 -v year %s' %
(serial, extra_params))
timestamp_tracker = TimestampTracker()
process.set_on_output_callback(_log_line_func(logger, timestamp_tracker))
process.set_on_terminate_callback(
_on_retry(serial, extra_params, timestamp_tracker))
return process