##// END OF EJS Templates
More work on the crash handler....
Brian Granger -
Show More
@@ -119,14 +119,13 b' class Application(object):'
119 119 argv = None
120 120 #: extra arguments computed by the command-line loader
121 121 extra_args = None
122 #: The class to use as the crash handler.
123 crash_handler_class = crashhandler.CrashHandler
122 124
123 125 # Private attributes
124 126 _exiting = False
125 127 _initialized = False
126 128
127 # Class choices for things that will be instantiated at runtime.
128 _CrashHandler = crashhandler.CrashHandler
129
130 129 def __init__(self, argv=None):
131 130 self.argv = sys.argv[1:] if argv is None else argv
132 131 self.init_logger()
@@ -217,7 +216,7 b' class Application(object):'
217 216
218 217 def create_crash_handler(self):
219 218 """Create a crash handler, typically setting sys.excepthook to it."""
220 self.crash_handler = self._CrashHandler(self, self.name)
219 self.crash_handler = self.crash_handler_class(self)
221 220 sys.excepthook = self.crash_handler
222 221
223 222 def create_default_config(self):
@@ -430,15 +429,6 b' class Application(object):'
430 429 # Utility methods
431 430 #-------------------------------------------------------------------------
432 431
433 def abort(self):
434 """Abort the starting of the application."""
435 if self._exiting:
436 pass
437 else:
438 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
439 self._exiting = True
440 sys.exit(1)
441
442 432 def exit(self, exit_status=0):
443 433 if self._exiting:
444 434 pass
@@ -447,17 +437,13 b' class Application(object):'
447 437 self._exiting = True
448 438 sys.exit(exit_status)
449 439
450 def attempt(self, func, action='abort'):
440 def attempt(self, func):
451 441 try:
452 442 func()
453 443 except SystemExit:
454 444 raise
455 445 except:
456 if action == 'abort':
457 self.log.critical("Aborting application: %s" % self.name,
458 exc_info=True)
459 self.abort()
460 raise
461 elif action == 'exit':
462 self.exit(0)
446 self.log.critical("Aborting application: %s" % self.name,
447 exc_info=True)
448 self.exit(0)
463 449
@@ -1,124 +1,113 b''
1 # -*- coding: utf-8 -*-
1 # encoding: utf-8
2 2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3 3
4 Authors:
4 5
5 Authors
6 -------
7 - Fernando Perez <Fernando.Perez@berkeley.edu>
6 * Fernando Perez
7 * Brian E. Granger
8 8 """
9 9
10 #*****************************************************************************
11 # Copyright (C) 2008-2009 The IPython Development Team
12 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
12 # Copyright (C) 2008-2010 The IPython Development Team
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 #****************************************************************************
19 # Required modules
18 #-----------------------------------------------------------------------------
19 # Imports
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 # Our own
27 from IPython.core import release
28 26 from IPython.core import ultratb
27 from IPython.external.Itpl import itpl
29 28 from IPython.utils.sysinfo import sys_info
30 29
31 from IPython.external.Itpl import itpl
30 #-----------------------------------------------------------------------------
31 # Code
32 #-----------------------------------------------------------------------------
32 33
33 #****************************************************************************
34 # Template for the user message.
35 _default_message_template = """\
36 Oops, $self.app_name crashed. We do our best to make it stable, but...
34 37
35 class CrashHandler(object):
36 """Customizable crash handlers for IPython-based systems.
38 A crash report was automatically generated with the following information:
39 - A verbatim copy of the crash traceback.
40 - A copy of your input history during this session.
41 - Data on your current $self.app_name configuration.
37 42
38 Instances of this class provide a __call__ method which can be used as a
39 sys.excepthook, i.e., the __call__ signature is:
43 It was left in the file named:
44 \t'$self.crash_report_fname'
45 If you can email this file to the developers, the information in it will help
46 them in understanding and correcting the problem.
40 47
41 def __call__(self,etype, evalue, etb)
48 You can mail it to: $self.contact_name at $self.contact_email
49 with the subject '$self.app_name Crash Report'.
42 50
43 """
51 If you want to do it now, the following command will work (under Unix):
52 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
53
54 To ensure accurate tracking of this issue, please file a report about it at:
55 $self.bug_tracker
56 """
44 57
45 def __init__(self,app, app_name, contact_name=None, contact_email=None,
46 bug_tracker=None, crash_report_fname='CrashReport.txt',
47 show_crash_traceback=True, call_pdb=False):
48 """New crash handler.
49 58
50 Inputs:
59 class CrashHandler(object):
60 """Customizable crash handlers for IPython applications.
51 61
52 - app: a running application instance, which will be queried at crash
53 time for internal information.
62 Instances of this class provide a :meth:`__call__` method which can be
63 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
54 64
55 - app_name: a string containing the name of your application.
65 def __call__(self, etype, evalue, etb)
66 """
56 67
57 - contact_name: a string with the name of the person to contact.
68 message_template = _default_message_template
58 69
59 - contact_email: a string with the email address of the contact.
70 def __init__(self, app, contact_name=None, contact_email=None,
71 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
72 """Create a new crash handler
60 73
61 - bug_tracker: a string with the URL for your project's bug tracker.
74 Parameters
75 ----------
76 app : Application
77 A running :class:`Application` instance, which will be queried at
78 crash time for internal information.
62 79
63 - crash_report_fname: a string with the filename for the crash report
64 to be saved in. These reports are left in the ipython user directory
65 as determined by the running IPython instance.
80 contact_name : str
81 A string with the name of the person to contact.
66 82
67 Optional inputs:
68
69 - show_crash_traceback(True): if false, don't print the crash
70 traceback on stderr, only generate the on-disk report
83 contact_email : str
84 A string with the email address of the contact.
71 85
86 bug_tracker : str
87 A string with the URL for your project's bug tracker.
88
89 show_crash_traceback : bool
90 If false, don't print the crash traceback on stderr, only generate
91 the on-disk report
72 92
73 93 Non-argument instance attributes:
74 94
75 These instances contain some non-argument attributes which allow for
76 further customization of the crash handler's behavior. Please see the
95 These instances contain some non-argument attributes which allow for
96 further customization of the crash handler's behavior. Please see the
77 97 source for further details.
78 98 """
79
80 # apply args into instance
81 99 self.app = app
82 self.app_name = app_name
100 self.app_name = self.app.name
83 101 self.contact_name = contact_name
84 102 self.contact_email = contact_email
85 103 self.bug_tracker = bug_tracker
86 self.crash_report_fname = crash_report_fname
104 self.crash_report_fname = "Crash_report_%s.txt" % self.app_name
87 105 self.show_crash_traceback = show_crash_traceback
88 106 self.section_sep = '\n\n'+'*'*75+'\n\n'
89 107 self.call_pdb = call_pdb
90 108 #self.call_pdb = True # dbg
91
92 # Hardcoded defaults, which can be overridden either by subclasses or
93 # at runtime for the instance.
94
95 # Template for the user message. Subclasses which completely override
96 # this, or user apps, can modify it to suit their tastes. It gets
97 # expanded using itpl, so calls of the kind $self.foo are valid.
98 self.user_message_template = """
99 Oops, $self.app_name crashed. We do our best to make it stable, but...
100
101 A crash report was automatically generated with the following information:
102 - A verbatim copy of the crash traceback.
103 - A copy of your input history during this session.
104 - Data on your current $self.app_name configuration.
105
106 It was left in the file named:
107 \t'$self.crash_report_fname'
108 If you can email this file to the developers, the information in it will help
109 them in understanding and correcting the problem.
110
111 You can mail it to: $self.contact_name at $self.contact_email
112 with the subject '$self.app_name Crash Report'.
113
114 If you want to do it now, the following command will work (under Unix):
115 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
116
117 To ensure accurate tracking of this issue, please file a report about it at:
118 $self.bug_tracker
119 """
120 109
121 def __call__(self,etype, evalue, etb):
110 def __call__(self, etype, evalue, etb):
122 111 """Handle an exception, call for compatible with sys.excepthook"""
123 112
124 113 # Report tracebacks shouldn't use color in general (safer for users)
@@ -137,10 +126,11 b' $self.bug_tracker'
137 126 # write the report filename into the instance dict so it can get
138 127 # properly expanded out in the user message template
139 128 self.crash_report_fname = report_name
140 TBhandler = ultratb.VerboseTB(color_scheme=color_scheme,
141 long_header=1,
142 call_pdb=self.call_pdb,
143 )
129 TBhandler = ultratb.VerboseTB(
130 color_scheme=color_scheme,
131 long_header=1,
132 call_pdb=self.call_pdb,
133 )
144 134 if self.call_pdb:
145 135 TBhandler(etype,evalue,etb)
146 136 return
@@ -159,7 +149,7 b' $self.bug_tracker'
159 149 return
160 150
161 151 # Inform user on stderr of what happened
162 msg = itpl('\n'+'*'*70+'\n'+self.user_message_template)
152 msg = itpl('\n'+'*'*70+'\n'+self.message_template)
163 153 print >> sys.stderr, msg
164 154
165 155 # Construct report on disk
@@ -178,7 +168,9 b' $self.bug_tracker'
178 168
179 169 try:
180 170 config = pformat(self.app.config)
181 rpt_add(sec_sep+'Current user configuration structure:\n\n')
171 rpt_add(sec_sep)
172 rpt_add('Application name: %s\n\n' % self.app_name)
173 rpt_add('Current user configuration structure:\n\n')
182 174 rpt_add(config)
183 175 except:
184 176 pass
@@ -186,39 +178,3 b' $self.bug_tracker'
186 178
187 179 return ''.join(report)
188 180
189
190 class IPythonCrashHandler(CrashHandler):
191 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
192
193 def __init__(self, app, app_name='IPython'):
194
195 # Set here which of the IPython authors should be listed as contact
196 AUTHOR_CONTACT = 'Fernando'
197
198 # Set argument defaults
199 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
200 contact_name,contact_email = release.authors[AUTHOR_CONTACT][:2]
201 crash_report_fname = 'IPython_crash_report.txt'
202 # Call parent constructor
203 CrashHandler.__init__(self,app,app_name,contact_name,contact_email,
204 bug_tracker,crash_report_fname)
205
206 def make_report(self,traceback):
207 """Return a string containing a crash report."""
208
209 sec_sep = self.section_sep
210 # Start with parent report
211 report = [super(IPythonCrashHandler, self).make_report(traceback)]
212 # Add interactive-specific info we may have
213 rpt_add = report.append
214 try:
215 rpt_add(sec_sep+"History of session input:")
216 for line in self.app.shell.user_ns['_ih']:
217 rpt_add(line)
218 rpt_add('\n*** Last line of input (may not be in above history):\n')
219 rpt_add(self.app.shell._last_input_line+'\n')
220 except:
221 pass
222
223 return ''.join(report)
224
@@ -21,13 +21,15 b' Authors'
21 21 #-----------------------------------------------------------------------------
22 22 # Imports
23 23 #-----------------------------------------------------------------------------
24
24 25 from __future__ import absolute_import
25 26
26 27 import logging
27 28 import os
28 29 import sys
29 30
30 from IPython.core import crashhandler
31 from IPython.core import release
32 from IPython.core.crashhandler import CrashHandler
31 33 from IPython.core.application import Application, BaseAppConfigLoader
32 34 from IPython.core.iplib import InteractiveShell
33 35 from IPython.config.loader import (
@@ -317,6 +319,67 b' class IPAppConfigLoader(BaseAppConfigLoader):'
317 319
318 320
319 321 #-----------------------------------------------------------------------------
322 # Crash handler for this application
323 #-----------------------------------------------------------------------------
324
325
326 _message_template = """\
327 Oops, $self.app_name crashed. We do our best to make it stable, but...
328
329 A crash report was automatically generated with the following information:
330 - A verbatim copy of the crash traceback.
331 - A copy of your input history during this session.
332 - Data on your current $self.app_name configuration.
333
334 It was left in the file named:
335 \t'$self.crash_report_fname'
336 If you can email this file to the developers, the information in it will help
337 them in understanding and correcting the problem.
338
339 You can mail it to: $self.contact_name at $self.contact_email
340 with the subject '$self.app_name Crash Report'.
341
342 If you want to do it now, the following command will work (under Unix):
343 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
344
345 To ensure accurate tracking of this issue, please file a report about it at:
346 $self.bug_tracker
347 """
348
349 class IPAppCrashHandler(CrashHandler):
350 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
351
352 message_template = _message_template
353
354 def __init__(self, app):
355 contact_name = release.authors['Fernando'][0]
356 contact_email = release.authors['Fernando'][1]
357 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
358 super(IPAppCrashHandler,self).__init__(
359 app, contact_name, contact_email, bug_tracker
360 )
361
362 def make_report(self,traceback):
363 """Return a string containing a crash report."""
364
365 sec_sep = self.section_sep
366 # Start with parent report
367 report = [super(IPAppCrashHandler, self).make_report(traceback)]
368 # Add interactive-specific info we may have
369 rpt_add = report.append
370 try:
371 rpt_add(sec_sep+"History of session input:")
372 for line in self.app.shell.user_ns['_ih']:
373 rpt_add(line)
374 rpt_add('\n*** Last line of input (may not be in above history):\n')
375 rpt_add(self.app.shell._last_input_line+'\n')
376 except:
377 pass
378
379 return ''.join(report)
380
381
382 #-----------------------------------------------------------------------------
320 383 # Main classes and functions
321 384 #-----------------------------------------------------------------------------
322 385
@@ -327,9 +390,7 b' class IPythonApp(Application):'
327 390 usage = usage.cl_usage
328 391 command_line_loader = IPAppConfigLoader
329 392 config_file_name = default_config_file_name
330
331 # Private and configuration attributes
332 _CrashHandler = crashhandler.IPythonCrashHandler
393 crash_handler_class = IPAppCrashHandler
333 394
334 395 def create_default_config(self):
335 396 super(IPythonApp, self).create_default_config()
@@ -27,6 +27,8 b' from twisted.python import log'
27 27 from IPython.config.loader import PyFileConfigLoader
28 28 from IPython.core.application import Application, BaseAppConfigLoader
29 29 from IPython.core.component import Component
30 from IPython.core.crashhandler import CrashHandler
31 from IPython.core import release
30 32 from IPython.utils.path import (
31 33 get_ipython_package_dir,
32 34 expand_path
@@ -290,6 +292,47 b' class ClusterDirConfigLoader(BaseAppConfigLoader):'
290 292
291 293
292 294 #-----------------------------------------------------------------------------
295 # Crash handler for this application
296 #-----------------------------------------------------------------------------
297
298
299 _message_template = """\
300 Oops, $self.app_name crashed. We do our best to make it stable, but...
301
302 A crash report was automatically generated with the following information:
303 - A verbatim copy of the crash traceback.
304 - Data on your current $self.app_name configuration.
305
306 It was left in the file named:
307 \t'$self.crash_report_fname'
308 If you can email this file to the developers, the information in it will help
309 them in understanding and correcting the problem.
310
311 You can mail it to: $self.contact_name at $self.contact_email
312 with the subject '$self.app_name Crash Report'.
313
314 If you want to do it now, the following command will work (under Unix):
315 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
316
317 To ensure accurate tracking of this issue, please file a report about it at:
318 $self.bug_tracker
319 """
320
321 class ClusterDirCrashHandler(CrashHandler):
322 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
323
324 message_template = _message_template
325
326 def __init__(self, app):
327 contact_name = release.authors['Brian'][0]
328 contact_email = release.authors['Brian'][1]
329 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
330 super(ClusterDirCrashHandler,self).__init__(
331 app, contact_name, contact_email, bug_tracker
332 )
333
334
335 #-----------------------------------------------------------------------------
293 336 # Main application
294 337 #-----------------------------------------------------------------------------
295 338
@@ -313,6 +356,7 b' class ApplicationWithClusterDir(Application):'
313 356 """
314 357
315 358 command_line_loader = ClusterDirConfigLoader
359 crash_handler_class = ClusterDirCrashHandler
316 360 auto_create_cluster_dir = True
317 361
318 362 def create_default_config(self):
General Comments 0
You need to be logged in to leave comments. Login now