The following will list the entire call stack at entry to a proc or method.
======
proc x {a} {
puts "Entered x, args $a"
set distanceToTop [info level]
for {set i 1} {$i < $distanceToTop} {incr i} {
set callerlevel [expr {$distanceToTop - $i}]
puts "CALLER $callerlevel: [info level $callerlevel]"
}
# ...
return
}
======
[KPV] Here's another version which prints out argument values
(even default one). (See also [Pstack].)
======
proc stacktrace {} {
set stack "Stack trace:\n"
for {set i 1} {$i < [info level]} {incr i} {
set lvl [info level -$i]
set pname [lindex $lvl 0]
append stack [string repeat " " $i]$pname
foreach value [lrange $lvl 1 end] arg [info args $pname] {
if {$value eq ""} {
info default $pname $arg value
}
append stack " $arg='$value'"
}
append stack \n
}
return $stack
}
# Testing code
proc A { } {
B 3
}
proc B { x } {
C [incr x] 2
}
proc C { x y {z 5} } {
D [incr x] [incr y] $z
}
proc D { x y z} {
E [incr x] [incr y] [incr z]
}
proc E {x y z } {
stacktrace
}
A
======
[Napier] notes that the above solutions will not work if you are using TclOO as [info args my] will result in an error.
[DKF]: Yes, there's other mechanisms for introspecting TclOO methods on the stack. The [self class]/[self method] command ''when run in the right stack scope'' will be useful, as will [info class definition] and/or [info object definition]: [self class] and [self method] say what is running, and [info class definition] is like [info args] and [info body] rolled into one. (Methods aren't ''quite'' procedures. They're just very similar.)
[Martyn Smith] Notes that this does not work for namespace procedures either which are not qualified when called, the [info args $pname] generates an error because pname is not qualified.
======
namespace eval ns {
proc a {} {
puts ns::a
b hello
}
proc b {x} {
puts ns::b
puts "=========\n[stacktrace]\n=========="
}
}
ns::a
======
CRN: For solving namespace issue you can use '''info frame'''. Here a small exemple :
======
proc callstack {} {
set stack [list "Stacktrace:"]
for {set i 1} {$i < [info level]} {incr i} {
set level [info level -$i]
set frame [info frame -$i]
if {[dict exists $frame proc]} {
set pname [dict get $frame proc]
set pargs [lrange $level 1 end]
lappend stack " - $pname"
foreach arg $pargs {
lappend stack " * $arg"
}
} else { lappend stack " - **unknwown stack item**: $level $frame"
}
}
return [join $stack "\n"]
}
======
<<categories>> Debugging