ANN: debugprint

Hi everybody,

Growing out of the discussions about $DEBUG and $VERBOSE, and how
they’re set from the commandline, I’ve created a dead-simple
"debugprint" library package. You can find it on RAA at:

But since it’s so tiny, here’s the entire code:

module Kernel
def info(*args)
puts(*args) if $VERBOSE
end

def debug(*args)
puts(*args) if $DEBUG
end

module_function :info, :debug
end

This time, I actually followed the KISS principle. :slight_smile:

I’m hoping this can save a few keystrokes in its current form. But I
also have visions for something more ambitious, so I’d like to discuss
a little.

In C, I have some debug macros that look like this:

#define printlnDebug(fmt, …)
printf("[D]%s#%s:%d " fmt “\n”, FILE, FUNCTION, LINE,
VA_ARGS)

#define printvarDebug(var)
printf("[D]%s#%s:%d %s=%d\n", FILE, FUNCTION, LINE, #var,
var)

The end result is that if I have these lines of c code:

state = “running”;
count = 5;
printlnDebug(“state is: %s”, state);
printvarDebug(count);

I get this result:

[D]main.c#doSomething:80 state is: running
[D]main.c#doSomething:81 count=5

I have ambitions to do something similar with Ruby. My idea is that
you could set a format string, similar to the one in the Time class and
use that when you print out debug info, the default format string would
simply include the debug message.

So, some questions:

  1. is it possible for a method to get access to the context that called
    it so it can fill in things like source file name, method name, and
    line number
  2. is there a way to get the name of a variable into a string, like the
    #var construct does in C macros

Could the ruby commandline syntax be modified so that they can do more
than just set $DEBUG and $VERBOSE to true/false? For example, maybe
allowing multiple flags so that -ddd (or -d -d -d) would set $DEBUG to
3. Or, possibly adding an optional parameter with the same syntax as
the -e flag that would allow you to set $DEBUG or $VERBOSE to any value
you want. As others have mentioned, these changes would keep backwards
compatibility with scripts that say “if $DEBUG”, which seems to be the
most common usage. On the other hand, might they have an effect on
other things, like C code that compiles to a Ruby library. I have no
idea how $DEBUG and $VERBOSE are used here.

Comments?

Ben

Hello,

···

In message “ANN: debugprint” on 03/08/01, Ben Giddings ben@thingmagic.com writes:

Growing out of the discussions about $DEBUG and $VERBOSE, and how
they’re set from the commandline, I’ve created a dead-simple
“debugprint” library package. You can find it on RAA at:

How about direct messages to $stderr?

						matz.

Ben,

So, some questions:

  1. is it possible for a method to get access to the context that called
    it so it can fill in things like source file name, method name, and
    line number

This might help a little:

filename = __FILE__
line = __LINE__

not sure about the rest

···

John Long
www.wiseheartdesign.com

Good point, I knew it was a wee bit too simple. I’ll make the change
now. :wink:

Ben

···

On Friday, August 1, 2003, at 12:23 AM, Yukihiro Matsumoto wrote:

How about direct messages to $stderr?

Actually, how about debug() goes to $stderr and info() goes to $stdout.
People mostly tend to do:

puts(“doing blah”) if $VERBOSE

rather than

$stderr.puts(“doing blah”) if $VERBOSE

Don’t they? Any opinions?

Ben

···

On Friday, August 1, 2003, at 12:23 AM, Yukihiro Matsumoto wrote:

How about direct messages to $stderr?

Yeah, only unless it’s in a macro, those will always give the file and
line of “fancydebugprint”, where the method is defined, right? I want
the ones one stack level up – something that’s easy with a macro but
I’m not sure how to do it here.

Ben

···

On Friday, August 1, 2003, at 12:41 AM, John W. Long wrote:

filename = __FILE__
line = __LINE__

Why not $deferr ? Or has that distinction been lost now?

Personally I’d like a way for this logging module to let you easily log to a
file, say, without interfering with stderr; with separate objects logging to
separate files. And I’d also like timestamps. The one I knocked together is
a mixin:

module Logger
private
def setlog(log=nil,timestamp=nil)
if log.nil?
@logger_proc = proc { |str| $stderr.puts(str) }
elsif log.is_a? Proc
@logger_proc = log
elsif log.is_a? String
@logger_proc = proc { |str| File.open(log,“a”) { |f| f.puts(str) } }
elsif log == false
@logger_proc = proc { }
elsif log.respond_to? :puts
@logger_proc = proc { |str| log.puts(str) }
else
raise TypeError, “#{log.class} is not suitable for setlog”
end
@logger_ts = timestamp
@logger_ts = "%b %d %H:%M:%S " if @logger_ts == true
end

def log(str)
@logger_proc ||= proc { |str| $stderr.puts(str) }
if @logger_ts
@logger_proc.call( Time.now.strftime(@logger_ts) + str )
else
@logger_proc.call( str )
end
end

def debug(str)
log(str) if $DEBUG
end
end

So you can use it like this:

class Foo
include Logger
def initialize
setlog(“/tmp/logout”, true)
end
def run
log “hello”
end
end
Foo.new.run

which logs:

Aug 01 12:46:16 hello

Note that you can also pass in an arbitary IO or Proc object for logging.

Regards,

Brian.

···

On Fri, Aug 01, 2003 at 01:23:44PM +0900, Yukihiro Matsumoto wrote:

Hello,

In message “ANN: debugprint” > on 03/08/01, Ben Giddings ben@thingmagic.com writes:

Growing out of the discussions about $DEBUG and $VERBOSE, and how
they’re set from the commandline, I’ve created a dead-simple
“debugprint” library package. You can find it on RAA at:

How about direct messages to $stderr?

Moin!

So, some questions:

  1. is it possible for a method to get access to the context that called
    it so it can fill in things like source file name, method name, and
    line number
    This might help a little:
    filename = FILE
    line = LINE
    not sure about the rest

def get_method_name
if md = /in `(.*?)'/.match(caller[0])
md[1]
end
end

method_name = get_method_name

Regards,
flgr

caller(1).first - although it will return a string, so that may need
some interpretation, or if it is only for debuging, it might just do.

TTFN,

Geoff.

···

On Fri, Aug 01, 2003 at 02:10:12PM +0900, Ben Giddings wrote:

On Friday, August 1, 2003, at 12:41 AM, John W. Long wrote:

filename = FILE line = LINE

Yeah, only unless it’s in a macro, those will always give the file and
line of “fancydebugprint”, where the method is defined, right? I want
the ones one stack level up – something that’s easy with a macro but
I’m not sure how to do it here.

Hi –

···

On Fri, 1 Aug 2003, Ben Giddings wrote:

On Friday, August 1, 2003, at 12:23 AM, Yukihiro Matsumoto wrote:

How about direct messages to $stderr?

Actually, how about debug() goes to $stderr and info() goes to $stdout.
People mostly tend to do:

puts(“doing blah”) if $VERBOSE

rather than

$stderr.puts(“doing blah”) if $VERBOSE

Don’t they? Any opinions?

See Brian’s answer for something more in-depth :slight_smile: But I’d say
avoiding $stdout is a good idea. You might be directing output
to a file or network client. I’ve even come across cases where
I was told that STDOUT was not open for writing – can’t
remember exactly when or why, though.

David


David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Very nice Brian. Can I use this code?

···

In message “ANN: debugprint” >> on 03/08/01, Ben Giddings ben@thingmagic.com writes:

Growing out of the discussions about $DEBUG and $VERBOSE, and how
they’re set from the commandline, I’ve created a dead-simple
“debugprint” library package. You can find it on RAA at:

How about direct messages to $stderr?

Why not $deferr ? Or has that distinction been lost now?

Personally I’d like a way for this logging module to let you easily log to a
file, say, without interfering with stderr; with separate objects logging to
separate files. And I’d also like timestamps. The one I knocked together is
a mixin:

module Logger
private
def setlog(log=nil,timestamp=nil)
if log.nil?
@logger_proc = proc { |str| $stderr.puts(str) }
elsif log.is_a? Proc
@logger_proc = log
elsif log.is_a? String
@logger_proc = proc { |str| File.open(log,“a”) { |f| f.puts(str) } }
elsif log == false
@logger_proc = proc { }
elsif log.respond_to? :puts
@logger_proc = proc { |str| log.puts(str) }
else
raise TypeError, “#{log.class} is not suitable for setlog”
end
@logger_ts = timestamp
@logger_ts = "%b %d %H:%M:%S " if @logger_ts == true
end

def log(str)
@logger_proc ||= proc { |str| $stderr.puts(str) }
if @logger_ts
@logger_proc.call( Time.now.strftime(@logger_ts) + str )
else
@logger_proc.call( str )
end
end

def debug(str)
log(str) if $DEBUG
end
end

So you can use it like this:

class Foo
include Logger
def initialize
setlog(“/tmp/logout”, true)
end
def run
log “hello”
end
end
Foo.new.run

which logs:

Aug 01 12:46:16 hello

Note that you can also pass in an arbitary IO or Proc object for logging.

Regards,

Brian.

Hi,

···

In message “Re: ANN: debugprint” on 03/08/01, Brian Candler B.Candler@pobox.com writes:

How about direct messages to $stderr?

Why not $deferr ? Or has that distinction been lost now?

Yes, it’s lost in the final 1.8.0.

						matz.

Very nice Brian. Can I use this code?

Be my guest - I’m very happy to have someone else host it, maintain it,
document it, and answer questions on it :slight_smile:

I just thought of a little improvement:

@logger_proc ||= proc { |str| $stderr.puts(str) }

can become

   @logger_proc ||= DEFAULT_LOGGER_PROC

with that constant defined earlier in the module.

The nice thing about defining it as a module, is that you can still get
global logging by including it at the top level:

require ‘/path/to/logger’
include Logger

log “hello world”

class Foo
def initialize
log “I am a new #{self.inspect}”
end
end
Foo.new
Foo.new

This logger does what I need at the moment, but I imagine another nice
feature would be to have multiple debug levels and be able to turn logging
on or off for those levels.

Regards,

Brian.

···

On Sat, Aug 02, 2003 at 12:51:02AM +0900, Michael Garriss wrote:

At which point you might consider using Log4r.

Gavin

···

On Saturday, August 2, 2003, 2:12:52 AM, Brian wrote:

[…]

This logger does what I need at the moment, but I imagine another nice
feature would be to have multiple debug levels and be able to turn logging
on or off for those levels.