diff options
-rw-r--r-- | tools/telemetry/telemetry/core/web_contents.py | 4 | ||||
-rw-r--r-- | tools/telemetry/telemetry/page/page_runner.py | 23 | ||||
-rw-r--r-- | tools/telemetry/telemetry/util/exception_formatter.py | 93 | ||||
-rw-r--r-- | tools/telemetry/telemetry/util/global_hooks.py | 10 |
4 files changed, 71 insertions, 59 deletions
diff --git a/tools/telemetry/telemetry/core/web_contents.py b/tools/telemetry/telemetry/core/web_contents.py index 25cc175..8932581 100644 --- a/tools/telemetry/telemetry/core/web_contents.py +++ b/tools/telemetry/telemetry/core/web_contents.py @@ -36,7 +36,7 @@ class WebContents(object): This method is robust against any given Evaluation timing out. """ - def IsTrue(): + def IsJavaScriptExpressionTrue(): try: return bool(self.EvaluateJavaScript(expr)) except util.TimeoutException: @@ -44,7 +44,7 @@ class WebContents(object): # may time out here early. Instead, we want to wait for the full # timeout of this method. return False - util.WaitFor(IsTrue, timeout) + util.WaitFor(IsJavaScriptExpressionTrue, timeout) def HasReachedQuiescence(self): """Determine whether the page has reached quiescence after loading. diff --git a/tools/telemetry/telemetry/page/page_runner.py b/tools/telemetry/telemetry/page/page_runner.py index dd54b95..3b4c16d 100644 --- a/tools/telemetry/telemetry/page/page_runner.py +++ b/tools/telemetry/telemetry/page/page_runner.py @@ -11,7 +11,6 @@ import random import sys import tempfile import time -import traceback from telemetry import decorators from telemetry.core import browser_finder @@ -180,12 +179,7 @@ class PageState(object): i.RunAction(self.page, self.tab, None) def CleanUpPage(self, test): - try: - test.CleanUpAfterPage(self.page, self.tab) - except Exception: - logging.error('While cleaning up %s:\n%s', self.page.url, - traceback.format_exc()) - + test.CleanUpAfterPage(self.page, self.tab) if self.page.credentials and self._did_login: self.tab.browser.credentials.LoginNoLongerNeeded( self.tab, self.page.credentials) @@ -293,13 +287,13 @@ def Run(test, page_set, expectations, finder_options): possible_browser = browser_finder.FindBrowser(finder_options) except browser_finder.BrowserTypeRequiredException, e: sys.stderr.write(str(e) + '\n') - sys.exit(1) + sys.exit(-1) if not possible_browser: sys.stderr.write( 'No browser found. Available browsers:\n' + '\n'.join(browser_finder.GetAllAvailableBrowserTypes(finder_options)) + '\n') - sys.exit(1) + sys.exit(-1) browser_options.browser_type = possible_browser.browser_type @@ -464,7 +458,8 @@ def _RunPage(test, page, state, expectation, results, finder_options): page_action.PageAction.ResetNextTimelineMarkerId() def ProcessError(): - logging.error('%s:\n%s', page.url, traceback.format_exc()) + logging.error('%s:', page.url) + exception_formatter.PrintFormattedException() if expectation == 'fail': logging.info('Error was expected\n') results.AddSuccess(page) @@ -482,11 +477,13 @@ def _RunPage(test, page, state, expectation, results, finder_options): raise except page_test.Failure: if expectation == 'fail': - logging.info('%s:\n%s', page.url, traceback.format_exc()) + logging.info('%s:', page.url) + exception_formatter.PrintFormattedException() logging.info('Failure was expected\n') results.AddSuccess(page) else: - logging.warning('%s:\n%s', page.url, traceback.format_exc()) + logging.warning('%s:', page.url) + exception_formatter.PrintFormattedException() results.AddFailure(page, sys.exc_info()) except (util.TimeoutException, exceptions.LoginException, exceptions.ProfilingException): @@ -497,7 +494,7 @@ def _RunPage(test, page, state, expectation, results, finder_options): raise except Exception: logging.warning('While running %s', page.url) - exception_formatter.PrintFormattedException(*sys.exc_info()) + exception_formatter.PrintFormattedException() results.AddFailure(page, sys.exc_info()) else: if expectation == 'fail': diff --git a/tools/telemetry/telemetry/util/exception_formatter.py b/tools/telemetry/telemetry/util/exception_formatter.py index e226067..4468b7f8 100644 --- a/tools/telemetry/telemetry/util/exception_formatter.py +++ b/tools/telemetry/telemetry/util/exception_formatter.py @@ -12,67 +12,84 @@ import traceback from telemetry.core import util -def PrintFormattedException(exception_class, exception, tb): +def PrintFormattedException(exception_class=None, exception=None, tb=None): + if not (bool(exception_class) == bool(exception) == bool(tb)): + raise ValueError('Must specify all or none of ' + 'exception_class, exception, and tb') + + if not exception_class: + exception_class, exception, tb = sys.exc_info() + + def _GetFinalFrame(tb_level): + while tb_level.tb_next: + tb_level = tb_level.tb_next + return tb_level.tb_frame + + processed_tb = traceback.extract_tb(tb) + frame = _GetFinalFrame(tb) + exception_list = traceback.format_exception_only(exception_class, exception) + exception_string = '\n'.join(l.strip() for l in exception_list) + _PrintFormattedTrace(processed_tb, frame, exception_string) + + +def PrintFormattedFrame(frame, exception_string=None): + _PrintFormattedTrace(traceback.extract_stack(frame), frame, exception_string) + + +def _PrintFormattedTrace(processed_tb, frame, exception_string=None): """Prints an Exception in a more useful format than the default. TODO(tonyg): Consider further enhancements. For instance: - Report stacks to maintainers like depot_tools does. - Add a debug flag to automatically start pdb upon exception. """ - def _GetFinalFrame(frame): - final_frame = None - while frame is not None: - final_frame = frame - frame = frame.tb_next - return final_frame - - def _AbbreviateMiddle(target, middle, length): - assert length >= 0, 'Must provide positive length' - assert len(middle) <= length, 'middle must not be greater than length' - if len(target) <= length: - return target - half_length = (length - len(middle)) / 2. - return '%s%s%s' % (target[:int(math.floor(half_length))], - middle, - target[-int(math.ceil(half_length)):]) - - base_dir = os.path.abspath(util.GetChromiumSrcDir()) - formatted_exception = traceback.format_exception( - exception_class, exception, tb) - extracted_tb = traceback.extract_tb(tb) - traceback_header = formatted_exception[0].strip() - exception = ''.join([l[2:] if l[:2] == ' ' else l for l in - traceback.format_exception_only(exception_class, - exception)]) - local_variables = [(variable, value) for variable, value in - _GetFinalFrame(tb).tb_frame.f_locals.iteritems() - if variable != 'self'] + print >> sys.stderr # Format the traceback. - print >> sys.stderr - print >> sys.stderr, traceback_header - for filename, line, function, text in extracted_tb: + base_dir = os.path.abspath(util.GetChromiumSrcDir()) + print >> sys.stderr, 'Traceback (most recent call last):' + for filename, line, function, text in processed_tb: filename = os.path.abspath(filename) if filename.startswith(base_dir): filename = filename[len(base_dir)+1:] print >> sys.stderr, ' %s at %s:%d' % (function, filename, line) print >> sys.stderr, ' %s' % text + # Format the exception. + if exception_string: + print >> sys.stderr, exception_string + # Format the locals. + local_variables = [(variable, value) for variable, value in + frame.f_locals.iteritems() if variable != 'self'] + print >> sys.stderr + print >> sys.stderr, 'Locals:' if local_variables: - print >> sys.stderr - print >> sys.stderr, 'Locals:' - longest_variable = max([len(v) for v, _ in local_variables]) + longest_variable = max(len(v) for v, _ in local_variables) for variable, value in sorted(local_variables): value = repr(value) - possibly_truncated_value = _AbbreviateMiddle(value, ' ... ', 1024) + possibly_truncated_value = _AbbreviateMiddleOfString(value, ' ... ', 1024) truncation_indication = '' if len(possibly_truncated_value) != len(value): truncation_indication = ' (truncated)' print >> sys.stderr, ' %s: %s%s' % (variable.ljust(longest_variable + 1), possibly_truncated_value, truncation_indication) + else: + print >> sys.stderr, ' No locals!' - # Format the exception. print >> sys.stderr - print >> sys.stderr, exception + sys.stderr.flush() + + +def _AbbreviateMiddleOfString(target, middle, max_length): + if max_length < 0: + raise ValueError('Must provide positive max_length') + if len(middle) > max_length: + raise ValueError('middle must not be greater than max_length') + + if len(target) <= max_length: + return target + half_length = (max_length - len(middle)) / 2. + return (target[:int(math.floor(half_length))] + middle + + target[-int(math.ceil(half_length)):]) diff --git a/tools/telemetry/telemetry/util/global_hooks.py b/tools/telemetry/telemetry/util/global_hooks.py index 50ed5b5..c7d5599 100644 --- a/tools/telemetry/telemetry/util/global_hooks.py +++ b/tools/telemetry/telemetry/util/global_hooks.py @@ -7,7 +7,6 @@ import os import signal import sys -import traceback from telemetry.core import util from telemetry.util import exception_formatter @@ -60,16 +59,15 @@ def InstallStackDumpOnSigusr1(): return def PrintDiagnostics(_, stack_frame): - print >> sys.stderr, 'SIGUSR1 received, printing stack trace:' - traceback.print_stack(stack_frame) + exception_string = 'SIGUSR1 received, printed stack trace' + exception_formatter.PrintFormattedFrame(stack_frame, exception_string) signal.signal(signal.SIGUSR1, PrintDiagnostics) def InstallTerminationHook(): """Catch SIGTERM, print a stack trace, and exit.""" def PrintStackAndExit(sig, stack_frame): - print >> sys.stderr, 'Traceback (most recent call last):' - traceback.print_stack(stack_frame) - print >> sys.stderr, 'Received signal %s, exiting' % sig + exception_string = 'Received signal %s, exiting' % sig + exception_formatter.PrintFormattedFrame(stack_frame, exception_string) sys.exit(-1) signal.signal(signal.SIGTERM, PrintStackAndExit) |