[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
Re: [PATCH] have anaconda write anacdump.txt on demand
- From: David Lehman <dlehman redhat com>
- To: Discussion of Development and Customization of the Red Hat Linux Installer <anaconda-devel-list redhat com>
- Subject: Re: [PATCH] have anaconda write anacdump.txt on demand
- Date: Thu, 04 Dec 2008 15:19:00 -0600
> I thought it'd be nice if we could generate an anacdump.txt on demand,
> to help debug where anaconda's stuck but hasn't crashed. The attached
> patch causes anaconda to write /tmp/anacdump.txt when SIGUSR2 is
> received. It requires the stuff Peter just mailed.
Nice idea.
What I don't like is adding new code to isys to do things we can easily
do in pure python. Attached are two patches. The first one changes our
current code to use stacks instead of tracebacks in
AnacondaExceptionDump. It contains the same information, just in a
slightly different form. What we gain is the ability to generate
traceback-like data by simply calling inspect.stack() instead of having
to resort to growing isys. To be clear, this first patch is intended as
an alternative to Peter's isys.traceback patch.
The second patch is just an update of Chris' original patch that uses
the aforementioned modifications.
Again, the only thing we gain here is not growing isys. Otherwise the
two approaches are functionally equivalent as verified by diffing two
artificially generated anacdump.txt files.
Dave
diff --git a/exception.py b/exception.py
index b146315..713e1aa 100644
--- a/exception.py
+++ b/exception.py
@@ -31,6 +31,7 @@ import os
import shutil
import signal
import traceback
+import inspect
import iutil
import types
import bdb
@@ -47,10 +48,17 @@ import logging
log = logging.getLogger("anaconda")
class AnacondaExceptionDump:
- def __init__(self, type, value, tb):
+ def __init__(self, type, value, stack):
self.type = type
self.value = value
- self.tb = tb
+
+ # this isn't used, but it's an option if we want to leave the
+ # two instantiations of this class as they are instead of
+ # passing in a stack
+ if inspect.istraceback(stack):
+ stack = inspect.getinnerframes(stack)
+
+ self.stack = stack
self.tbFile = None
@@ -59,13 +67,27 @@ class AnacondaExceptionDump:
# Reverse the order that tracebacks are printed so people will hopefully quit
# giving us the least useful part of the exception in bug reports.
def __str__(self):
- lst = traceback.format_tb(self.tb)
+ lst = self.format_stack()
lst.reverse()
lst.insert(0, "anaconda %s exception report\n" % os.getenv("ANACONDAVERSION"))
lst.insert(1, 'Traceback (most recent call first):\n')
+
lst.extend(traceback.format_exception_only(self.type, self.value))
+
return joinfields(lst, "")
+ def format_stack(self):
+ frames = []
+ for (frame, file, lineno, func, ctx, idx) in self.stack:
+ if type(ctx) == type([]):
+ code = "".join(ctx)
+ else:
+ code = ctx
+
+ frames.append((file, lineno, func, code))
+
+ return traceback.format_list(frames)
+
# Create a string representation of a class and write it to fd. This
# method will recursively handle all attributes of the base given class.
def _dumpClass(self, instance, fd, level=0, parentkey="", skipList=[]):
@@ -180,11 +202,8 @@ class AnacondaExceptionDump:
fd.write(str(self))
- trace = self.tb
- if trace is not None:
- while trace.tb_next:
- trace = trace.tb_next
- frame = trace.tb_frame
+ if self.stack:
+ frame = self.stack[-1][0]
fd.write ("\nLocal variables in innermost frame:\n")
try:
for (key, value) in frame.f_locals.items():
@@ -220,7 +239,9 @@ class AnacondaExceptionDump:
import hashlib
s = ""
- for (file, lineno, func, text) in traceback.extract_tb(self.tb):
+ for (file, lineno, func, text) in [f[1:5] for f in self.stack]:
+ if type(text) == type([]):
+ text = "".join(text)
s += "%s %s %s\n" % (file, func, text)
return hashlib.sha256(s).hexdigest()
@@ -548,8 +569,11 @@ def handleException(anaconda, (type, value, tb)):
# restore original exception handler
sys.excepthook = sys.__excepthook__
+ # convert the traceback to a stack
+ stack = inspect.getinnerframes(tb)
+
# Save the exception file to local storage first.
- exn = AnacondaExceptionDump(type, value, tb)
+ exn = AnacondaExceptionDump(type, value, stack)
exn.write(anaconda)
text = str(exn)
diff --git a/partedUtils.py b/partedUtils.py
index fac1433..ea6f4a0 100644
--- a/partedUtils.py
+++ b/partedUtils.py
@@ -37,7 +37,7 @@ import raid
import dmraid
import block
import lvm
-import traceback
+import inspect
from flags import flags
from errors import *
from constants import *
@@ -1142,7 +1142,8 @@ class DiskSet:
raise
except:
(type, value, tb) = sys.exc_info()
- exn = exception.AnacondaExceptionDump(type, value, tb)
+ stack = inspect.getinnerframes(tb)
+ exn = exception.AnacondaExceptionDump(type, value, stack)
lines = exn.__str__()
for line in lines:
log.error(line)
--- a/anaconda
+++ b/anaconda
@@ -502,6 +502,13 @@ class Anaconda:
# *sigh* we still need to be able to write this out
self.xdriver = None
+ def dumpState(self):
+ from exception import AnacondaExceptionDump
+ from inspect import stack as _stack
+ # Skip the frames for isys.traceback, dumpState, and the signal handler.
+ exn = AnacondaExceptionDump(None, None, _stack())
+ exn.write(anaconda)
+
def writeXdriver(self, instPath="/"):
# this should go away at some point, but until it does, we
# need to keep it around. it could go into instdata but this
@@ -588,7 +595,7 @@ if __name__ == "__main__":
# this handles setting up updates for pypackages to minimize the set needed
setupPythonUpdates()
- import signal, traceback, string, isys, iutil, time
+ import signal, string, isys, iutil, time
from exception import handleException
import dispatch
import warnings
@@ -611,6 +618,9 @@ if __name__ == "__main__":
signal.signal(signal.SIGINT, signal.SIG_DFL)
signal.signal(signal.SIGSEGV, isys.handleSegv)
+ # add our own additional signal handlers
+ signal.signal(signal.SIGUSR2, lambda signum, frame: anaconda.dumpState())
+
setupEnvironment()
# we need to do this really early so we make sure its done before rpm
--- a/exception.py 2008-12-04 15:05:23.000000000 -0600
+++ b/exception.py 2008-12-04 15:04:14.000000000 -0600
@@ -72,7 +72,8 @@
lst.insert(0, "anaconda %s exception report\n" % os.getenv("ANACONDAVERSION"))
lst.insert(1, 'Traceback (most recent call first):\n')
- lst.extend(traceback.format_exception_only(self.type, self.value))
+ if self.type is not None and self.value is not None:
+ lst.extend(traceback.format_exception_only(self.type, self.value))
return joinfields(lst, "")
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]