Ich benutze ein Modul in meiner Python-App, die eine Menge von Nachrichten mit dem Logging-Modul schreibt. Anfangs verwendete ich dies in einer Konsolenanwendung und es war ziemlich einfach, die Logging-Ausgabe mit einem Konsolen-Handler auf der Konsole anzuzeigen. Jetzt habe ich eine GUI-Version meiner App mit wxPython entwickelt und möchte die gesamte Logging-Ausgabe zu einem benutzerdefinierten Steuerelement anzeigen - eine mehrzeilige textCtrl. Gibt es eine Möglichkeit, einen benutzerdefinierten Logging-Handler zu erstellen, so dass ich die gesamte Logging-Ausgabe umleiten kann und die Logging-Nachrichten anzeigen kann, wo immer ich möchte - in diesem Fall eine wxPython-App.Wie kann ich den Logger mithilfe eines benutzerdefinierten Protokollierungshandlers in eine wxPython-textCtrl umleiten?
Antwort
erstellen Handler
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)
Dann in Ihrer Kontrolle
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()
Sie müssen ein benutzerdefiniertes logging.Handler
erstellen und es zu Ihrem logging.Logger
hinzufügen.
Aus der Dokumentation:
Handler
Objekte sind für verantwortlich die entsprechende Protokoll Nachrichten Dispatching (basierend auf den Schwere der Log-Meldungen) an den angegebenen Ziel absetzen. Logger-Objekte können null oder mehr Handler-Objekte mit einer Methode addHandler() zu selbst hinzufügen. Als ein Beispielszenario könnte eine Anwendung alle Protokollnachrichten an eine Protokolldatei senden, alle Protokollfehlermeldungen oder höher an stdout, und alle Nachrichten von kritisch an eine E-Mail-Adresse senden. Dieses Szenario erfordert drei einzelne Handler, wobei jeder Handler ist verantwortlich für das Senden von Nachrichten mit einem bestimmten Schweregrad an einen spezifischen Speicherort .
Siehe http://docs.python.org/library/logging.html#handler-objects für die Handler
API.
Insbesondere ist es die Handler.emit(record)
Methode, die Sie implementieren können, um das Ziel der Ausgabe anzugeben. Vermutlich würden Sie dies implementieren, um TextCtrl.AppendText
zu rufen.
Hier ist ein einfaches Arbeitsbeispiel:
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()
Screenshot:
Update: Wie iondiode darauf hinweist, kann dieses einfache Skript Probleme haben, wenn mehrere Threads in Ihrer App vorhanden sind, die alle über einen solchen Handler protokollieren; Im Idealfall sollte nur ein UI-Thread die Benutzeroberfläche aktualisieren. Sie können den vorgeschlagenen Ansatz zum Protokollieren des Ereignisses mithilfe eines benutzerdefinierten Ereignisses gemäß seiner Antwort verwenden.
ist die Zeile logging.Handler .__ init __ (selbst) korrekt?Ist es richtig, sich selbst in __init__ zu übergeben? – piertoni
- 1. Erstellen eines Protokollierungshandlers für die Verbindung mit Oracle?
- 2. Wie kann ich auf den Host eines benutzerdefinierten Elements zugreifen?
- 3. Wie javax.mail.Session umleiten setDebugOut zu log4j Logger?
- 4. Wie kann ich mit nginx zu einer benutzerdefinierten URL umleiten?
- 5. Wie initialisiere ich den Logger für Integrationstests?
- 6. Kann ich den Log-Header für Ruby Logger deaktivieren?
- 7. Wie kann ich im Servlet mithilfe der Methode response.sendRedirect() auf eine andere Seite umleiten?
- 8. Wie kann ich auf eine private Google-Gruppe umleiten?
- 9. Wie kann ich einen Logger für eine große Anwendung freigeben?
- 10. Wie kann ich meine WordPress-Website in eine Subdomain umleiten?
- 11. Wie umleiten Sie die Ausgabe eines CMake benutzerdefinierten Befehls in eine Datei?
- 12. Wie kann ich den Loglevel eines einzelnen Loggers in Runtime ändern?
- 13. Wie bekomme ich den Logger in slf4j verpackt?
- 14. Flex: Wie platziere ich Elemente in einem HorizontalList-Steuerelement (mithilfe eines benutzerdefinierten ItemRenderer)
- 15. Wie kann ich den benutzerdefinierten UIGestureRecognizer in Swift definieren?
- 16. JSch Logger - wo kann ich den Level konfigurieren
- 17. NativeScript Wie kann ich den Kamerastream an HTML Canvas umleiten?
- 18. Wert eines benutzerdefinierten Attributs mithilfe von JavaScript oder Jquery abrufen
- 19. Wie kann ich eine Liste von benutzerdefinierten Objekten mithilfe von WCF serialisieren?
- 20. Wie kann ich einen benutzerdefinierten Transformator debuggen
- 21. Wie kann ich ein Commit mithilfe eines SHA rückgängig machen?
- 22. Wie kann ich ein anderes Modell mithilfe eines Callbacks aktualisieren?
- 23. Wie umleiten npgsql Log-Ausgabe zu einem log4net Logger?
- 24. Wie kann ich den Standort mithilfe von UIActivityViewController freigeben?
- 25. Wie kann ich LibLog mit einer benutzerdefinierten Serilog Logger-Konfiguration verwenden?
- 26. Wie umleiten eines Benutzers in angular.js mithilfe von Access Token-Mechanismus?
- 27. Wie kann ich eine Zeichenfolge durch eine andere Zeichenfolge mithilfe eines Arrays ersetzen?
- 28. Wie leite ich den Python Logger zu Tkinkers Listbox?
- 29. Wie umleiten alle httpErrors zu benutzerdefinierten URL?
- 30. Wie umleiten Sie Ordner in einem Unterverzeichnis mithilfe von htaccess in eine bestimmte Datei?
@Vinjay Sajip: Ihre Antwort ist nicht Thread sicher, wenn Ereignisse außerhalb von Wx Hauptschleife protokolliert werden. Es ist sicherer, wx-Ereignisse zu verwenden, um Daten von externen Threads zu verarbeiten. – iondiode
Zweifellos hast du recht, aber meine Antwort zeigt nur auf den Ansatz, der verwendet wird, anstatt eine vollständig kampferprobte Lösung anzubieten. –