I have made the simply logging of crashes (unhandled exceptions): At start you simple call CrashEngine.register("sw", "1.1.7") from main thread.
import sys
import time
import os
import traceback
from PyQt5.QtWidgets import *
class CrashEngine:
@staticmethod
def register(name, version):
CrashEngine.name = name
CrashEngine.version = version
sys.excepthook = CrashEngine.__logCrash
@staticmethod
def __logCrash(exc_type, exc_value, exc_traceback):
crash = "".join(traceback.format_exception(exc_type, exc_value, exc_traceback))
with open("crash.log", "w") as f:
f.write(time.ctime() + "\n")
f.write("Software name: " + CrashEngine.name + "\n")
f.write("Software version: " + CrashEngine.version + "\n")
f.write("\n")
f.write(crash)
CrashEngine.__showDialog()
@staticmethod
def __showDialog():
message = ("Fatal error occurred and application will be terminated.\n\n"
"Crash log was created at:\n" +
os.getcwd() + "\crash.log.\n\n"
"Please send log to ***@***.com")
msg = QMessageBox(QMessageBox.Critical, "Application Crashed", message)
msg.exec()
quit(1)
Everything worked excellent until i have meet multithreaded app where is sys.excepthook raised sometimes from different thread than main thread. As we know Calling GUI from different threads will result in unexpected behavior and crash in most of time.
The only thing i know is create slot in QMainWindow and create Signal in CrashEngine and connect them. But this is what I don't want to because CrashEngine is used in so many scripts, programs, etc and I don't want to add same piece of code (showing MsgBox) in all of them.
UPDATE: I reworked code according to @three_pineapples suggestion but via PyQt framework instead of pure Python.
@staticmethod
def __showDialog():
path = sys.executable
arg = os.path.dirname(os.path.abspath(__file__)) + "\\show_crash.py"
QProcess.startDetached(path, [arg])
sys.exit(1)
and show_crash.py contains:
import sys
import os
from PyQt5.QtWidgets import *
class ErrorWindow(QMessageBox):
def __init__(self):
super().__init__()
self.setWindowTitle("Application Crashed")
message = ("Fatal error occurred and application was terminated.\n\n"
"Crash log was created at:\n" +
os.getcwd() + "\crash.log.\n\n"
"Please send log to ***@***.com")
self.setText(message)
self.setIcon(QMessageBox.Critical)
self.show()
def main():
app = QApplication(sys.argv)
ex = ErrorWindow()
sys.exit(app.exec_())
main()