ANN: debugprint

B

Ben Giddings

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. :)

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
 
Y

Yukihiro Matsumoto

Hello,

In message "ANN: debugprint"

|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.
 
B

Brian Candler

Hello,

In message "ANN: debugprint"

|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.
 
M

Michael Garriss

Very nice Brian. Can I use this code?
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.
 
B

Brian Candler

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 :)

I just thought of a little improvement:

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.
 
F

Florian Groß

Moin!
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,792
Messages
2,569,639
Members
45,353
Latest member
RogerDoger

Latest Threads

Top