Improve crash log handling because of single-instance.

This commit is contained in:
Florian Bruhin 2014-10-14 20:47:06 +02:00
parent bfcb309460
commit cf6d303ad1
2 changed files with 16 additions and 32 deletions

View File

@ -44,7 +44,7 @@ from qutebrowser.widgets import mainwindow, crash
from qutebrowser.keyinput import modeman
from qutebrowser.utils import (log, version, message, readline, utils, qtutils,
urlutils, debug, objreg, usertypes, standarddir,
ipc)
ipc, earlyinit)
# We import utilcmds to run the cmdutils.register decorators.
from qutebrowser.utils import utilcmds # pylint: disable=unused-import
@ -172,41 +172,27 @@ class Application(QApplication):
def _handle_segfault(self):
"""Handle a segfault from a previous run."""
# FIXME If an empty logfile exists, we log to stdout instead, which is
# the only way to not break multiple instances.
# However this also means if the logfile is there for some weird
# reason, we'll *always* log to stderr, but that's still better than no
# dialogs at all.
# probably irrelevant with single instance support
# https://github.com/The-Compiler/qutebrowser/issues/10
path = standarddir.get(QStandardPaths.DataLocation)
logname = os.path.join(path, 'crash.log')
# First check if an old logfile exists.
if os.path.exists(logname):
with open(logname, 'r', encoding='ascii') as f:
data = f.read()
try:
os.remove(logname)
except PermissionError:
log.init.warning("Could not remove crash log!")
else:
self._init_crashlogfile()
if data:
# Crashlog exists and has data in it, so something crashed
# previously.
try:
os.remove(logname)
except PermissionError:
log.init.warning("Could not remove crash log!")
else:
self._init_crashlogfile()
self._crashdlg = crash.FatalCrashDialog(data)
self._crashdlg.show()
else:
# Crashlog exists but without data.
# This means another instance is probably still running and
# didn't remove the file. As we can't write to the same file,
# we just leave faulthandler as it is and log to stderr.
log.init.warning("Empty crash log detected. This means either "
"another instance is running (then ignore "
"this warning) or the file is lying here "
"because of some earlier crash (then delete "
"{}).".format(logname))
self._crashlogfile = None
# This probably means another instance crashed.
log.init.warning("Deleted empty crash log.")
else:
# There's no log file, so we can use this to display crashes to the
# user on the next start.
@ -217,12 +203,7 @@ class Application(QApplication):
path = standarddir.get(QStandardPaths.DataLocation)
logname = os.path.join(path, 'crash.log')
self._crashlogfile = open(logname, 'w', encoding='ascii')
faulthandler.enable(self._crashlogfile)
if (hasattr(faulthandler, 'register') and
hasattr(signal, 'SIGUSR1')):
# If available, we also want a traceback on SIGUSR1.
# pylint: disable=no-member
faulthandler.register(signal.SIGUSR1)
earlyinit.init_faulthandler(self._crashlogfile)
def _open_pages(self):
"""Open startpage etc. and process commandline args."""

View File

@ -94,15 +94,18 @@ def _die(message, exception=True):
sys.exit(1)
def init_faulthandler():
def init_faulthandler(fileobj=sys.__stderr__):
"""Enable faulthandler module if available.
This print a nice traceback on segfauls.
We use sys.__stderr__ instead of sys.stderr here so this will still work
when sys.stderr got replaced, e.g. by "Python Tools for Visual Studio".
Args:
fobj: An opened file object to write the traceback to.
"""
if sys.__stderr__ is None:
if fileobj is None:
# When run with pythonw.exe, sys.__stderr__ can be None:
# https://docs.python.org/3/library/sys.html#sys.__stderr__
# If we'd enable faulthandler in that case, we just get a weird
@ -112,7 +115,7 @@ def init_faulthandler():
# to write to a file so we can display a crash to the user at the next
# start.
return
faulthandler.enable(sys.__stderr__)
faulthandler.enable(fileobj)
if hasattr(faulthandler, 'register') and hasattr(signal, 'SIGUSR1'):
# If available, we also want a traceback on SIGUSR1.
faulthandler.register(signal.SIGUSR1) # pylint: disable=no-member