【问题标题】:How to redirect Python's logging output to Kivy label?如何将 Python 的日志输出重定向到 Kivy 标签?
【发布时间】:2015-12-31 00:53:47
【问题描述】:

正如标题中所写,我需要以尽可能简单的方式将日志记录模块输出重定向到 Kivy 标签。我在网上搜索了一个解决方案,我认为最好的方法是以某种方式覆盖 StreamHandlerMemoryHandler (但我不知道该怎么做点)。

有人可以帮我实现吗?

我使用 python 2.7

谢谢

【问题讨论】:

    标签: python stream event-handling output kivy


    【解决方案1】:

    我总是为此类情况制作自己的 logging.Handler。

    这是一个工作示例:

    main.py:

    import kivy
    from kivy.app import App
    from kivy.clock import Clock
    from kivy.uix.label import Label
    import logging
    import thread
    import time
    
    def my_thread(log):
    
        for i in range(2**20):
            time.sleep(1)
            log.info("WOO %s", i)
    
    class MyLabelHandler(logging.Handler):
    
        def __init__(self, label, level=logging.NOTSET):
            logging.Handler.__init__(self, level=level)
            self.label = label
    
        def emit(self, record):
            "using the Clock module for thread safety with kivy's main loop"
            def f(dt=None):
                self.label.text = self.format(record) #"use += to append..."
            Clock.schedule_once(f)
    
    
    class MyApp(App):
        def build(self):
            label = Label(text="showing the log here")
    
            log = logging.getLogger("my.logger")
            log.level = logging.DEBUG
            log.addHandler(MyLabelHandler(label, logging.DEBUG))
    
            thread.start_new(my_thread, (log,))
    
            return label
    
    
    if __name__ == '__main__':
        MyApp().run()
    

    注意这里的简单线程来测试日志记录。

    【讨论】:

    • 很好的解决方案。让我问两个问题:StreamHandler 不是比基本 Handler 更好吗?你真的需要同时使用调度函数和线程实例吗?据我所知(如果我没记错的话)Kivy Clock 类是使用线程实现的。
    • @Tungsteno 我不确定它更好,只是不同。 kivy 时钟没有使用线程实现,它只是在 kivy 主 gui 线程中安排一个事件。调用除 Clock 以外的其他 kivy 方法被认为是不安全的。
    【解决方案2】:

    您可以将日志写入文件,然后在单独的线程中使用您的应用程序读取它。如果没有单独的线程,GUI 将被冻结。

    test.kv:

    #:kivy 1.9.1
    
    GridLayout:
        cols: 1
    
        LogButton:
            text: 'log me'
            on_press: self.log_me()
    
        ScrollView:
    
            GridLayout:
                cols: 1
                size_hint_y: None
                height: self.minimum_height
    
                LogLabel:
                    size_hint_y: None
                    height: self.texture_size[1]
                    text_size: self.width, None
                    halign: 'center'
    

    main.py:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    from kivy.app import App
    from kivy.uix.button import Button
    from kivy.uix.label import Label
    import logging
    import threading
    import time
    
    
    class LogButton(Button):
        def __init__(self, **kwargs):
            super(LogButton, self).__init__(**kwargs)
            self.set_logger()
    
        def set_logger(self):
            self.logger = logging.getLogger('example')
            hdlr = logging.FileHandler('example.log')
            formatter = logging.Formatter(
                '%(asctime)s %(levelname)s %(message)s'
            )
            hdlr.setFormatter(formatter)
            self.logger.addHandler(hdlr)
            self.logger.setLevel(logging.DEBUG)
    
        def log_me(self, *x):
            self.logger.debug('logger text')
    
    
    class LogLabel(Label):
        def __init__(self, **kwargs):
            super(LogLabel, self).__init__(**kwargs)
            thread = threading.Thread(target=self.read_log)
            thread.daemon = True  # kill thread on app close
            thread.start()
    
        def read_log(self):
            with open('example.log', 'r') as file:
                while 1:
                    where = file.tell()
                    line = file.readline()
                    if not line:
                        time.sleep(0.1)
                        file.seek(where)
                    else:
                        # newest logs on top
                        self.text = '%s%s' % (line, self.text)
    
    
    class Test(App):
        def build(self):
            return self.root
    
    
    Test().run()
    

    【讨论】:

    • 感谢您的回答,但我认为这个解决方案不是很优雅,而且是 IO 密集型(在 HDD 上)。
    猜你喜欢
    • 2016-10-07
    • 2010-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-14
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    相关资源
    最近更新 更多