summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/telemetry/telemetry/core/web_contents.py4
-rw-r--r--tools/telemetry/telemetry/page/page_runner.py23
-rw-r--r--tools/telemetry/telemetry/util/exception_formatter.py93
-rw-r--r--tools/telemetry/telemetry/util/global_hooks.py10
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)