From: Steve Tuckner Date: 2004-02-25T23:58:52+09:00 Subject: Re: proposal: debug keyword Simon Strandgaard wrote: > > >>I'd prefer to have specialized methods for debug printing. >> >> >> > >Please enlighten me. How do you debug ? > > >It would be nice to identify a good model for advanced debugging with >Test::Unit. > > I too am interested in how others debug their unit tests (or code in general). I am preparing to release my vrtools library an am removing my trace statements in them because it seems like an unnecessary dependency (perhaps just my way of working). Below is my trace module that I use all the time. I once tried log4r but didn't like it because it didn't seem easy to turn on and off debugging when I needed it to. My output includes the code and line number which my editor links up when the unit test is done running. Also it includes a time stamp to help with any timing related issues. I can include and exclude debug in various ways and direct output to a file. It all works pretty well for me (not perfectly -- for example some things could be named better). So my requirements for a simple tracing/debugging system are for me: 1. Trace output should include file/line number plus time stamp 2. Need to be able to turn it on and off at run time 3. Need to be able to filter which debug statements come out by debug level, function, file, possibly other considerations 4. Need to be able to redirect output to a file What are others requirements? Maybe log4r provides all these capabilities and if so enlighten me please. Steve Tuckner ----------------- Examples of use --------------------------- require "my/mytrace" # to use my tracing this creates a global $TRACE of class Tracer $TRACE.set_level 5 # sets the level under which traces will appear $TRACE.exclude_files("foo.rb") # this excludes any traces in foo.rb from coming out $TRACE.include_files("bar.rb") # this overrides exculsions to only allow traces from included files $TRACE.exclude_functions(:foo, :bar) # this excludes any traces from coming out from these functions (no matter the class) $TRACE.set_output("out.txt") # write each statement to the output file and close it after every trace (this is not as bad as it sounds and if the program dies you definitiely get all the trace) $TRACE.debug 5, "this is a trace" # this is the basic trace statement with level 5 ----------------- Example of program and output --------------------------- --------------------------- tracetest.rb ---------- require "my/mytrace" def foo $TRACE.debug 5, "I am in foo" puts "not a debug statement" end $TRACE.set_level 5 foo $TRACE.set_level 0 foo -------------------------- output ----------------- [tracetest.rb:4 ] [02/25/04 08:47:51] I am in foo not a debug statement not a debug statement -------------------------------------------------- ----------------- Trace code ------------------------------------------------ class Tracer def initialize @trace_level = 0 @file = nil @width = 25 @excluded_functions = [] @excluded_files = [] @output_to_screen_always = false end def set_width(width) @width = width end def trace(str, level=1) #old_dollar_equal = $= #$= = false if @trace_level >= level then m = /([\w_]+\.rb):(\d+):in `(.*)'/.match(caller[1]) if m then filename = m[1] line = m[2].to_i function = m[3] t = Time.current.strftime("%m/%d/%y %H:%M:%S") str = sprintf "[%-#{@width}s] [%s] %s", "#{m[1]}:#{m[2]}", t, str if @included_files then return unless @included_files.include?(filename) else if @excluded_functions.include?(function) then return end if @excluded_files.include?(filename) then return end end end if @filename then File.open(@filename, "a") {|f| f.print str, "\n"} end if !@filename || @output_to_screen_always then puts str $stdout.flush end end ensure #$= = old_dollar_equal end def debug(level, str) trace(str, level) end def set_level(level) @trace_level = level end def set_level_include(level, included_files) @trace_level = level @included_files = included_files end def set_output(filename) @filename = filename File.open(@filename, "w") {} end def set_output_io(io) @io = io end def set_output_to_screen_always @output_to_screen_always = true end def exclude_functions(functions) @excluded_functions += functions end def exclude_files(filenames) @excluded_files += filenames end end # define the $TRACE variable if not already defined if !$TRACE then $TRACE = Tracer.new end