Python、tkinter 和导入的类 : logging uncaught exceptions

标签 python exception logging tkinter

我正在编写一些想要与我的团队共享的脚本,因此我一直在构建大量日志记录,以便在他们在某个地方遇到崩溃时更容易进行调试,从那时起我就可以看到到底发生了什么崩溃。

一般记录到文件没有问题,但我遇到了未捕获异常的问题。我尝试了各种方法来使其正常工作,例如参见 thisthis 。当我从 IDLE 或命令提示符运行它时,似乎 sys.excepthook 没有被调用。

昨天,如果异常发生在主模块中,它会正确记录,但如果异常发生在导入的类中,则不会正确记录。现在异常根本不会被记录,我不知道我改变了什么(所以我今天安装了 Git :-P)

这是我试图开始工作的代码,主模块:

import tkinter as tk
import sys
import traceback
import logging
import datetime

import exception_logging_test_imported_class as impclass

# Main Class
class ExceptMain(tk.Frame):
    def __init__(self, parent):
        logging.info('Start main')
        tk.Frame.__init__(self, parent, relief='groove', bd=4)
        self.parent = parent
        self.pack()
        tk.Label(self, text='This is the main class', bg='white').pack()
        tk.Button(self, text='Start subframe', command=self.run).pack()
        tk.Button(self, text='Throw main exception', command=self.throwex).pack()
        tk.Button(self, text='Start imported class', command=self.start_import).pack()

    # Function to start another frame, from this same file
    def run(self):
        logging.info('Run main function')
        subclass = ExceptSubclass(self)
        subclass.pack()

    # Function to start an imported frame class
    def start_import(self):
        imported_class = impclass.ExtraClass(self)
        imported_class.pack()

    # Throw an exception
    def throwex(self):
        raise ValueError("Main is burning down")

#Another class in this file
class ExceptSubclass(tk.Frame):
    def __init__(self, parent):
        logging.info('Start subframe')
        tk.Frame.__init__(self, parent, relief='groove', bd=4)
        self.parent = parent
        self.pack()
        tk.Label(self, text='This is the subclass', bg='white').pack()
        tk.Button(self, text='run sub function', command=self.script).pack()
        tk.Button(self, text='Throw sub exception', command=self.throwexsub).pack()

    # Run something
    def script(self):
        logging.info('Run subfunction')
        tk.Label(self, text='Script has run').pack()

    # Throw an exception
    def throwexsub(self):
        thing = []
        thing[1]

# Use a logger object or just logging
logger_not_just_logging = False
if logger_not_just_logging:
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)
    logger.addHandler(logging.FileHandler("ZZ_logging_test.log"))
else:
    logging.basicConfig(filename='ZZ_logging_test.log', level=logging.DEBUG)

logging.info('<<<<< STARTING NEW INSTANCE >>>>>')

# This function needs to be called somehow when an uncaught exception happens
def exception_handler(etype, value, tb):
    logging.exception("Uncaught exception: {0}".format(str(value)))
    with open('ZZ_exception_test.log', 'a') as file:
        file.write("<<< Exception occurred at " + str(datetime.datetime.now()) + " >>>")
        traceback.print_exception(etype, value, tb, file=file)

# Install the hook  
sys.excepthook = exception_handler

# Run the app
root = tk.Tk()
app = ExceptMain(root)
root.mainloop()

还有一个子模块:

import tkinter as tk
import logging

# This is an imported frame
class ExtraClass(tk.Frame):
    def __init__(self, parent):
        logging.info('Start imported frame')
        tk.Frame.__init__(self, parent, relief='groove', bd=4)
        self.parent = parent
        self.pack()
        tk.Label(self, text='This is an imported frame', bg='white').pack()
        tk.Button(self, text='run imported frame function', command=self.script).pack()
        tk.Button(self, text='Throw imported exception', command=self.throwexsub).pack()

    # Imported frame has a function
    def script(self):
        logging.info('Run imported frame function')
        tk.Label(self, text='Imported script has run').pack()

    # Imported frame throws an exception
    def throwexsub(self):
        thing = []
        thing[1]

我期望得到的是一个包含所有常规日志记录的文件和一个包含异常和堆栈跟踪的单独文件。

如果您能帮我解决这个问题,我将永远感激不已!

最佳答案

啊哈,我发现问题了。 以上述方式安装的 excepthook 仅在较高级别上工作。当我注意到我的类抛出的异常仍在控制台中记录而键盘中断确实按我想要的方式记录在文件中时,我发现了这一点。

接下来我发现在 Python 中使用线程时可能会遇到类似的问题。主线程仍将按需要记录,但其他线程中的异常不会记录。然后我发现类可以覆盖我对异常处理方式的覆盖。由于我的所有代码都在 tkinter 主循环中运行,我可能需要告诉该位执行我想要它执行的操作。这种洞察使我得出this所以答案和一行代码一切都被修复了,一直在主类的末尾:

# Run the app
root = tk.Tk()
root.report_callback_exception = exception_handler # this here.
app = ExceptMain(root)
root.mainloop()

关于Python、tkinter 和导入的类 : logging uncaught exceptions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43941276/

相关文章:

python - pyuic5 - ModuleNotFoundError : No module named PyQt5. sip

python - 如何轻松编写带有变量的多行文件(python 2.6)?

python - 为字典中的每个键值创建单独的 pandas 数据帧

swift - 是否可以使用 "try?"在保护语句中检索异常?

exception - Junit 异常处理

java - 我将如何使用 slf4j/log4j/java.util.logging robuSTLy 记录二进制或 XML?

c# - 城堡记录设施

针对 fuzzywuzzy 的 Python 多处理列表

Android 和引入自己的自定义 key 存储的异常

java - 嵌套异常是 java.lang.NoClassDefFoundError : org/slf4j/impl/MessageFormatter