crash reporter: add EarlyExceptionsQueue
`util.send_exception_to_crash_reporter` is now useful and can be transparently used even before the exception hook is set up.
This commit is contained in:
@@ -24,6 +24,7 @@ import json
|
||||
import locale
|
||||
import traceback
|
||||
import sys
|
||||
import queue
|
||||
|
||||
from .version import ELECTRUM_VERSION
|
||||
from . import constants
|
||||
@@ -131,6 +132,43 @@ class BaseCrashReporter(Logger):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class EarlyExceptionsQueue:
|
||||
"""Helper singleton for explicitly sending exceptions to crash reporter.
|
||||
|
||||
Typically the GUIs set up an "exception hook" that catches all otherwise
|
||||
uncaught exceptions (which unroll the stack of a thread completely).
|
||||
This class provides methods to report *any* exception, and queueing logic
|
||||
that delays processing until the exception hook is set up.
|
||||
"""
|
||||
|
||||
_is_exc_hook_ready = False
|
||||
_exc_queue = queue.Queue()
|
||||
|
||||
@classmethod
|
||||
def set_hook_as_ready(cls):
|
||||
if cls._is_exc_hook_ready:
|
||||
return
|
||||
cls._is_exc_hook_ready = True
|
||||
while cls._exc_queue.qsize() > 0:
|
||||
e = cls._exc_queue.get()
|
||||
cls._send_exception_to_crash_reporter(e)
|
||||
|
||||
@classmethod
|
||||
def send_exception_to_crash_reporter(cls, e: BaseException):
|
||||
if cls._is_exc_hook_ready:
|
||||
cls._send_exception_to_crash_reporter(e)
|
||||
else:
|
||||
cls._exc_queue.put(e)
|
||||
|
||||
@staticmethod
|
||||
def _send_exception_to_crash_reporter(e: BaseException):
|
||||
assert EarlyExceptionsQueue._is_exc_hook_ready
|
||||
sys.excepthook(type(e), e, e.__traceback__)
|
||||
|
||||
|
||||
send_exception_to_crash_reporter = EarlyExceptionsQueue.send_exception_to_crash_reporter
|
||||
|
||||
|
||||
def trigger_crash():
|
||||
# note: do not change the type of the exception, the message,
|
||||
# or the name of this method. All reports generated through this
|
||||
|
||||
@@ -487,8 +487,6 @@ class Daemon(Logger):
|
||||
if self.config.get('use_gossip', False):
|
||||
self.network.start_gossip()
|
||||
|
||||
self.exception = None # type: Optional[Exception]
|
||||
|
||||
self._stop_entered = False
|
||||
self._stopping_soon_or_errored = threading.Event()
|
||||
self._stopped_event = threading.Event()
|
||||
@@ -508,7 +506,6 @@ class Daemon(Logger):
|
||||
raise
|
||||
except Exception as e:
|
||||
self.logger.exception("taskgroup died.")
|
||||
self.exception = e
|
||||
util.send_exception_to_crash_reporter(e)
|
||||
finally:
|
||||
self.logger.info("taskgroup stopped.")
|
||||
|
||||
@@ -12,7 +12,7 @@ from kivy.utils import platform
|
||||
|
||||
from electrum.gui.kivy.i18n import _
|
||||
|
||||
from electrum.base_crash_reporter import BaseCrashReporter
|
||||
from electrum.base_crash_reporter import BaseCrashReporter, EarlyExceptionsQueue
|
||||
from electrum.logging import Logger
|
||||
|
||||
|
||||
@@ -185,6 +185,7 @@ class ExceptionHook(base.ExceptionHandler, Logger):
|
||||
base.ExceptionManager.add_handler(self)
|
||||
# For everything else:
|
||||
sys.excepthook = lambda exctype, value, tb: self.handle_exception(value)
|
||||
EarlyExceptionsQueue.set_hook_as_ready()
|
||||
|
||||
def handle_exception(self, _inst):
|
||||
exc_info = sys.exc_info()
|
||||
|
||||
@@ -403,8 +403,6 @@ class ElectrumGui(Logger):
|
||||
signal.signal(signal.SIGINT, lambda *args: self.app.quit())
|
||||
# hook for crash reporter
|
||||
Exception_Hook.maybe_setup(config=self.config)
|
||||
if self.daemon.exception: # if daemon errored too early, replay that now:
|
||||
send_exception_to_crash_reporter(self.daemon.exception)
|
||||
# first-start network-setup
|
||||
try:
|
||||
self.init_network()
|
||||
|
||||
@@ -31,7 +31,7 @@ from PyQt5.QtWidgets import (QWidget, QLabel, QPushButton, QTextEdit,
|
||||
QMessageBox, QHBoxLayout, QVBoxLayout)
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.base_crash_reporter import BaseCrashReporter
|
||||
from electrum.base_crash_reporter import BaseCrashReporter, EarlyExceptionsQueue
|
||||
from electrum.logging import Logger
|
||||
from electrum import constants
|
||||
from electrum.network import Network
|
||||
@@ -172,6 +172,7 @@ class Exception_Hook(QObject, Logger):
|
||||
|
||||
sys.excepthook = self.handler
|
||||
self._report_exception.connect(_show_window)
|
||||
EarlyExceptionsQueue.set_hook_as_ready()
|
||||
|
||||
@classmethod
|
||||
def maybe_setup(cls, *, config: 'SimpleConfig', wallet: 'Abstract_Wallet' = None) -> None:
|
||||
|
||||
@@ -1112,7 +1112,8 @@ def setup_thread_excepthook():
|
||||
|
||||
|
||||
def send_exception_to_crash_reporter(e: BaseException):
|
||||
sys.excepthook(type(e), e, e.__traceback__)
|
||||
from .base_crash_reporter import send_exception_to_crash_reporter
|
||||
send_exception_to_crash_reporter(e)
|
||||
|
||||
|
||||
def versiontuple(v):
|
||||
|
||||
Reference in New Issue
Block a user