OLD | NEW |
| (Empty) |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 """Print prettier and more detailed exceptions.""" | |
6 | |
7 import math | |
8 import os | |
9 import sys | |
10 import traceback | |
11 | |
12 from telemetry.core import util | |
13 | |
14 | |
15 def InstallUnhandledExceptionFormatter(): | |
16 sys.excepthook = PrintFormattedException | |
17 | |
18 | |
19 def PrintFormattedException(exception_class, exception, tb): | |
20 """Prints an Exception in a more useful format than the default. | |
21 | |
22 TODO(tonyg): Consider further enhancements. For instance: | |
23 - Report stacks to maintainers like depot_tools does. | |
24 - Add a debug flag to automatically start pdb upon exception. | |
25 """ | |
26 def _GetFinalFrame(frame): | |
27 final_frame = None | |
28 while frame is not None: | |
29 final_frame = frame | |
30 frame = frame.tb_next | |
31 return final_frame | |
32 | |
33 def _AbbreviateMiddle(target, middle, length): | |
34 assert length >= 0, 'Must provide positive length' | |
35 assert len(middle) <= length, 'middle must not be greater than length' | |
36 if len(target) <= length: | |
37 return target | |
38 half_length = (length - len(middle)) / 2. | |
39 return '%s%s%s' % (target[:int(math.floor(half_length))], | |
40 middle, | |
41 target[-int(math.ceil(half_length)):]) | |
42 | |
43 base_dir = os.path.abspath(util.GetChromiumSrcDir()) | |
44 formatted_exception = traceback.format_exception( | |
45 exception_class, exception, tb) | |
46 extracted_tb = traceback.extract_tb(tb) | |
47 traceback_header = formatted_exception[0].strip() | |
48 exception = ''.join([l[2:] if l[:2] == ' ' else l for l in | |
49 traceback.format_exception_only(exception_class, | |
50 exception)]) | |
51 local_variables = [(variable, value) for variable, value in | |
52 _GetFinalFrame(tb).tb_frame.f_locals.iteritems() | |
53 if variable != 'self'] | |
54 | |
55 # Format the traceback. | |
56 print >> sys.stderr | |
57 print >> sys.stderr, traceback_header | |
58 for filename, line, function, text in extracted_tb: | |
59 filename = os.path.abspath(filename) | |
60 if filename.startswith(base_dir): | |
61 filename = filename[len(base_dir)+1:] | |
62 print >> sys.stderr, ' %s at %s:%d' % (function, filename, line) | |
63 print >> sys.stderr, ' %s' % text | |
64 | |
65 # Format the locals. | |
66 if local_variables: | |
67 print >> sys.stderr | |
68 print >> sys.stderr, 'Locals:' | |
69 longest_variable = max([len(v) for v, _ in local_variables]) | |
70 for variable, value in sorted(local_variables): | |
71 value = repr(value) | |
72 possibly_truncated_value = _AbbreviateMiddle(value, ' ... ', 1024) | |
73 truncation_indication = '' | |
74 if len(possibly_truncated_value) != len(value): | |
75 truncation_indication = ' (truncated)' | |
76 print >> sys.stderr, ' %s: %s%s' % (variable.ljust(longest_variable + 1), | |
77 possibly_truncated_value, | |
78 truncation_indication) | |
79 | |
80 # Format the exception. | |
81 print >> sys.stderr | |
82 print >> sys.stderr, exception | |
OLD | NEW |