Re: A simple debugging macro



Ken Tilton <kennytilton@xxxxxxxxxxxxx> writes:

fairchild.anthony@xxxxxxxxx wrote:
Hello all,

I wrote this simple macro a while back and I've found it to be
extremely useful for old-fashioned trace style debugging. Maybe
others will find it useful as well. Thoughts or criticism are
welcome. Perhaps others have similar macros or other methods of doing
this that are better.

Think to come of it, that would be a way kewl project, Ye Ultimate
Lisp Debuggery Tools. Yer hired.

Adding to the wish list:

* Being able to turn on debugging WITHOUT re-compiling everything (as
Rainer already pointed out)

* Logging of debug output into a file or (on *nix/OS X) to syslog

I have some ideas for this, of course:

;;; -*- mode: Lisp; Syntax: Common-Lisp; Package: gt.app.dbg; -*-

(in-package :cl-user)
(pushnew :net.goenninger.app.debug *features*)

(defpackage #:net.goenninger.app.debug
(:use
#:common-lisp
#:utils-kt
#:cells
#:net.goenninger.app.tools)
(:nicknames :gnc.app.dbg)
(:export
#:logmsg
#:*module*
#:in-module
#:enable-debugging
#:disable-debugging
#:reset-debugging-settings
#:defdbgobs))

(in-package :net.goenninger.app.debug)

;;; ----------------------------------------------------------------------------
;;; Debug Message Printing And Logging
;;; ----------------------------------------------------------------------------
;;; Requires: utils-kt package (by Kenneth Tilton)

(defun find-package-defining-symbol (designator)
(let ((name (string designator)))
(labels ((in-package-p (package)
(nth-value 1 (find-symbol name package))))
(if (member (in-package-p *package*) '(:external :internal))
*package*
(find :external (package-use-list *package*) :key #'in-package-p)))))

(defparameter *debug-modules* nil "Holds the module names for which debugging is enabled globally.")

(defparameter *module* nil "Holds the currently active module name.")

(defparameter *debug-functions* nil "Holds the package and function names for which debugging is enabled.")

(defparameter *log-level* nil "Defines the log level above which messages are logged - one of [\":DEBUG\"|\":INFO\"|\":WARN\"|\":ERROR\"|\":CRITICAL\"|\":EMERGENCY\"].")

(defmacro in-module (module-name)
(eval-when (:load-toplevel :compile-toplevel :execute)
`(setf net.goenninger.app.debug:*module* (up$ ,module-name))))

(defmacro logmsg (msg-class method method-desc msg &rest msg-args)
`(logmsg-fn ,msg-class
(find-package-defining-symbol ,method)
,method
,method-desc
,msg
,@msg-args))

(defun logmsg-fn (msg-class package method method-desc msg &rest msg-args)
(when (and (member (up$ (symbol-name method))
*debug-functions* :test #'string=)
(member *module* *debug-modules* :test #'string=))
(format *debug-io* "~&~%--- ~a --------------------------------------------------"
(format-iso8601-time (get-universal-time) t))
(format *debug-io* "~&*** ~A [ FN ~S ( ~A ) ]~&"
msg-class method method-desc)
(format *debug-io* "*** ")
(apply 'format *debug-io* msg msg-args)
(format *debug-io* "~%")
(force-output *debug-io*)))

(defmethod enable-debugging ((key (eql :module)) module-name)
(pushnew (up$ module-name) *debug-modules* :test #'string=))

(defmethod enable-debugging ((key (eql :function)) function-name)
(pushnew (up$ (symbol-name function-name)) *debug-functions* :test #'string=))

(defmethod disable-debugging ((key (eql :module)) module-name)
(setf *debug-modules* (remove (up$ module-name) *debug-modules*
:test #'string=)))

(defmethod disable-debugging ((key (eql :function)) function-name)
(setf *debug-modules* (remove (up$ (symbol-name function-name))
*debug-functions* :test #'string=)))

(defun reset-debugging-settings ()
(setf *debug-modules* nil)
(setf *debug-functions* nil))

;;; ----------------------------------------------------------------------------
;;; defdbgobs - Define standard debugging observer for a cell slot MACRO
;;; ----------------------------------------------------------------------------
;;; slot-name := Identifies the slot name to be observed
;;; class-desc := Identifies the class, example: ((self my-class))
;;;
;;; Requires: Cells 3.0 (by Kenneth Tilton)

(defmacro defdbgobs (slot-name class-desc)
`(defobserver ,slot-name ,class-desc
(logmsg :INFO 'observer ',slot-name
"~A of ~S: ~S -> ~S"
',slot-name self old-value new-value )))

Just some thoughts ... ;-)

// frgo

--

Frank Goenninger

frgo(at)mac(dot)com

"Don't ask me! I haven't been reading comp.lang.lisp long enough to
really know ..."
.



Relevant Pages

  • Re: Debug statements
    ... i have used some debug macro and called several timesin ... The purpose of the macro was to print the values at that time to the ... Now that i have finished debugging, i do not want to execute the ... unless you come up with some regex to do the commenting ...
    (comp.lang.c)
  • Re: Explanation of macros; Haskell macros
    ... This macro lets me write thing like: ... The amount of debugging noise is ... (PROGN ... fake eta-expanded form. ...
    (comp.lang.lisp)
  • Re: Explanation of macros; Haskell macros
    ... This macro lets me write thing like: ... The amount of debugging noise is ... (PROGN ... fake eta-expanded form. ...
    (comp.lang.python)
  • Error building GCL-2.6.2 Win XP/ MINGW GCC 3.2.3 / MSYS 1.0.10
    ... makeinfo gcl-tk.texi ... Fast links are on: do for debugging ... The tag (NIL) is undefined. ...
    (comp.lang.lisp)
  • Re: On getting started with gcl
    ... I meant the multiple print statements stopped happening. ... Fast links are on: do (si::use-fast-links nil) for debugging ...
    (comp.lang.lisp)