Simpletracer

if 0 {

MSW(2005-02-08)

Preludium (from tcl'ers chatroom)

msw er, any way to get a quick log of functions along with their arguments & return vals as they're called ?

msw but only for a subset of all called procs .. like pls show me the args & results of all 'expr' and 'lindex' in this interpreter ?

suchenwi You might try execution traces.

miguel yes - or else 'rename expr _expr; proc expr args {lappend ::log [info level 0]; eval expr $args}'

msw Hmm exec traces are too verbose... I like miguel's suggestion :)

suchenwi proc expr args {lappend ::log [info level 0]; set res [expr $args]; lappend ::log $res; return $res}

msw Seems like a token for the wiki :>

miguel oops : eval _expr $args, or get an infinite recursion:o

Code }

 namespace eval Simpletracer {
    variable log
    variable procs
    namespace export watch forget watched results
 }

 namespace eval Simpletracer::traced {}

 # don't trace the following:
 # o lindex  o lappend
 # o return  o uplevel
 # o set
 proc Simpletracer::watch args {
    variable procs
    variable log
    foreach a $args {
        if {[catch {rename $a ::Simpletracer::traced::$a} msg]} then {
            puts stderr "Error tracing $a: $msg"
            continue
        }
        proc ::$a args {
            set inf [info level 0]
            set cmd ::Simpletracer::traced::[lindex $inf 0]
            lappend ::Simpletracer::log $inf
            set res [uplevel 1 $cmd $args]
            lappend ::Simpletracer::log $res
            return $res
        }
        lappend procs $a
        lappend log "watching $a"
    }
 }

 proc Simpletracer::forget args {
    variable procs
    variable log
    foreach a $args {
        if {[lsearch $procs $a] == -1} then {
            puts stderr "$a ain't traced!"
            continue
        }
        if {[catch {rename $a {}; rename ::Simpletracer::traced::$a ::$a} msg]} then {
            puts stderr "untracing $a failed: $msg"
            continue
        }
        lappend log "forgetting $a"
    }    
 }

 proc Simpletracer::watched args {
    variable procs
    return $procs
 }

 proc Simpletracer::results args {
    variable log
    return $log
 }

if 0 {

 % namespace import Simpletracer::*
 % watch expr
 % expr 1 + 1
 2
 % expr 1+1
 2
 % results
 {watching expr} {expr 1 + 1} 2 {expr 1+1} 2
 % forget expr
 % expr 2+2
 4
 % results
 {watching expr} {expr 1 + 1} 2 {expr 1+1} 2 {forgetting expr}
 % 

Thanks RS & MS !


Discussion:

Obviously it's not possible to [watch] one of the procs/commands which are used in [watch]'s generated [proc]. How to solve that ? If there exists [Simpletracer::traced::cmd], then the proc should use [Simpletracer::traced::cmd] instead of [::cmd]. Thinking of some [unknown] magic to do that, and instead use something like [Simpletracer::sane::cmd] in the proc. Hrmm, ideas ?

Note: when I said 'trace is too verbose', I was thinking of tcl_traceLevel (a tclvars), not of the trace add execution (which isn't in 8.3: cmp [L1 ] vs. [L2 ])


Category Example

}