在Python中返回一个连续的终端日志

0 人关注

我正在创建一个小应用程序,我可以插入我的安卓手机的IP地址,然后按一个按钮。我是通过ADB无线连接的。这很有效,现在我想在一个可滚动的、不可编辑的文本字段中显示 adb logcat 的日志。但是在这里我遇到了一个问题,我试图像这样捕捉logcat命令的输出 p = os.popen("adb logcat") ,然后像这样打印它 print(p.read()) 。这只会让我的应用程序(tkinter)冻结,我猜这与打印永不结束的事实有关。有没有人知道如何显示logcat的结果。

Code of function

def logcatcommand():
    p = os.popen("adb logcat")
    print(p.read())

Button:

button2 = tk.Button(text="Open logcat",width=25, height=3, command=logcatcommand)
button2.grid(row=5, column=0)

你们是否也有办法让我实时显示这些信息?我想我必须使用这样的代码。

result = scrolledtext.ScrolledText(window, wrap = tk.WORD, width = 40, height = 10, font = ("Times New Roman", 15))
result.grid(column = 1, row=0)
result.insert(tk.INSERT, output)
result.configure(state ='disabled') 

其中输出为从终端检索的实时数据。

示例行logcat。

09-10 14:10:28.479   971  3009 I WifiHAL : event received NL80211_CMD_VENDOR, vendor_id = 0x1374, subcmd = 0xd
09-10 14:10:34.779  1526  4567 I BatteryStatsService: In wakeup_callback: resumed from suspend
09-10 14:10:35.321  1526  4567 I BatteryStatsService: In wakeup_callback: suspend aborted
感谢Javier Gonzalez,我能够使用logcat打印。

def logcatcommand():
    popen = subprocess.Popen(args="adb logcat", shell=True, stdout=subprocess.PIPE)
    return iter(popen.stdout.readline, b"")
def logcatresult():
    for line in logcatcommand():
        print(line)

但是,当我试图将数值设置到一个变量中,或者只是一般地做其他事情(比如试图按下另一个按钮)时,我唯一看到的是Mac OSX的彩虹旋转轮。

3 个评论
为什么打印永远不会结束?也包括你的tkinter代码,以便我们能更好地帮助你。
ADB Logcat是一个命令,你可以从连接的安卓设备显示设备信息。这是实时的,只是报告当前的状态。只有在设备断开连接、命令停止或给定时间后才会停止。我想让它在设备连接的情况下显示设备信息。我将在帖子中添加一些logcat的样本行。
这可能有很多原因,为了更好地理解,你能不能展示一些更多的代码,包括整个函数被执行的部分?
python
android
python-3.x
tkinter
logcat
Gorter-dev
Gorter-dev
发布于 2020-09-10
1 个回答
Javier Gonzalez
Javier Gonzalez
发布于 2020-09-10
已采纳
0 人赞同

我相信在这里,这个问题已经以稍微不同的方式被问到了。 Python。如何以非阻塞的方式读取子进程的stdout

在你的代码中,我实际上会使用subprocess模块而不是os.popen。

The first time I encountered this issue, I used the select 在我上面链接的问题的答案中提到的模块。一个更现代的方法是使用asyncio来代替。这方面的问题是,你可以在SO中找到各种使用asyncio的方法。这些都是不同的,因为asyncio在不同的版本中有很大的变化。

EDIT #1

你的根本问题是你的主线程是阻塞的。现在你有一个循环,在logcatresult函数中从未结束,所以它从未返回。Tk循环从未重新获得控制权。这就是为什么它冻结了。

一般来说,人们可以做几件事。

  • do periodical non-blocking calls. In other words: your main loop needs to periodically call a non-blocking function that returns any output, if there is any.
  • move any blocking code to a separate thread.
  • Use asyncio (I will not try to give you an example of this)
  • #1: 读取日志而不阻塞的想法与#1一致,你需要实现定期调用的逻辑。

    #2: 如果把阅读循环移到一个线程中,你就可以把主线程释放出来,做其他的事情,并做出反应。然后让logcatresult线程填充你的滚动文本。在这种情况下,你甚至不需要我上面提到的东西。

    以下是一个简化版本,可能对你有用。

    from tkinter import *
    from tkinter import messagebox
    import threading
    import subprocess
    THREAD = None
    PROCESS = None
    def read_log(process):
        for line in iter(process.stdout.readline, b""):
            print(line.decode(), end=''),
    def read_log_thread():
        """ Button-Event-Handler starting the log reading. """
        global THREAD
        global PROCESS
        PROCESS = subprocess.Popen(["adb logcat"], shell=False, stdout=subprocess.PIPE)
        THREAD = threading.Thread(target=read_log, args=(PROCESS,))
        THREAD.start()
    def hello():
        messagebox.showinfo(message='Hello.')
    def main():
        root = Tk()
        Button(master=root, text='Start reading', command=read_log_thread).pack()
        buttonX = Button(master=root, text='Hello', command=hello).pack()
        root.mainloop()
        if PROCESS and PROCESS.poll():
            PROCESS.terminate()
        THREAD.join()
    if __name__ == '__main__':
        main()
    

    Things to keep in mind:

  • This implementation is just a guide. It will have issues (some mentioned below).
  •