如何使用自定义日志记录处理程序将记录器重定向到wxPython textCtrl?
我在我的python应用程序中使用了一个模块,它使用日志记录模块写了很多消息。最初我在控制台应用程序中使用它,并且使用控制台处理程序使日志输出显示在控制台上非常简单。现在我使用wxPython开发了我的应用程序的GUI版本,并且我想将所有日志输出显示到自定义控件 - 多行textCtrl。有没有一种方法可以创建自定义日志记录处理程序,以便我可以将所有日志记录输出重定向到那里,并在任何地方显示日志消息/但是我希望 - 在这种情况下,是一个wxPython应用程序。如何使用自定义日志记录处理程序将记录器重定向到wxPython textCtrl?
在你的控制创建处理程序
import wx
import wx.lib.newevent
import logging
# create event type
wxLogEvent, EVT_WX_LOG_EVENT = wx.lib.newevent.NewEvent()
class wxLogHandler(logging.Handler):
"""
A handler class which sends log strings to a wx object
"""
def __init__(self, wxDest=None):
"""
Initialize the handler
@param wxDest: the destination object to post the event to
@type wxDest: wx.Window
"""
logging.Handler.__init__(self)
self.wxDest = wxDest
self.level = logging.DEBUG
def flush(self):
"""
does nothing for this handler
"""
def emit(self, record):
"""
Emit a record.
"""
try:
msg = self.format(record)
evt = wxLogEvent(message=msg,levelname=record.levelname)
wx.PostEvent(self.wxDest,evt)
except (KeyboardInterrupt, SystemExit):
raise
except:
self.handleError(record)
然后
self.Bind(EVT_WX_LOG_EVENT, self.onLogEvent)
def onLogEvent(self,event):
'''
Add event.message to text window
'''
msg = event.message.strip("\r")+"\n"
self.logwindow.AppendText(msg) # or whatevery
event.Skip()
您将需要创建自定义logging.Handler
并将其添加到您的logging.Logger
。
从文档:
Handler
对象负责 调度相应的日志 消息(基于日志消息 严重性)的处理程序的规定 目的地。记录器对象可以使用addHandler() 方法将 零个或多个处理程序对象本身添加到 本身。举例来说, 应用程序可能希望将所有日志 消息发送到日志文件,所有日志文件中包含错误或更高的错误消息,标准输出, 以及所有对电子邮件地址至关重要的消息。这种情况下需要三个独立的处理程序,其中每个处理程序负责将特定严重性的消息发送到 特定位置。
请参阅http://docs.python.org/library/logging.html#handler-objects为Handler
API。
特别是,您可以使用Handler.emit(record)
方法来指定输出的目的地。据推测,你会执行这个调用TextCtrl.AppendText
。
这里有一个简单的工作示例:
import logging
import random
import sys
import wx
logger = logging.getLogger(__name__)
class WxTextCtrlHandler(logging.Handler):
def __init__(self, ctrl):
logging.Handler.__init__(self)
self.ctrl = ctrl
def emit(self, record):
s = self.format(record) + '\n'
wx.CallAfter(self.ctrl.WriteText, s)
LEVELS = [
logging.DEBUG,
logging.INFO,
logging.WARNING,
logging.ERROR,
logging.CRITICAL
]
class Frame(wx.Frame):
def __init__(self):
TITLE = "wxPython Logging To A Control"
wx.Frame.__init__(self, None, wx.ID_ANY, TITLE)
panel = wx.Panel(self, wx.ID_ANY)
log = wx.TextCtrl(panel, wx.ID_ANY, size=(300,100),
style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
btn = wx.Button(panel, wx.ID_ANY, 'Log something!')
self.Bind(wx.EVT_BUTTON, self.onButton, btn)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(log, 1, wx.ALL|wx.EXPAND, 5)
sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
panel.SetSizer(sizer)
handler = WxTextCtrlHandler(log)
logger.addHandler(handler)
FORMAT = "%(asctime)s %(levelname)s %(message)s"
handler.setFormatter(logging.Formatter(FORMAT))
logger.setLevel(logging.DEBUG)
def onButton(self, event):
logger.log(random.choice(LEVELS), "More? click again!")
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = Frame().Show()
app.MainLoop()
截图:
更新:正如iondiode指出的,如果您的应用程序中有多个线程,通过这样的处理程序进行所有日志记录,则此简单脚本可能会有问题;理想情况下只有一个UI线程应该更新UI。根据他的回答,您可以使用建议的使用自定义事件记录事件的方法。
是行logging.Handler .__ init __(self)是否正确?在__init__中传递自己是否正确? – piertoni 2016-01-19 07:16:28
@Vinjay Sajip:如果事件在wx主循环之外被记录,你的回答不是线程安全的。使用wx事件处理来自外部线程的数据更安全。 – iondiode 2010-05-12 23:49:07
毫无疑问,你是对的,但我的回答只是指出要使用的方法,而不是提供经过战场考验的完整解决方案。 – 2010-05-13 14:42:26