1
0

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:
SomberNight
2021-11-05 19:55:22 +01:00
parent e0246b30b9
commit c331c311db
6 changed files with 44 additions and 8 deletions

View File

@@ -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

View File

@@ -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.")

View File

@@ -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()

View File

@@ -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()

View File

@@ -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:

View File

@@ -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):