127 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			Common Lisp
		
	
	
	
	
	
			
		
		
	
	
			127 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			Common Lisp
		
	
	
	
	
	
| (in-package #:trivial-backtrace)
 | |
| 
 | |
| (defun print-condition (condition stream)
 | |
|   "Print `condition` to `stream` using the pretty printer."
 | |
|   (format
 | |
|    stream
 | |
|    "~@<An unhandled error condition has been signalled:~3I ~a~I~:@>~%~%"
 | |
|    condition))
 | |
|   
 | |
| (defun print-backtrace (error &key (output *debug-io*)
 | |
| 			(if-exists :append)
 | |
| 			(verbose nil))
 | |
|   "Send a backtrace for the error `error` to `output`. 
 | |
| 
 | |
| The keywords arguments are:
 | |
| 
 | |
|  * :output - where to send the output. This can be:
 | |
| 
 | |
|      * a string (which is assumed to designate a pathname)
 | |
|      * an open stream
 | |
|      * nil to indicate that the backtrace information should be 
 | |
|        returned as a string
 | |
| 
 | |
|  * if-exists - what to do if output designates a pathname and 
 | |
|    the pathname already exists. Defaults to :append.
 | |
| 
 | |
|  * verbose - if true, then a message about the backtrace is sent
 | |
|    to \\*terminal-io\\*. Defaults to `nil`.
 | |
| 
 | |
| If the `output` is nil, the returns the backtrace output as a
 | |
| string. Otherwise, returns nil.
 | |
| "
 | |
|   (when verbose
 | |
|     (print-condition error *terminal-io*))
 | |
|   (multiple-value-bind (stream close?)
 | |
|       (typecase output
 | |
| 	(null (values (make-string-output-stream) nil))
 | |
| 	(string (values (open output :if-exists if-exists
 | |
| 			      :if-does-not-exist :create
 | |
| 			      :direction :output) t))
 | |
| 	(stream (values output nil)))
 | |
|     (unwind-protect
 | |
| 	 (progn
 | |
| 	   (format stream "~&Date/time: ~a" (date-time-string))
 | |
| 	   (print-condition error stream)
 | |
| 	   (terpri stream)
 | |
| 	   (print-backtrace-to-stream stream)
 | |
| 	   (terpri stream)
 | |
| 	   (when (typep stream 'string-stream)
 | |
| 	     (get-output-stream-string stream)))
 | |
| 	 ;; cleanup
 | |
| 	 (when close?
 | |
| 	   (close stream)))))
 | |
| 
 | |
| #+(or mcl ccl)
 | |
| (defun print-backtrace-to-stream (stream)
 | |
|   (let ((*debug-io* stream))
 | |
|     (ccl:print-call-history :detailed-p nil)))
 | |
| 
 | |
| #+allegro
 | |
| (defun print-backtrace-to-stream (stream)
 | |
|   (with-standard-io-syntax
 | |
|     (let ((*print-readably* nil)
 | |
| 	  (*print-miser-width* 40)
 | |
| 	  (*print-pretty* t)
 | |
| 	  (tpl:*zoom-print-circle* t)
 | |
| 	  (tpl:*zoom-print-level* nil)
 | |
| 	  (tpl:*zoom-print-length* nil))
 | |
|       (cl:ignore-errors
 | |
|        (let ((*terminal-io* stream)
 | |
| 	     (*standard-output* stream))
 | |
| 	 (tpl:do-command "zoom"
 | |
| 	   :from-read-eval-print-loop nil
 | |
| 	   :count t
 | |
| 	   :all t))))))
 | |
| 
 | |
| #+lispworks
 | |
| (defun print-backtrace-to-stream (stream)
 | |
|   (let ((dbg::*debugger-stack*
 | |
| 	 (dbg::grab-stack nil :how-many most-positive-fixnum))
 | |
| 	(*debug-io* stream)
 | |
| 	(dbg:*debug-print-level* nil)
 | |
| 	(dbg:*debug-print-length* nil))
 | |
|     (dbg:bug-backtrace nil)))
 | |
| 
 | |
| #+sbcl
 | |
| ;; determine how we're going to access the backtrace in the next
 | |
| ;; function
 | |
| (eval-when (:compile-toplevel :load-toplevel :execute)
 | |
|   (when (find-symbol "*DEBUG-PRINT-VARIABLE-ALIST*" :sb-debug)
 | |
|     (pushnew :sbcl-debug-print-variable-alist *features*)))
 | |
| 
 | |
| #+sbcl
 | |
| (defun print-backtrace-to-stream (stream)
 | |
|   (let (#+:sbcl-debug-print-variable-alist
 | |
| 	(sb-debug:*debug-print-variable-alist*
 | |
| 	 (list* '(*print-level* . nil)
 | |
| 		'(*print-length* . nil)
 | |
| 		sb-debug:*debug-print-variable-alist*))
 | |
| 	#-:sbcl-debug-print-variable-alist
 | |
| 	(sb-debug:*debug-print-level* nil)
 | |
| 	#-:sbcl-debug-print-variable-alist
 | |
| 	(sb-debug:*debug-print-length* nil))
 | |
|     (sb-debug:backtrace most-positive-fixnum stream)))
 | |
| 
 | |
| #+clisp
 | |
| (defun print-backtrace-to-stream (stream)
 | |
|   (system::print-backtrace :out stream))
 | |
| 
 | |
| #+(or cmucl scl)
 | |
| (defun print-backtrace-to-stream (stream)
 | |
|   (let ((debug:*debug-print-level* nil)
 | |
| 	(debug:*debug-print-length* nil))
 | |
|     (debug:backtrace most-positive-fixnum stream)))
 | |
| 
 | |
| 
 | |
| ;; must be after the defun above or the docstring may be wiped out
 | |
| (setf (documentation 'print-backtrace-to-stream 'function)
 | |
|   "Send a backtrace of the current error to stream. 
 | |
| 
 | |
| Stream is assumed to be an open writable file stream or a
 | |
| string-output-stream. Note that `print-backtrace-to-stream`
 | |
| will print a backtrace for whatever the Lisp deems to be the 
 | |
| *current* error.
 | |
| ")
 | |
| 
 | |
| 
 |