Getting module of caller in Ruby
We have code to log data in our Ruby 1.8.6 web application. You call it roughly as follows:
$log.info("Some text here")
Now, in the logged output, I would like to include the module where that line appeared. I know that the Kernel#caller
will give me an array where I can pull out the file and line number that the log line occurred, but I don't want that. I want the module, not the file name. The obvious solution is to modify the log line so that it reads like:
$log.info("Some text here", self.class.name)
and then parse the result. That's not going to work, though, because I am trying to extract this information in the default case. That is, I need the solution to work if the programmer forgot to specify the module, the second parameter to the log line.
Is there any way to do this? If not, I will just have to make do with the caller
array; most of our modules are in separate directories, so this would be an 80% solution.
More comple开发者_开发问答te example, please excuse minor syntax errors:
in file log.rb:
module Log
class Logger
def info(msg, mod = '')
puts "Module: #{mod} Msg: #{msg}"
end
end # class Logger
end # module Log
$log = Log::Logger.new
in file foo.rb:
module Foo
class Bar
def do_something
# Do not pass in self.class.name.
# We want the output to look like:
# Module: Foo Msg: I did something!
$log.info "I did something!"
end
end # class Bar
end #module Foo
Use call_stack.
First install it with RubyGems:
gem install call_stack
Then change log.rb to:
require 'rubygems'
require 'call_stack'
call_stack_on
module Log
class Logger
def info(msg, mod = '')
mod = call_stack(2)[0][0] if mod == ''
puts "Module: #{mod} Msg: #{msg}"
end
end # class Logger
end # module Log
$log = Log::Logger.new
Works for me (Ruby 1.8.7).
$ ruby foo.rb
Module: Foo::Bar Msg: I did something!
A mixin solves the OP's specific requirements (meanwhile, +1 to Asher for solving the generic "who called me" case!).
module Log
module Logger
def info(msg)
puts "Module: #{self} Msg: #{msg}"
end
end # class Logger
end # module Log
module Foo
class Bar
include Log::Logger
def do_something
# Do not pass in self.class.name.
# We want the output to look like:
# Module: Foo Msg: I did something!
info "I did something!"
end
end # class Bar
end # module Foo
foobar = Foo::Bar.new
foobar.do_something
Came across this post while looking for an answer for my own purposes.
Didn't find one that was appropriate, so I dug through the Ruby source and put together an extension. I've bundled it as a gem- should install without any problem so long as you are using Ruby 1.9.1:
sudo gem install sender
This will not work with Ruby 1.8, as 1.8 has a different model for tracking frames.
http://rubygems.org/gems/sender
精彩评论