> 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, "")
_______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list