Python: объедините logging и wx так, чтобы поток регистрации перенаправлялся в кадр stdout / stderr - PullRequest
3 голосов
/ 22 апреля 2010

Вот в чем дело:

Я пытаюсь объединить модуль журналирования с функцией перенаправления 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 / ОШИБКА / ПРЕДУПРЕЖДЕНИЕ / КРИТИЧЕСКИЙ
- сообщения типа 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.

должно отображаться в кадре, а не на консоли.

Мне кажется, что wx.App не может перенаправить stderr на фрейм, как только экземпляр регистратора использует stderr в качестве вывода. Документы wxPythons утверждают требуемое поведение, см. здесь.

Есть идеи?

Уве

Ответы [ 2 ]

1 голос
/ 06 июня 2010

Способ сделать это, который я считаю более элегантным, - создать собственный подкласс обработчика ведения журнала, который отправляет свои сообщения в определенный кадр ведения журнала.

Это облегчает включение входа в систему графического интерфейса пользователя /выключено во время выполнения.

1 голос
/ 22 апреля 2010

Когда 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 установил, поэтому более простым решением является создание wx.App. перед созданием обработчика streap, например в коде переместите 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...