##// END OF EJS Templates
unregister crash handler on call...
MinRK -
Show More
@@ -1,181 +1,186 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-2010 The IPython Development Team
12 # Copyright (C) 2008-2010 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 from pprint import pformat
24 from pprint import pformat
25
25
26 from IPython.core import ultratb
26 from IPython.core import ultratb
27 from IPython.utils.sysinfo import sys_info
27 from IPython.utils.sysinfo import sys_info
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Code
30 # Code
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 # Template for the user message.
33 # Template for the user message.
34 _default_message_template = """\
34 _default_message_template = """\
35 Oops, {app_name} crashed. We do our best to make it stable, but...
35 Oops, {app_name} crashed. We do our best to make it stable, but...
36
36
37 A crash report was automatically generated with the following information:
37 A crash report was automatically generated with the following information:
38 - A verbatim copy of the crash traceback.
38 - A verbatim copy of the crash traceback.
39 - A copy of your input history during this session.
39 - A copy of your input history during this session.
40 - Data on your current {app_name} configuration.
40 - Data on your current {app_name} configuration.
41
41
42 It was left in the file named:
42 It was left in the file named:
43 \t'{crash_report_fname}'
43 \t'{crash_report_fname}'
44 If you can email this file to the developers, the information in it will help
44 If you can email this file to the developers, the information in it will help
45 them in understanding and correcting the problem.
45 them in understanding and correcting the problem.
46
46
47 You can mail it to: {contact_name} at {contact_email}
47 You can mail it to: {contact_name} at {contact_email}
48 with the subject '{app_name} Crash Report'.
48 with the subject '{app_name} Crash Report'.
49
49
50 If you want to do it now, the following command will work (under Unix):
50 If you want to do it now, the following command will work (under Unix):
51 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
51 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
52
52
53 To ensure accurate tracking of this issue, please file a report about it at:
53 To ensure accurate tracking of this issue, please file a report about it at:
54 {bug_tracker}
54 {bug_tracker}
55 """
55 """
56
56
57
57
58 class CrashHandler(object):
58 class CrashHandler(object):
59 """Customizable crash handlers for IPython applications.
59 """Customizable crash handlers for IPython applications.
60
60
61 Instances of this class provide a :meth:`__call__` method which can be
61 Instances of this class provide a :meth:`__call__` method which can be
62 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
62 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
63
63
64 def __call__(self, etype, evalue, etb)
64 def __call__(self, etype, evalue, etb)
65 """
65 """
66
66
67 message_template = _default_message_template
67 message_template = _default_message_template
68 section_sep = '\n\n'+'*'*75+'\n\n'
68 section_sep = '\n\n'+'*'*75+'\n\n'
69
69
70 def __init__(self, app, contact_name=None, contact_email=None,
70 def __init__(self, app, contact_name=None, contact_email=None,
71 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
71 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
72 """Create a new crash handler
72 """Create a new crash handler
73
73
74 Parameters
74 Parameters
75 ----------
75 ----------
76 app : Application
76 app : Application
77 A running :class:`Application` instance, which will be queried at
77 A running :class:`Application` instance, which will be queried at
78 crash time for internal information.
78 crash time for internal information.
79
79
80 contact_name : str
80 contact_name : str
81 A string with the name of the person to contact.
81 A string with the name of the person to contact.
82
82
83 contact_email : str
83 contact_email : str
84 A string with the email address of the contact.
84 A string with the email address of the contact.
85
85
86 bug_tracker : str
86 bug_tracker : str
87 A string with the URL for your project's bug tracker.
87 A string with the URL for your project's bug tracker.
88
88
89 show_crash_traceback : bool
89 show_crash_traceback : bool
90 If false, don't print the crash traceback on stderr, only generate
90 If false, don't print the crash traceback on stderr, only generate
91 the on-disk report
91 the on-disk report
92
92
93 Non-argument instance attributes:
93 Non-argument instance attributes:
94
94
95 These instances contain some non-argument attributes which allow for
95 These instances contain some non-argument attributes which allow for
96 further customization of the crash handler's behavior. Please see the
96 further customization of the crash handler's behavior. Please see the
97 source for further details.
97 source for further details.
98 """
98 """
99 self.crash_report_fname = "Crash_report_%s.txt" % app.name
99 self.crash_report_fname = "Crash_report_%s.txt" % app.name
100 self.app = app
100 self.app = app
101 self.call_pdb = call_pdb
101 self.call_pdb = call_pdb
102 #self.call_pdb = True # dbg
102 #self.call_pdb = True # dbg
103 self.show_crash_traceback = show_crash_traceback
103 self.show_crash_traceback = show_crash_traceback
104 self.info = dict(app_name = app.name,
104 self.info = dict(app_name = app.name,
105 contact_name = contact_name,
105 contact_name = contact_name,
106 contact_email = contact_email,
106 contact_email = contact_email,
107 bug_tracker = bug_tracker,
107 bug_tracker = bug_tracker,
108 crash_report_fname = self.crash_report_fname)
108 crash_report_fname = self.crash_report_fname)
109
109
110
110
111 def __call__(self, etype, evalue, etb):
111 def __call__(self, etype, evalue, etb):
112 """Handle an exception, call for compatible with sys.excepthook"""
112 """Handle an exception, call for compatible with sys.excepthook"""
113
113
114 # do not allow the crash handler to be called twice without reinstalling it
115 # this prevents unlikely errors in the crash handling from entering an
116 # infinite loop.
117 sys.excepthook = sys.__excepthook__
118
114 # Report tracebacks shouldn't use color in general (safer for users)
119 # Report tracebacks shouldn't use color in general (safer for users)
115 color_scheme = 'NoColor'
120 color_scheme = 'NoColor'
116
121
117 # Use this ONLY for developer debugging (keep commented out for release)
122 # Use this ONLY for developer debugging (keep commented out for release)
118 #color_scheme = 'Linux' # dbg
123 #color_scheme = 'Linux' # dbg
119 try:
124 try:
120 rptdir = self.app.ipython_dir
125 rptdir = self.app.ipython_dir
121 except:
126 except:
122 rptdir = os.getcwdu()
127 rptdir = os.getcwdu()
123 if rptdir is None or not os.path.isdir(rptdir):
128 if rptdir is None or not os.path.isdir(rptdir):
124 rptdir = os.getcwdu()
129 rptdir = os.getcwdu()
125 report_name = os.path.join(rptdir,self.crash_report_fname)
130 report_name = os.path.join(rptdir,self.crash_report_fname)
126 # write the report filename into the instance dict so it can get
131 # write the report filename into the instance dict so it can get
127 # properly expanded out in the user message template
132 # properly expanded out in the user message template
128 self.crash_report_fname = report_name
133 self.crash_report_fname = report_name
129 self.info['crash_report_fname'] = report_name
134 self.info['crash_report_fname'] = report_name
130 TBhandler = ultratb.VerboseTB(
135 TBhandler = ultratb.VerboseTB(
131 color_scheme=color_scheme,
136 color_scheme=color_scheme,
132 long_header=1,
137 long_header=1,
133 call_pdb=self.call_pdb,
138 call_pdb=self.call_pdb,
134 )
139 )
135 if self.call_pdb:
140 if self.call_pdb:
136 TBhandler(etype,evalue,etb)
141 TBhandler(etype,evalue,etb)
137 return
142 return
138 else:
143 else:
139 traceback = TBhandler.text(etype,evalue,etb,context=31)
144 traceback = TBhandler.text(etype,evalue,etb,context=31)
140
145
141 # print traceback to screen
146 # print traceback to screen
142 if self.show_crash_traceback:
147 if self.show_crash_traceback:
143 print >> sys.stderr, traceback
148 print >> sys.stderr, traceback
144
149
145 # and generate a complete report on disk
150 # and generate a complete report on disk
146 try:
151 try:
147 report = open(report_name,'w')
152 report = open(report_name,'w')
148 except:
153 except:
149 print >> sys.stderr, 'Could not create crash report on disk.'
154 print >> sys.stderr, 'Could not create crash report on disk.'
150 return
155 return
151
156
152 # Inform user on stderr of what happened
157 # Inform user on stderr of what happened
153 print >> sys.stderr, '\n'+'*'*70+'\n'
158 print >> sys.stderr, '\n'+'*'*70+'\n'
154 print >> sys.stderr, self.message_template.format(**self.info)
159 print >> sys.stderr, self.message_template.format(**self.info)
155
160
156 # Construct report on disk
161 # Construct report on disk
157 report.write(self.make_report(traceback))
162 report.write(self.make_report(traceback))
158 report.close()
163 report.close()
159 raw_input("Hit <Enter> to quit this message (your terminal may close):")
164 raw_input("Hit <Enter> to quit this message (your terminal may close):")
160
165
161 def make_report(self,traceback):
166 def make_report(self,traceback):
162 """Return a string containing a crash report."""
167 """Return a string containing a crash report."""
163
168
164 sec_sep = self.section_sep
169 sec_sep = self.section_sep
165
170
166 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
171 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
167 rpt_add = report.append
172 rpt_add = report.append
168 rpt_add(sys_info())
173 rpt_add(sys_info())
169
174
170 try:
175 try:
171 config = pformat(self.app.config)
176 config = pformat(self.app.config)
172 rpt_add(sec_sep)
177 rpt_add(sec_sep)
173 rpt_add('Application name: %s\n\n' % self.app_name)
178 rpt_add('Application name: %s\n\n' % self.app_name)
174 rpt_add('Current user configuration structure:\n\n')
179 rpt_add('Current user configuration structure:\n\n')
175 rpt_add(config)
180 rpt_add(config)
176 except:
181 except:
177 pass
182 pass
178 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
183 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
179
184
180 return ''.join(report)
185 return ''.join(report)
181
186
General Comments 0
You need to be logged in to leave comments. Login now