Since 8.6 and TIP #348, we now have the built-in info errorstack providing the same functionality more efficiently and robustly. The script-level emulation below is only for the curious, or for pre-8.6 releases.
if {[catch {some code} err]} { Log "Argh: err\n$::errorInfo" }
or if you're catching from bgerror:
proc bgerror err { Log "Argh: err\n$::errorInfo" }
set ::errorLevel -1 set ::errorStack {} trace add variable ::errorInfo write { set __n [info level] if {($__n>0)&&($__n!=$::errorLevel)} { set ::errorLevel $__n set __l [info level 0] lappend ::errorStack $__l } # the next line must end with the closing brace on the same line # in order to consume the extra arguments at runtime. list }
It works by exploiting the fact that ::errorInfo is built progressively while climbing back up the stack; hence, each increment occurs within the scope of each level, and there [info level 0] gives the local function's actual arguments, regardless of whether the variables holding these args have been modified since function entry or not.
if {![regexp {\n invoked from within\n} $::errorInfo]} { set ::errorLevel -1; set ::errorStack [list]; }
if {[string match {*while executing*} $::errorInfo] == 0} { set ::errorLevel -1; set ::errorStack [list]; }
-Alex
Twylite 20090227: How does this interact with [catch] in Tcl 8.5 (TIP #90 [L1 ] introduced the options dict) and [try] in Tcl 8.5 (introduced by TIP #329 [L2 ])?
HaO: IMHO the same way as errorInfo, as it is based on its creation. For me, it works with both language extensions and errorStack is correctly created
HaO 2010-12-09: I have included this into my tcl 8.5.9 framework and it is brilliant. Insert the addendum with the regexp at the beginning of the trace write definition and display ::errorStack within a custom bgerror routine together with ::errorInfo. errorInfo tells the error and errorStack the current values. Thank you very much, Alex and Martin!
Interactive sample session after copying the upper lines in a fresh wish interpreter:
% proc e1 args { expr 1/0 } % proc e2 args { e1 {*}$args } % e2 1 2 3 divide by zero % set errorInfo divide by zero invoked from within "expr 1/0 " (procedure "e1" line 1) invoked from within "e1 {*}$args " (procedure "e2" line 1) invoked from within "e2 1 2 3" % set errorStack {e1 1 2 3} {e2 1 2 3}
HaO 2010-12-15: In interactive mode, the term auto_load_index may appear when a potentially unknown procedure is called.
% proc e args {qq $args} % e 1 2 3 invalid command name "qq" % set errorStack auto_load_index {e 1 2 3}
Alex remarked on clt [L3 ], that this is the truth.
HaO 2010-12-16: A bug in 8.5.x - 8.5.9 may cause that traces on error variables crash TCL. . Sorry, this makes this nice trick practically unusable (Discussion: [L4 ], Bug: [L5 ]).