2010-04-22 60 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日誌記錄。

相關問題