diff options
author | Bryn M. Reeves <bmr@redhat.com> | 2018-09-07 12:15:10 -0400 |
---|---|---|
committer | Bryn M. Reeves <bmr@redhat.com> | 2018-09-10 15:43:53 +0100 |
commit | 9aaba972bf6a42c33ea9bca80f07bfb880ba45a1 (patch) | |
tree | 3de02015473f235ce671a979222d50c355bdbaa9 | |
parent | 5d6228b85e174dee8abcc4c206a1e9034242c6c6 (diff) | |
download | sos-9aaba972bf6a42c33ea9bca80f07bfb880ba45a1.tar.gz |
[sosreport] trap directly to PDB in handle_exception()
Now that plugins are run in a threadpool, it is not possible to
defer the call to pdb.post_mortem() to the top-level exception
handler in the main thread: this is due to the fact that in a pool,
exceptions are caught and saved to be re-raised to thread calling
the pool when results are returned. When the saved exception is
raised to the top-level handler the execution context it relates
to is gone: the backtrace and stack frame have been torn down and
only very limited information is available from the exception
frame.
Instead, catch these exceptions _inside_ the thread pool context,
and directly trap to the Python debugger. This allows plugin code
to be debugged interactively with the full backtrace and with all
access to local variables and the execution stack. In addition,
this means that after the debugger has handled the exception it is
possible to return to the run and continue until report completion.
One side effect of this change is that the *-plugin-errors.txt
file containng the backtrace is now written into the archive
whether or not --debug is given.
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
-rw-r--r-- | sos/sosreport.py | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/sos/sosreport.py b/sos/sosreport.py index 44be75a1..77ae7161 100644 --- a/sos/sosreport.py +++ b/sos/sosreport.py @@ -30,6 +30,7 @@ from shutil import rmtree import tempfile import hashlib from concurrent.futures import ThreadPoolExecutor, TimeoutError +import pdb from sos import _sos as _ from sos import __version__ @@ -504,7 +505,13 @@ class SoSReport(object): def handle_exception(self, plugname=None, func=None): if self.raise_plugins or self.exit_process: - raise + # retrieve exception info for the current thread and stack. + (etype, val, tb) = sys.exc_info() + # we are NOT in interactive mode, print the exception... + traceback.print_exception(etype, val, tb, file=sys.stdout) + print_() + # ...then start the debugger in post-mortem mode. + pdb.post_mortem(tb) if plugname and func: self._log_plugin_exception(plugname, func) |