This is the new home of the egghelp.org community forum.
All data has been migrated (including user logins/passwords) to a new phpBB version.


For more information, see this announcement post. Click the X in the top right-corner of this box to dismiss this message.

searching for errors/bugs in a script

Issues often discussed about Tcl scripting. Check before posting a scripting question.
Post Reply
User avatar
sKy
Op
Posts: 194
Joined: Thu Apr 14, 2005 5:58 pm
Location: Germany

searching for errors/bugs in a script

Post by sKy »

Here are some tips which should help you to find errors or bugs in a script.
Firstly i suggest to read this thread: http://forum.egghelp.org/viewtopic.php?t=10215

Questions like "How the bot won`t do this or this" won`t really help you or others to find out why. The better way may be to try to understand how tcl works.

The following short proc will putlog the procname and the variables of the atual proc.
name-of-proc args1 ?arg arg ...?

Code: Select all

proc logCaller {} { 
	set r [catch {info level [expr [info level] - 1]} e] 
	if {$r} { 
		 putlog "Called directly by the interpreter (e.g.: .tcl on the partyline)." 
	} { 
		putlog "Called by ${e}." 
	} 
}
or you can use: putlog "procname $var $var2 ..."
Always, if something won`t work and you have no idea why then you should use putlog to show you the exact point of the problem and the content of your variables, returncodes etc.

--
Beware of adding scripts to your config and to type .rehash without testing them. If there are unbalanced barces this will crash your bot which means you have to restart him. To load a script on the save way you have to use the source command in combination with catch. Something like that should be useful:

Code: Select all

# .s scriptname
# not .s scriptname.tcl
bind dcc n|- s script:load
proc script:load { handle idx text } {
	if { [catch { uplevel #0 [list source scripts/$text.tcl] } error] } {
		putlog "0,4Error while loading $text -- Errormsg: $error"
		putlog "script: $text -- ::errorInfo: $::errorInfo"
		return
	} 
	putlog "script: $text -- loaded without error."
	return
}
That`s how i suggest you should scripts if you are not 100% sure if there is no error inside.
Last edited by sKy on Mon Aug 15, 2005 7:01 am, edited 1 time in total.
User avatar
sKy
Op
Posts: 194
Joined: Thu Apr 14, 2005 5:58 pm
Location: Germany

Post by sKy »

If you have big scripts and many procs which will call each other and you don`t know really which proc got called by another one you can use this.

Code: Select all

# strace (original by Elven http://tclhelp.net/forum/viewtopic.php?t=96)
# usage:
# putlog [strace]
proc strace { {args ""} } { 
	if { [info level] == 1 } {
		return "strace: got called directly by the interpreter (e.g.: .tcl on the partyline)."
	}
       set ret {} 
       set r [catch {expr [info level] - 1} l] 
       if {$r} { return {""} } 
       while {$l > -1} { 
               incr l -1 
               lappend ret [info level $l] 
       } 
	set ret [lremove $ret [lindex $ret [expr [llength $ret] - 2]]]
	set last [lrange $ret end end]
	set ret [lreplace $ret end end]
	eval lappend last $ret
	set while_protection 0
	while { [llength $last] != 0 } {
		set x [lindex $last end]
		set last [lremove $last $x]
		if { $x == "" } {
			break
		}
		set x [lindex [split $x] 0]
		lappend newlist $x
		incr while_protection
		if { $while_protection > 100 } {
			putlog "strace: breaking loop, to many executions (>100)."
			break
		}
	}
	set newlist [join [split $newlist] " --> "]
	return $newlist
}
Examaple for what this proc can be used for:

Code: Select all

proc test_a args { test_b 2 2 2 }
proc test_b args { test_c 3 3 3 }
proc test_c args { test_d 4 4 4 }
proc test_d args { test_e 5 5 5 }
proc test_e args { putlog "procname: test_e: strace: [strace]" }
type: .tcl test_e

This will show you which proc got called first, which second, etc...

--
Tcl error: invalid command name "s"
Yeah nice :/ You have many procs and don`t know which script cause this error... How can you find more fast? (http://www.tcl.tk/man/tcl8.5/TclCmd/unknown.htm)

Code: Select all

if { [info command unknown_new] == "" } {
	rename unknown unknown_new
}

proc unknown { args } {
	set command [join [lrange [split $args] 0 0]]
	set arg [join [lrange [split $args] 1 end]]
	putlog "WARNING: unknown command: $command (arguments: $arg) | Lastbind: $::lastbind"
	uplevel #1 [list unknown_new $args]
}
Another nice tcl feature is the errorInfo varibale. I wonder that so less people know it.

Code: Select all

bind dcc n|- e dcc:errorinfo
proc dcc:errorinfo { handle idx text } {
	putlog $::lastbind
	putlog $::errorInfo
}
This will show a multi line traceback to the last error. If you read this you will know what you have to do to prevent this error.
The ugly point is, errorInfo shows always the last error. So, if you use catch and a error has been caused it will show that error last, so be fast ;).

thom\mey showed me a nice way to handle that.

Code: Select all

trace add variable ::errorInfo write logerr
proc logerr { args } {
  if { [set utm [utimerexists errorlog]] != "" } { return }
  utimer 1 errorlog
}
proc errorlog { } {
  set fs [open errorlog.txt a]
  regsub -all -- {\n|\s+} $::errorInfo { } error
  putlog $::errorInfo
  puts $fs "\n"
  puts $fs "[clock format [clock seconds] -format "%d/%m/%y@%H:%M.%S>"] : $::errorInfo"
  close $fs
}
Well, in some case this will create a big error errorlog.txt. I don`t know... Do you want this? But the putlog works nice for me.
User avatar
demond
Revered One
Posts: 3073
Joined: Sat Jun 12, 2004 9:58 am
Location: San Francisco, CA
Contact:

Post by demond »

small correction: the trace command handler is invoked with 3 arguments, not 1; so [logger] actually becomes:

Code: Select all

proc logger {name1 name2 op} {
   # stuff
}
User avatar
rosc2112
Revered One
Posts: 1454
Joined: Sun Feb 19, 2006 8:36 pm
Location: Northeast Pennsylvania

no-crash script loader

Post by rosc2112 »

Just thought I'd post my little script that I created after reading the post by sky. This allows loading any script without it crashing the bot (wish I had found this sooner! <g>) This is how the script is loaded in eggdrop.conf:

##### SCRIPTS #####
source scripts/scripts.txt

and then the scripts.txt file uses:

Code: Select all

set error ""
foreach script {
alltools.tcl
cmd_resolve.tcl
whatever-script-one-per-line.tcl
} {
catch {source scripts/$script} error
if {$error != ""} {putcmdlog "\002SCRIPT ERROR\002:$script\: $::errorInfo"}
}
Never have another bot crash from a script error on load :)
Post Reply