Article View: gnu.emacs.sources
Article #273trace.el - a trace package for Emacs-Lisp functions
From: Hans Chalupsky
Date: Wed, 16 Dec 1992 04:48
Date: Wed, 16 Dec 1992 04:48
267 lines
9657 bytes
9657 bytes
Here is a simple trace package that gives you Lisp-style trace output for
Emacs-Lisp functions. The package is based on advice.el previously posted
here.
The latest versions of trace.el and advice.el are also available via anonymous
ftp from ftp.cs.buffalo.edu (128.205.32.9) in directory /pub/Emacs/.
Enjoy,
Hans
hans@cs.buffalo.edu
Hans Chalupsky, Dept. of CS, 226 Bell Hall, SUNY@Buffalo, NY 14260.
------------------------ cut here ------------------------
;; -*-Emacs-Lisp-*-
;;
;; Tracing facility for Emacs-Lisp functions
;;
;; Copyright (C) 1992 Hans Chalupsky
;;
;; File: trace.el
;; Revision: $Revision: 1.1 $
;; Author: Hans Chalupsky (hans@cs.buffalo.edu)
;; Created: Date: 92/12/09 19:18:06
;; Modified: $Date: 92/12/15 22:45:15 $
;;
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 1, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; A copy of the GNU General Public License can be obtained from this
;; program's author (send electronic mail to hans@cs.buffalo.edu) or from
;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
;; 02139, USA.
;;
;;
;; Description:
;; ============
;; A simple trace package that utilizes advice.el. It generates trace
;; information in a Lisp-style fashion and inserts it into a trace output
;; buffer. Tracing can be done in the background (or silently) so that
;; generation of trace output won't interfere with what you are currently
;; doing.
;;
;; How to get the latest trace.el:
;; ===============================
;; You can get the latest version of this file either via anonymous ftp from
;; ftp.cs.buffalo.edu (128.205.32.9) with pathname /pub/Emacs/trace.el,
;; or send email to hans@cs.buffalo.edu and I'll mail it to you.
;;
;; Restrictions:
;; =============
;; - Traced subrs when called interactively will always show nil as the
;; value of ad-subr-args.
;; - Subrs called from other subrs/C-code won't generate any trace output.
;; - All the restrictions that apply to advice.el
;;
;; Installation:
;; =============
;; Put this file together with advice.el (which you can get from the same
;; ftp directory mentioned above) somewhere into your Emacs load-path,
;; byte-compile it/them for efficiency, and put the following autoload
;; declaration into your .emacs
;;
;; (autoload 'trace-function "trace" "Trace a function" t nil)
;;
;; or explicitly load it with (require 'trace) or (load "trace").
;;
;; Comments, suggestions, bug reports
;; ==================================
;; are strongly appreciated, please email them to hans@cs.buffalo.edu.
;; Also feel free to mail me any questions you might have about trace.el.
;;
;; Usage:
;; ======
;; - To trace a function say M-x trace-function which will ask you for the name
;; of the function/subr/macro you want to trace, as well as for the buffer
;; into which trace output should go. With a prefix argument the tracing
;; will be done silently in the background.
;; - To untrace a function say M-x untrace-function and supply the function
;; you want to have untraced as an argument.
;; - To untrace all currently traced functions say M-x untrace-all.
;;
;;
;; Examples:
;; =========
;;
;; (defun fact (n)
;; (if (= n 0) 1
;; (* n (fact (1- n)))))
;; fact
;;
;; (trace-function 'fact)
;; fact
;;
;; ;; Now, evaluating this...
;; (fact 4)
;; 24
;;
;; ;; ...will generate the following in *trace-buffer*:
;; 1 -> fact: n=4
;; | 2 -> fact: n=3
;; | | 3 -> fact: n=2
;; | | | 4 -> fact: n=1
;; | | | | 5 -> fact: n=0
;; | | | | 5 <- fact: 1
;; | | | 4 <- fact: 1
;; | | 3 <- fact: 2
;; | 2 <- fact: 6
;; 1 <- fact: 24
;;
;;
;; (defun ack (x y z)
;; (if (= x 0)
;; (+ y z)
;; (if (and (<= x 2) (= z 0))
;; (1- x)
;; (if (and (> x 2) (= z 0))
;; y
;; (ack (1- x) y (ack x y (1- z)))))))
;; ack
;;
;; (trace-function 'ack)
;; ack
;;
;; ;; Try this for some interesting trace output:
;; (ack 3 3 1)
;; 27
;;
;;
;; ;; The following does something similar to the functionality of the
;; ;; package log-message.el by Robert Potter (rpotter@grip.cis.upenn.edu),
;; ;; which is giving you a chance to look at messages that might have
;; ;; whizzed by too quickly (you won't see subr generated messages though):
;;
;; (trace-function 'message "*Message Log*" t)
;;
(require 'advice)
(require 'backquote)
(defconst trace-version (substring "$Revision: 1.1 $" 11 -2))
(defvar trace-buffer "*trace-output*"
"Trace output will by default go to that buffer")
(defvar traced-functions nil
"List of functions that are currently traced")
(defvar trace-level 0
"Current level of traced function invocation")
(defvar trace-in-background nil
"If non-NIL all trace ouput will silently go to trace-buffer, otherwise
the execution of a traced function will pop to the trace-buffer.")
(defvar trace-separator (format "%s\n" (make-string 70 ?=))
"Used to separate new trace output from previous traced runs")
(defun trace-entry-message (function level argument-bindings)
"Generates a string that describes that FUNCTION has been entered at
trace LEVEL with ARGUMENT-BINDINGS."
(format "%s%s%d -> %s: %s\n"
(mapconcat 'char-to-string (make-string (1- level) ?|) " ")
(if (> level 1) " " "")
level
function
(mapconcat (function
(lambda (binding)
(format "%s=%s"
(ad-arg-binding-field binding 'name)
(ad-arg-binding-field binding 'value))))
argument-bindings
" ")))
(defun trace-exit-message (function level value)
"Generates a string that describes that FUNCTION has been exited at
trace LEVEL and that it returned VALUE."
(format "%s%s%d <- %s: %s\n"
(mapconcat 'char-to-string (make-string (1- level) ?|) " ")
(if (> level 1) " " "")
level
function
value))
(defun trace-function (function &optional buffer background)
"Generates the trace advice for FUNCTION and activates it (and all other
advice there might be!!) Trace output will go to BUFFER. If BACKGROUND is
non-NIL (or when called with a prefix argument) trace output will be
generated in the background, otherwise a traced FUNCTION will popup its
trace BUFFER whenever it is called."
(interactive
(call-interactively
(progn
;; This seems to be the only way to influence the default used by the
;; B specifier in interactive. Messes with buffer list but is much less
;; work than doing the correct thing by hand:
(save-excursion
(switch-to-buffer (get-buffer-create trace-buffer)))
'(lambda (function &optional buffer background)
(interactive "aFunction to trace: \nBOutput to buffer: \nP")
(list function buffer background)))))
(ad-add-advice
function
(ad-make-advice
'trace nil
(` ((let ((trace-level (1+ trace-level))
(trace-buffer (get-buffer-create (, (or buffer trace-buffer))))
(trace-in-background (, (and background t))))
(if (and (= trace-level 1)
(not trace-in-background))
(pop-to-buffer trace-buffer))
(save-excursion
(set-buffer trace-buffer)
(goto-char (point-max))
;; Insert a separator from previous trace output:
(if (= trace-level 1) (insert trace-separator))
(insert
(trace-entry-message
'(, function) trace-level ad-arg-bindings)))
(if (not trace-in-background) (goto-char (point-max)))
ad-do-it
(save-excursion
(set-buffer trace-buffer)
(goto-char (point-max))
(insert
(trace-exit-message
'(, function) trace-level ad-return-value)))
(if (not trace-in-background) (goto-char (point-max)))
))))
'around 'last)
(if (ad-has-proper-definition function)
(ad-activate function nil))
(if (not (memq function traced-functions))
(setq traced-functions (cons function traced-functions)))
function)
(defun untrace-function (function)
"Untraces FUNCTION and activates all remaining advice information. If
FUNCTION was not traced this is a noop."
(interactive "aFunction to untrace: ")
(cond ((memq function traced-functions)
(ad-remove-advice function 'around 'trace)
(if (ad-has-proper-definition function)
(ad-activate function nil))
(setq traced-functions (delq function traced-functions))
function)))
(defun untrace-all ()
"Untraces all currently traced functions"
(interactive)
(ad-dolist (traced-fn (copy-alist traced-functions))
(untrace-function traced-fn)))
(provide 'trace)
;; eof
Technical Details
Message-ID:
<BzC5DD.HKB@acsu.buffalo.edu>Path:
arc1-ca.pugleaf.net!sparky!uunet!elroy.jpl.nasa.gov!swrinde!news.dell.com!natinst.com!cs.utexas.edu!qt.cs.utexas.edu!yale.edu!spool.mu.edu!umn.edu!cs.widener.edu!dsinc!ub!acsu.buffalo.edu!hansShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!sparky!uunet!elroy.jpl.nasa.gov!swrinde!news.dell.com!natinst.com!cs.utexas.edu!qt.cs.utexas.edu!yale.edu!spool.mu.edu!umn.edu!cs.widener.edu!dsinc!ub!acsu.buffalo.edu!hans From: hans@acsu.buffalo.edu (Hans Chalupsky) Newsgroups: gnu.emacs.sources Subject: trace.el - a trace package for Emacs-Lisp functions Message-ID: <BzC5DD.HKB@acsu.buffalo.edu> Date: 16 Dec 92 04:48:49 GMT Sender: nntp@acsu.buffalo.edu Distribution: gnu Organization: State University of New York at Buffalo/Comp Sci Lines: 267 Nntp-Posting-Host: hadar.cs.buffalo.edu