Python实现安卓logcat日志捕获

部署运行你感兴趣的模型镜像

简介

        在做安卓自动化时,我们经常需要捕获日志,但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中,可自行查看

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值