2010-04-22 61 views
3

事情是这样的:的Python:使日志流redirectet到标准输出/标准错误帧结合测井和WX

我想记录模块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类型的消息显示在控制台上或单独的框架中,具体取决于它们的创建位置
- 控制台上显示不在MyApp或MyFrame中的记录器消息
01 -从内部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.

任何想法?

乌韦

回答

1

当wx.App表示,将stdout重定向/标准错误,以一个弹出窗口,这意味着什么真的是,它会重定向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") 

问题是,如果在创建StreamHandler中后创建wxApp,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) 
+0

>日志不写入sys.stdout或sys.stderr 这不是真的(如果文档是正确的(http://docs.python.org/library/logging.html#module-logging .handlers))。在文档状态下,如果logging.handlers.StreamHandler的实例创建时没有参数,则使用sys.stderr。 – Uwe 2010-04-22 11:34:02

+0

@Uwe,我已经更新了答案,您需要在创建Streamhandler之前移动wx.App – 2010-04-22 13:56:38

+0

不幸的是,这将不起作用,因为在MyApp或MyFrame内创建的所有记录器实例都不会连接到实际的记录器“main” 。 “main”的流被重定向到wx的重定向帧,但“main.MyApp”和“main.MyFrame”记录器不是“main”的子项,因为创建“main.MyApp”时不存在“main” “main.MyFrame”。因为他们还没有设置格式化程序和处理程序,所以不知道从MyApp和MyFrame中放置调试消息的位置。 – Uwe 2010-04-22 14:15:35

1

我这样做,我认为这是更优雅的方式,是创建一个自定义日志Handler子类职位的信息到特定的日志框架。

这样可以更轻松地在运行时打开/关闭GUI日志记录。

相关问题