Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:将日志记录和wx结合起来,以便将日志记录流重定向到stdout/stderr框架_Python_Logging_Wxpython - Fatal编程技术网

Python:将日志记录和wx结合起来,以便将日志记录流重定向到stdout/stderr框架

Python:将日志记录和wx结合起来,以便将日志记录流重定向到stdout/stderr框架,python,logging,wxpython,Python,Logging,Wxpython,事情是这样的: 我正在尝试将日志模块与wx.App()的重定向功能结合起来。我的目的是登录到一个文件和到stderr。但是我想把stderr/stdout重定向到一个单独的帧,就像wx.App的特性一样 我的测试代码: import logging import wx class MyFrame(wx.Frame): def __init__(self): self.logger = logging.getLogger("main.MyFrame") w

事情是这样的:

我正在尝试将日志模块与wx.App()的重定向功能结合起来。我的目的是登录到一个文件到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的日志消息
-来自type 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文档声称有通缉行为

有什么想法吗


Uwe

当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设置的新的sys.stdout,因此更简单的解决方案是在创建streap处理程序之前创建wx.App,例如在代码移动
App=MyApp(重定向=True)中
在记录初始化代码之前

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

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)

我这样做的方式(我认为更优雅)是创建一个自定义日志处理程序子类,将其消息发布到特定的日志框架


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

>日志记录不会写入sys.stdout或sys.stderr这不是很正确(如果文档正确()。如文档所述,如果在没有参数的情况下创建logging.handlers.StreamHandler的实例,则使用sys.stderr。@Uwe,我已更新了答案,您需要在StreamHandler创建之前移动wx.App创建。不幸的是,这也不起作用,因为在MyApp或MyFrame中创建的所有记录器实例都不会连接到实际的记录器“main”。“main”的流被重定向到wx的重定向帧,但“main.MyApp”和“main.MyFrame”记录器不是“main”的子项,因为在创建“main.MyApp”和“main.MyFrame”时,“main”不存在。由于他们没有设置格式化程序和处理程序,所以他们不知道将MyApp和MyFrame中的调试消息放在哪里。唯一的选项是您必须编写自定义处理程序。我决定使用Gabriel Genellina的LoggingWebMonitor()作为解决方案。