Browse Source

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.
patch-4
SomberNight 3 years ago
parent
commit
c331c311db
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 38
      electrum/base_crash_reporter.py
  2. 3
      electrum/daemon.py
  3. 3
      electrum/gui/kivy/uix/dialogs/crash_reporter.py
  4. 2
      electrum/gui/qt/__init__.py
  5. 3
      electrum/gui/qt/exception_window.py
  6. 3
      electrum/util.py

38
electrum/base_crash_reporter.py

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

3
electrum/daemon.py

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

3
electrum/gui/kivy/uix/dialogs/crash_reporter.py

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

2
electrum/gui/qt/__init__.py

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

3
electrum/gui/qt/exception_window.py

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

3
electrum/util.py

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

Loading…
Cancel
Save