简介
在做安卓自动化时,我们经常需要捕获日志,但logcat一般是阻塞式的。为了不影响主进程,一般我们可以通过子进程或线程的方式去捕获。
logcat类示例
通常来讲,捕获设备的日志,肯定存在设备控制类,假设控制安卓的设备类为Phone:
class Phone:
def __init__(sn: str):
self.sn = sn
个人认为,需要把日志捕获单独封装一个类,赋给Phone使用:
class _Logcat:
"""日志管理类"""
def __init__(self, d: Phone, log_path: str|Path):
"""
:param d: 安卓对象
:param log_path: file路径
"""
self.d = d
self.sn = d.sn
self.log_path = log_path
self._log_proc = None
self._log_file = None
# 注册退出清理
atexit.register(self.safe_shutdown)
signal.signal(signal.SIGINT, self._signal_handler)
signal.signal(signal.SIGTERM, self._signal_handler)
def _signal_handler(self, signum, frame):
"""处理中断信号"""
self.safe_shutdown()
raise SystemExit("进程被终止")
def start_capture(self, filter_cmd: str = ''):
"""启动日志捕获"""
# 关闭已有进程
self.safe_shutdown()
# 准备文件
self.log_path.parent.mkdir(exist_ok=True, parents=True)
if self.log_path.exists():
self.log_path.unlink()
# 启动进程
self._log_file = open(self.log_path, 'w', encoding='utf-8')
adb_cmd = f"adb -s {self.sn} shell logcat" if self.sn else "adb logcat"
full_cmd = f"{adb_cmd} | {filter_cmd}" if filter_cmd else adb_cmd
self.d.exec_shell("logcat -c")
self.log.debug(f"开始捕获日志: {full_cmd}")
self._log_proc = subprocess.Popen(
full_cmd.split(),
stdout=self._log_file,
stderr=subprocess.DEVNULL
)
def safe_shutdown(self):
"""安全关闭(幂等方法,无论执行多少次,与单次执行效果相同)"""
# 终止进程
self.log.debug("停止日志捕获")
if self._log_proc:
self.log.debug(f"终止日志捕获进程")
try:
self._log_proc.terminate()
self._log_proc.wait(timeout=3)
except (subprocess.TimeoutExpired, AttributeError):
if self._log_proc:
self._log_proc.kill()
finally:
self._log_proc = None
# 关闭文件
if self._log_file:
self.log.debug(f"关闭日志文件")
self._log_file.close()
self._log_file = None
def __del__(self):
"""析构函数兜底(析构函数做“清理善后” 的工作,结束时自动调用)"""
self.safe_shutdown()
需要注意的是,这个logcat类中,使用了signal和atexit以及析构函数,确保在程序自动结束和被终止时,也会执行关闭操作,避免程序不断地创建子进程,导致一些性能问题。
使用示例:
Class Phone:
def __init__(sn: str):
self.sn = sn
self.logfile = 'logcat.txt'
self._logcat = _Logcat(self, self.logfile)
def capture_log(self, flt):
self._logcat.start_capture(flt)
if __name__ == "__main__":
d = Phone()
d.capture_log('grep "the first flag"')
# 日志记录在logcat.txt中,可自行查看
627

被折叠的 条评论
为什么被折叠?



