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!