【问题标题】:Python: combine logging and wx so that logging stream is redirectet to stdout/stderr framePython:将日志记录和 wx 结合起来,以便将日志记录流重定向到 stdout/stderr 帧
【发布时间】:2010-04-22 09:02:49
【问题描述】:

事情是这样的:

我正在尝试将日志记录模块与 wx.App() 的重定向功能相结合。我的意图是将文件 AND 记录到 stderr。但我希望 stderr/stdout 重定向到一个单独的框架,这是 wx.App 的功能。

我的测试代码:

import logging
import wx

class MyFrame(wx.Frame):
    def __init__(self):
        self.logger = logging.getLogger("main.MyFrame")
        wx.Frame.__init__(self, parent = None, id = wx.ID_ANY, title = "MyFrame")
        self.logger.debug("MyFrame.__init__() called.")

    def OnExit(self):
        self.logger.debug("MyFrame.OnExit() called.")

class MyApp(wx.App):
    def __init__(self, redirect):
        self.logger = logging.getLogger("main.MyApp")
        wx.App.__init__(self, redirect = redirect)
        self.logger.debug("MyApp.__init__() called.")

    def OnInit(self):
        self.frame = MyFrame()
        self.frame.Show()
        self.SetTopWindow(self.frame)
        self.logger.debug("MyApp.OnInit() called.")
        return True

    def OnExit(self):
        self.logger.debug("MyApp.OnExit() called.")

def main():
    logger_formatter = logging.Formatter("%(name)s\t%(levelname)s\t%(message)s")
    logger_stream_handler = logging.StreamHandler()
    logger_stream_handler.setLevel(logging.INFO)
    logger_stream_handler.setFormatter(logger_formatter)
    logger_file_handler = logging.FileHandler("test.log", mode = "w")
    logger_file_handler.setLevel(logging.DEBUG)
    logger_file_handler.setFormatter(logger_formatter)
    logger = logging.getLogger("main")
    logger.setLevel(logging.DEBUG)
    logger.addHandler(logger_stream_handler)
    logger.addHandler(logger_file_handler)
    logger.info("Logger configured.")

    app = MyApp(redirect = True)
    logger.debug("Created instance of MyApp. Calling MainLoop().")
    app.MainLoop()
    logger.debug("MainLoop() ended.")
    logger.info("Exiting program.")

    return 0

if (__name__ == "__main__"):
    main()

预期的行为是:
- 创建一个名为 test.log
的文件 - 该文件包含级别为 DEBUG 和 INFO/ERROR/WARNING/CRITICAL
的日志消息 - 来自 INFO 和 ERROR/WARNING/CRITICAL 类型的消息要么显示在控制台上,要么显示在单独的框架中,具体取决于它们的创建位置
- 不在 MyApp 或 MyFrame 中的记录器消息显示在控制台
- 来自 MyApp 或 MyFrame 内部的记录器消息显示在单独的框架中

实际行为是:
- 文件已创建并包含:

main    INFO    Logger configured.
main.MyFrame    DEBUG   MyFrame.__init__() called.
main.MyFrame    INFO    MyFrame.__init__() called.
main.MyApp  DEBUG   MyApp.OnInit() called.
main.MyApp  INFO    MyApp.OnInit() called.
main.MyApp  DEBUG   MyApp.__init__() called.
main    DEBUG   Created instance of MyApp. Calling MainLoop().
main.MyApp  DEBUG   MyApp.OnExit() called.
main    DEBUG   MainLoop() ended.
main    INFO    Exiting program.

- 控制台输出为:

main    INFO    Logger configured.
main.MyFrame    INFO    MyFrame.__init__() called.
main.MyApp      INFO    MyApp.OnInit() called.
main    INFO    Exiting program.

- 没有打开单独的框架,虽然行

main.MyFrame    INFO    MyFrame.__init__() called.
main.MyApp      INFO    MyApp.OnInit() called.

应该显示在框架内而不是控制台上。

在我看来,一旦记录器实例使用 stderr 作为输出,wx.App 就无法将 stderr 重定向到帧。 wxPythons Docs 声明了想要的行为,see here.

有什么想法吗?

Uwe

【问题讨论】:

    标签: python logging wxpython


    【解决方案1】:

    当 wx.App 说它将 stdout/stderr 重定向到弹出窗口时,它的真正含义是它将重定向 sys.stdout 和 sys.stderr,所以如果你直接写入 sys.stdout 或 sys.stderr 它将被重定向到一个弹出窗口,例如试试这个

    print "this will go to wx msg frame"
    sys.stdout.write("yes it goes")
    sys.stderr.write("... and this one too")
    

    这里的问题是,如果 wxApp 在创建 streamhandler 之后创建,streamhandler 指向旧的(原始) sys.stderr 和 sys.stdout 而不是 wxApp 设置的新的,所以更简单的解决方案是创建 wx.App在创建串处理程序之前,例如在记录初始化代码之前在代码中移动app = MyApp(redirect = True)

    或者创建一个自定义日志处理程序并将数据写入 sys.stdout 和 sys.stderr,或者更好地创建您自己的窗口并在那里添加数据。例如试试这个

    class LogginRedirectHandler(logging.Handler):
            def __init__(self,):
                # run the regular Handler __init__
                logging.Handler.__init__(self)
    
            def emit(self, record):
                sys.stdout.write(record.message)
    
    loggingRedirectHandler = LogginRedirectHandler()
    logger_file_handler.setLevel(logging.DEBUG)
    logger.addHandler(loggingRedirectHandler)
    

    【讨论】:

    • >logging 不会写入 sys.stdout 或 sys.stderr 这不是真的(如果文档是正确的 (docs.python.org/library/logging.html#module-logging.handlers))。如文档所述,如果在没有参数的情况下创建了 logging.handlers.StreamHandler 的实例,则使用 sys.stderr。
    • @Uwe,我已经更新了答案,您需要在创建 Streamhandler 之前移动 wx.App 创建
    • 不幸的是,这将不起作用,因为在 MyApp 或 MyFrame 中创建的所有记录器实例都不会连接到实际的记录器“main”。 “main”的流被重定向到 wx 的重定向框架,但“main.MyApp”和“main.MyFrame”记录器不是“main”的子级,因为“main”在创建“main.MyApp”时不存在,并且“main.MyFrame”。而且由于他们没有设置格式化程序和处理程序,因此不知道将调试消息从 MyApp 和 MyFrame 中放在哪里。
    • 您必须编写自定义处理程序的唯一选项
    • 我决定使用 Gabriel Genellina 的 LoggingWebMonitor (code.activestate.com/recipes/…) 作为解决方案。
    【解决方案2】:

    我认为更优雅的方法是创建一个自定义日志记录处理程序子类,将其消息发布到特定的日志记录框架。

    这使得在运行时打开/关闭 GUI 日志记录变得更加容易。

    【讨论】:

      猜你喜欢
      • 2018-04-03
      • 2022-10-15
      • 1970-01-01
      • 1970-01-01
      • 2022-07-06
      • 2021-05-05
      • 1970-01-01
      • 1970-01-01
      • 2012-10-22
      相关资源
      最近更新 更多