##// END OF EJS Templates
Improve instructions on reporting crash...
Samuel Lelièvre -
Show More
@@ -1,218 +1,225 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez
6 * Fernando Perez
7 * Brian E. Granger
7 * Brian E. Granger
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import os
22 import os
23 import sys
23 import sys
24 import traceback
24 import traceback
25 from pprint import pformat
25 from pprint import pformat
26
26
27 from IPython.core import ultratb
27 from IPython.core import ultratb
28 from IPython.core.release import author_email
28 from IPython.core.release import author_email
29 from IPython.utils.sysinfo import sys_info
29 from IPython.utils.sysinfo import sys_info
30 from IPython.utils.py3compat import input
30 from IPython.utils.py3compat import input
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Code
33 # Code
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36 # Template for the user message.
36 # Template for the user message.
37 _default_message_template = """\
37 _default_message_template = """\
38 Oops, {app_name} crashed. We do our best to make it stable, but...
38 Oops, {app_name} crashed. We do our best to make it stable, but...
39
39
40 A crash report was automatically generated with the following information:
40 A crash report was automatically generated with the following information:
41 - A verbatim copy of the crash traceback.
41 - A verbatim copy of the crash traceback.
42 - A copy of your input history during this session.
42 - A copy of your input history during this session.
43 - Data on your current {app_name} configuration.
43 - Data on your current {app_name} configuration.
44
44
45 It was left in the file named:
45 It was left in the file named:
46 \t'{crash_report_fname}'
46 \t'{crash_report_fname}'
47 If you can email this file to the developers, the information in it will help
47 If you can email this file to the developers, the information in it will help
48 them in understanding and correcting the problem. Please include information
48 them in understanding and correcting the problem.
49 about your operating system: is it Linux, macOS, Windows, other, and which
50 version, for example Ubuntu 16.04, macOS 10.13.2, Windows 10 Pro 64-bit...
51 Please also include information on how you installed {app_name}.
52
49
53 You can mail it to: {contact_name} at {contact_email}
50 You can mail it to: {contact_name} at {contact_email}
54 with the subject '{app_name} Crash Report'.
51 with the subject '{app_name} Crash Report'.
55
52
56 If you want to do it now, the following command will work (under Unix):
53 If you want to do it now, the following command will work (under Unix):
57 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
54 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
58
55
56 Please also include in your email:
57 - information about your operating system: is it Linux, macOS, Windows, other,
58 and which version, for example Ubuntu 16.04, macOS 10.13.2, Windows 10 Pro,
59 is it 32-bit or 64-bit, ...
60 - information on how you installed {app_name}: from binary, compiled from source,
61 via Docker, on a virtual machine...
62 - information on how to reproduce the crash: what exact sequence of instructions
63 can one input to get the same crash? Ideally, find a minimal yet complete
64 sequence of instructions that yields the crash.
65
59 To ensure accurate tracking of this issue, please file a report about it at:
66 To ensure accurate tracking of this issue, please file a report about it at:
60 {bug_tracker}
67 {bug_tracker}
61 """
68 """
62
69
63 _lite_message_template = """
70 _lite_message_template = """
64 If you suspect this is an IPython bug, please report it at:
71 If you suspect this is an IPython bug, please report it at:
65 https://github.com/ipython/ipython/issues
72 https://github.com/ipython/ipython/issues
66 or send an email to the mailing list at {email}
73 or send an email to the mailing list at {email}
67
74
68 You can print a more detailed traceback right now with "%tb", or use "%debug"
75 You can print a more detailed traceback right now with "%tb", or use "%debug"
69 to interactively debug it.
76 to interactively debug it.
70
77
71 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
78 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
72 {config}Application.verbose_crash=True
79 {config}Application.verbose_crash=True
73 """
80 """
74
81
75
82
76 class CrashHandler(object):
83 class CrashHandler(object):
77 """Customizable crash handlers for IPython applications.
84 """Customizable crash handlers for IPython applications.
78
85
79 Instances of this class provide a :meth:`__call__` method which can be
86 Instances of this class provide a :meth:`__call__` method which can be
80 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
87 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
81
88
82 def __call__(self, etype, evalue, etb)
89 def __call__(self, etype, evalue, etb)
83 """
90 """
84
91
85 message_template = _default_message_template
92 message_template = _default_message_template
86 section_sep = '\n\n'+'*'*75+'\n\n'
93 section_sep = '\n\n'+'*'*75+'\n\n'
87
94
88 def __init__(self, app, contact_name=None, contact_email=None,
95 def __init__(self, app, contact_name=None, contact_email=None,
89 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
96 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
90 """Create a new crash handler
97 """Create a new crash handler
91
98
92 Parameters
99 Parameters
93 ----------
100 ----------
94 app : Application
101 app : Application
95 A running :class:`Application` instance, which will be queried at
102 A running :class:`Application` instance, which will be queried at
96 crash time for internal information.
103 crash time for internal information.
97
104
98 contact_name : str
105 contact_name : str
99 A string with the name of the person to contact.
106 A string with the name of the person to contact.
100
107
101 contact_email : str
108 contact_email : str
102 A string with the email address of the contact.
109 A string with the email address of the contact.
103
110
104 bug_tracker : str
111 bug_tracker : str
105 A string with the URL for your project's bug tracker.
112 A string with the URL for your project's bug tracker.
106
113
107 show_crash_traceback : bool
114 show_crash_traceback : bool
108 If false, don't print the crash traceback on stderr, only generate
115 If false, don't print the crash traceback on stderr, only generate
109 the on-disk report
116 the on-disk report
110
117
111 Non-argument instance attributes:
118 Non-argument instance attributes:
112
119
113 These instances contain some non-argument attributes which allow for
120 These instances contain some non-argument attributes which allow for
114 further customization of the crash handler's behavior. Please see the
121 further customization of the crash handler's behavior. Please see the
115 source for further details.
122 source for further details.
116 """
123 """
117 self.crash_report_fname = "Crash_report_%s.txt" % app.name
124 self.crash_report_fname = "Crash_report_%s.txt" % app.name
118 self.app = app
125 self.app = app
119 self.call_pdb = call_pdb
126 self.call_pdb = call_pdb
120 #self.call_pdb = True # dbg
127 #self.call_pdb = True # dbg
121 self.show_crash_traceback = show_crash_traceback
128 self.show_crash_traceback = show_crash_traceback
122 self.info = dict(app_name = app.name,
129 self.info = dict(app_name = app.name,
123 contact_name = contact_name,
130 contact_name = contact_name,
124 contact_email = contact_email,
131 contact_email = contact_email,
125 bug_tracker = bug_tracker,
132 bug_tracker = bug_tracker,
126 crash_report_fname = self.crash_report_fname)
133 crash_report_fname = self.crash_report_fname)
127
134
128
135
129 def __call__(self, etype, evalue, etb):
136 def __call__(self, etype, evalue, etb):
130 """Handle an exception, call for compatible with sys.excepthook"""
137 """Handle an exception, call for compatible with sys.excepthook"""
131
138
132 # do not allow the crash handler to be called twice without reinstalling it
139 # do not allow the crash handler to be called twice without reinstalling it
133 # this prevents unlikely errors in the crash handling from entering an
140 # this prevents unlikely errors in the crash handling from entering an
134 # infinite loop.
141 # infinite loop.
135 sys.excepthook = sys.__excepthook__
142 sys.excepthook = sys.__excepthook__
136
143
137 # Report tracebacks shouldn't use color in general (safer for users)
144 # Report tracebacks shouldn't use color in general (safer for users)
138 color_scheme = 'NoColor'
145 color_scheme = 'NoColor'
139
146
140 # Use this ONLY for developer debugging (keep commented out for release)
147 # Use this ONLY for developer debugging (keep commented out for release)
141 #color_scheme = 'Linux' # dbg
148 #color_scheme = 'Linux' # dbg
142 try:
149 try:
143 rptdir = self.app.ipython_dir
150 rptdir = self.app.ipython_dir
144 except:
151 except:
145 rptdir = os.getcwd()
152 rptdir = os.getcwd()
146 if rptdir is None or not os.path.isdir(rptdir):
153 if rptdir is None or not os.path.isdir(rptdir):
147 rptdir = os.getcwd()
154 rptdir = os.getcwd()
148 report_name = os.path.join(rptdir,self.crash_report_fname)
155 report_name = os.path.join(rptdir,self.crash_report_fname)
149 # write the report filename into the instance dict so it can get
156 # write the report filename into the instance dict so it can get
150 # properly expanded out in the user message template
157 # properly expanded out in the user message template
151 self.crash_report_fname = report_name
158 self.crash_report_fname = report_name
152 self.info['crash_report_fname'] = report_name
159 self.info['crash_report_fname'] = report_name
153 TBhandler = ultratb.VerboseTB(
160 TBhandler = ultratb.VerboseTB(
154 color_scheme=color_scheme,
161 color_scheme=color_scheme,
155 long_header=1,
162 long_header=1,
156 call_pdb=self.call_pdb,
163 call_pdb=self.call_pdb,
157 )
164 )
158 if self.call_pdb:
165 if self.call_pdb:
159 TBhandler(etype,evalue,etb)
166 TBhandler(etype,evalue,etb)
160 return
167 return
161 else:
168 else:
162 traceback = TBhandler.text(etype,evalue,etb,context=31)
169 traceback = TBhandler.text(etype,evalue,etb,context=31)
163
170
164 # print traceback to screen
171 # print traceback to screen
165 if self.show_crash_traceback:
172 if self.show_crash_traceback:
166 print(traceback, file=sys.stderr)
173 print(traceback, file=sys.stderr)
167
174
168 # and generate a complete report on disk
175 # and generate a complete report on disk
169 try:
176 try:
170 report = open(report_name,'w')
177 report = open(report_name,'w')
171 except:
178 except:
172 print('Could not create crash report on disk.', file=sys.stderr)
179 print('Could not create crash report on disk.', file=sys.stderr)
173 return
180 return
174
181
175 # Inform user on stderr of what happened
182 # Inform user on stderr of what happened
176 print('\n'+'*'*70+'\n', file=sys.stderr)
183 print('\n'+'*'*70+'\n', file=sys.stderr)
177 print(self.message_template.format(**self.info), file=sys.stderr)
184 print(self.message_template.format(**self.info), file=sys.stderr)
178
185
179 # Construct report on disk
186 # Construct report on disk
180 report.write(self.make_report(traceback))
187 report.write(self.make_report(traceback))
181 report.close()
188 report.close()
182 input("Hit <Enter> to quit (your terminal may close):")
189 input("Hit <Enter> to quit (your terminal may close):")
183
190
184 def make_report(self,traceback):
191 def make_report(self,traceback):
185 """Return a string containing a crash report."""
192 """Return a string containing a crash report."""
186
193
187 sec_sep = self.section_sep
194 sec_sep = self.section_sep
188
195
189 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
196 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
190 rpt_add = report.append
197 rpt_add = report.append
191 rpt_add(sys_info())
198 rpt_add(sys_info())
192
199
193 try:
200 try:
194 config = pformat(self.app.config)
201 config = pformat(self.app.config)
195 rpt_add(sec_sep)
202 rpt_add(sec_sep)
196 rpt_add('Application name: %s\n\n' % self.app_name)
203 rpt_add('Application name: %s\n\n' % self.app_name)
197 rpt_add('Current user configuration structure:\n\n')
204 rpt_add('Current user configuration structure:\n\n')
198 rpt_add(config)
205 rpt_add(config)
199 except:
206 except:
200 pass
207 pass
201 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
208 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
202
209
203 return ''.join(report)
210 return ''.join(report)
204
211
205
212
206 def crash_handler_lite(etype, evalue, tb):
213 def crash_handler_lite(etype, evalue, tb):
207 """a light excepthook, adding a small message to the usual traceback"""
214 """a light excepthook, adding a small message to the usual traceback"""
208 traceback.print_exception(etype, evalue, tb)
215 traceback.print_exception(etype, evalue, tb)
209
216
210 from IPython.core.interactiveshell import InteractiveShell
217 from IPython.core.interactiveshell import InteractiveShell
211 if InteractiveShell.initialized():
218 if InteractiveShell.initialized():
212 # we are in a Shell environment, give %magic example
219 # we are in a Shell environment, give %magic example
213 config = "%config "
220 config = "%config "
214 else:
221 else:
215 # we are not in a shell, show generic config
222 # we are not in a shell, show generic config
216 config = "c."
223 config = "c."
217 print(_lite_message_template.format(email=author_email, config=config), file=sys.stderr)
224 print(_lite_message_template.format(email=author_email, config=config), file=sys.stderr)
218
225
General Comments 0
You need to be logged in to leave comments. Login now