##// END OF EJS Templates
Added ability to invoke pdb on IPython crashes....
Fernando Perez -
Show More
@@ -1,220 +1,228 b''
1 1 # -*- coding: utf-8 -*-
2 2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3 3
4 4
5 5 Authors
6 6 -------
7 7 - Fernando Perez <Fernando.Perez@berkeley.edu>
8 8 """
9 9
10 10 #*****************************************************************************
11 11 # Copyright (C) 2008-2009 The IPython Development Team
12 12 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #*****************************************************************************
17 17
18 18 #****************************************************************************
19 19 # Required modules
20 20
21 21 # From the standard library
22 22 import os
23 23 import sys
24 24 from pprint import pformat
25 25
26 26 # Our own
27 27 from IPython.core import release
28 28 from IPython.core import ultratb
29 29 from IPython.external.Itpl import itpl
30 30
31 31 #****************************************************************************
32 32 class CrashHandler(object):
33 33 """Customizable crash handlers for IPython-based systems.
34 34
35 35 Instances of this class provide a __call__ method which can be used as a
36 36 sys.excepthook, i.e., the __call__ signature is:
37 37
38 38 def __call__(self,etype, evalue, etb)
39 39
40 40 """
41 41
42 42 def __init__(self,app, app_name, contact_name=None, contact_email=None,
43 43 bug_tracker=None, crash_report_fname='CrashReport.txt',
44 show_crash_traceback=True):
44 show_crash_traceback=True, call_pdb=False):
45 45 """New crash handler.
46 46
47 47 Inputs:
48 48
49 49 - app: a running application instance, which will be queried at crash
50 50 time for internal information.
51 51
52 52 - app_name: a string containing the name of your application.
53 53
54 54 - contact_name: a string with the name of the person to contact.
55 55
56 56 - contact_email: a string with the email address of the contact.
57 57
58 58 - bug_tracker: a string with the URL for your project's bug tracker.
59 59
60 60 - crash_report_fname: a string with the filename for the crash report
61 61 to be saved in. These reports are left in the ipython user directory
62 62 as determined by the running IPython instance.
63 63
64 64 Optional inputs:
65 65
66 66 - show_crash_traceback(True): if false, don't print the crash
67 67 traceback on stderr, only generate the on-disk report
68 68
69 69
70 70 Non-argument instance attributes:
71 71
72 72 These instances contain some non-argument attributes which allow for
73 73 further customization of the crash handler's behavior. Please see the
74 74 source for further details.
75 75 """
76 76
77 77 # apply args into instance
78 78 self.app = app
79 79 self.app_name = app_name
80 80 self.contact_name = contact_name
81 81 self.contact_email = contact_email
82 82 self.bug_tracker = bug_tracker
83 83 self.crash_report_fname = crash_report_fname
84 84 self.show_crash_traceback = show_crash_traceback
85 85 self.section_sep = '\n\n'+'*'*75+'\n\n'
86 self.call_pdb = call_pdb
87 #self.call_pdb = True # dbg
86 88
87 89 # Hardcoded defaults, which can be overridden either by subclasses or
88 90 # at runtime for the instance.
89 91
90 92 # Template for the user message. Subclasses which completely override
91 93 # this, or user apps, can modify it to suit their tastes. It gets
92 94 # expanded using itpl, so calls of the kind $self.foo are valid.
93 95 self.user_message_template = """
94 96 Oops, $self.app_name crashed. We do our best to make it stable, but...
95 97
96 98 A crash report was automatically generated with the following information:
97 99 - A verbatim copy of the crash traceback.
98 100 - A copy of your input history during this session.
99 101 - Data on your current $self.app_name configuration.
100 102
101 103 It was left in the file named:
102 104 \t'$self.crash_report_fname'
103 105 If you can email this file to the developers, the information in it will help
104 106 them in understanding and correcting the problem.
105 107
106 108 You can mail it to: $self.contact_name at $self.contact_email
107 109 with the subject '$self.app_name Crash Report'.
108 110
109 111 If you want to do it now, the following command will work (under Unix):
110 112 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
111 113
112 114 To ensure accurate tracking of this issue, please file a report about it at:
113 115 $self.bug_tracker
114 116 """
115 117
116 118 def __call__(self,etype, evalue, etb):
117 119 """Handle an exception, call for compatible with sys.excepthook"""
118 120
119 121 # Report tracebacks shouldn't use color in general (safer for users)
120 122 color_scheme = 'NoColor'
121 123
122 124 # Use this ONLY for developer debugging (keep commented out for release)
123 125 #color_scheme = 'Linux' # dbg
124 126
125 127 try:
126 128 rptdir = self.app.ipython_dir
127 129 except:
128 130 rptdir = os.getcwd()
129 131 if not os.path.isdir(rptdir):
130 132 rptdir = os.getcwd()
131 133 report_name = os.path.join(rptdir,self.crash_report_fname)
132 134 # write the report filename into the instance dict so it can get
133 135 # properly expanded out in the user message template
134 136 self.crash_report_fname = report_name
135 137 TBhandler = ultratb.VerboseTB(color_scheme=color_scheme,
136 long_header=1)
137 traceback = TBhandler.text(etype,evalue,etb,context=31)
138 long_header=1,
139 call_pdb=self.call_pdb,
140 )
141 if self.call_pdb:
142 TBhandler(etype,evalue,etb)
143 return
144 else:
145 traceback = TBhandler.text(etype,evalue,etb,context=31)
138 146
139 147 # print traceback to screen
140 148 if self.show_crash_traceback:
141 149 print >> sys.stderr, traceback
142 150
143 151 # and generate a complete report on disk
144 152 try:
145 153 report = open(report_name,'w')
146 154 except:
147 155 print >> sys.stderr, 'Could not create crash report on disk.'
148 156 return
149 157
150 158 # Inform user on stderr of what happened
151 159 msg = itpl('\n'+'*'*70+'\n'+self.user_message_template)
152 160 print >> sys.stderr, msg
153 161
154 162 # Construct report on disk
155 163 report.write(self.make_report(traceback))
156 164 report.close()
157 165 raw_input("Hit <Enter> to quit this message (your terminal may close):")
158 166
159 167 def make_report(self,traceback):
160 168 """Return a string containing a crash report."""
161 169 import platform
162 170
163 171 sec_sep = self.section_sep
164 172
165 173 report = []
166 174 rpt_add = report.append
167 175
168 176 rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n')
169 177 rpt_add('IPython version: %s \n' % release.version)
170 178 rpt_add('BZR revision : %s \n' % release.revision)
171 179 rpt_add('Platform info : os.name -> %s, sys.platform -> %s\n' %
172 180 (os.name,sys.platform) )
173 181 rpt_add(' : %s\n' % platform.platform())
174 182 rpt_add('Python info : %s\n' % sys.version)
175 183
176 184 try:
177 185 config = pformat(self.app.config)
178 186 rpt_add(sec_sep+'Current user configuration structure:\n\n')
179 187 rpt_add(config)
180 188 except:
181 189 pass
182 190 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
183 191
184 192 return ''.join(report)
185 193
186 194
187 195 class IPythonCrashHandler(CrashHandler):
188 196 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
189 197
190 198 def __init__(self, app, app_name='IPython'):
191 199
192 200 # Set here which of the IPython authors should be listed as contact
193 201 AUTHOR_CONTACT = 'Fernando'
194 202
195 203 # Set argument defaults
196 204 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
197 205 contact_name,contact_email = release.authors[AUTHOR_CONTACT][:2]
198 206 crash_report_fname = 'IPython_crash_report.txt'
199 207 # Call parent constructor
200 208 CrashHandler.__init__(self,app,app_name,contact_name,contact_email,
201 209 bug_tracker,crash_report_fname)
202 210
203 211 def make_report(self,traceback):
204 212 """Return a string containing a crash report."""
205 213
206 214 sec_sep = self.section_sep
207 215 # Start with parent report
208 216 report = [super(IPythonCrashHandler, self).make_report(traceback)]
209 217 # Add interactive-specific info we may have
210 218 rpt_add = report.append
211 219 try:
212 220 rpt_add(sec_sep+"History of session input:")
213 221 for line in self.app.shell.user_ns['_ih']:
214 222 rpt_add(line)
215 223 rpt_add('\n*** Last line of input (may not be in above history):\n')
216 224 rpt_add(self.app.shell._last_input_line+'\n')
217 225 except:
218 226 pass
219 227
220 228 return ''.join(report)
General Comments 0
You need to be logged in to leave comments. Login now