2010-01-06 33 views
6

我們有代碼在我們的Ruby 1.8.6 web應用程序中記錄數據。你大致這樣稱呼它:在Ruby中調用者模塊

$log.info("Some text here") 

現在,在記錄的輸出中,我想包括該行出現的模塊。我知道Kernel#caller會給我一個數組,在那裏我可以取出日誌行發生的文件和行號,但我不想那樣。我想要這個模塊,而不是文件名。顯而易見的解決方案是修改日誌行,使其如下所示:

$log.info("Some text here", self.class.name) 

然後解析結果。但是,這並不奏效,因爲我試圖在默認情況下提取這些信息。也就是說,如果程序員忘記指定模塊,即日誌行的第二個參數,我需要解決方案才能工作。

有沒有辦法做到這一點?如果不是的話,我只需要與caller陣列合作;我們大多數模塊都在不同的目錄中,所以這將是一個80%的解決方案。在文件foo.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 

:在文件log.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 
+0

我看不出如何做到這一點,除非將'self'或'binding'傳遞給記錄器對象。你必須用來自'caller'的信息解析文件,我相信你不想這樣做。 – 2010-01-07 18:33:14

回答

3

使用call_stack

先用RubyGems的安裝:

gem install call_stack 

然後換log.rb到:

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 

對我的作品(紅寶石1.8.7)。

$ ruby foo.rb 
Module: Foo::Bar Msg: I did something! 
+0

根據他們的網站,我們希望使用ruby-debug來代替,儘管鏈接顯示爲中斷。它還指出,這涉及大幅減速。事實上,它甚至可能不起作用。儘管如此,迄今爲止最好的解決方案,所以我+ 1'這個答案。謝謝。 – ChrisInEdmonton 2010-01-08 01:59:28

+0

這裏是ruby-debug:http://rubyforge.org/projects/ruby-debug/,是的,它會很慢。 Ruby對callstack檢查的默認支持是可悲的,並且有很多改進它的建議,所以你得到的只是Kernel#調用者。任何解決方案要麼涉及跟蹤或使用C API,所以我代表了似乎是最簡單的一個。我建議,如果你真的需要這個功能,你可以執行一個編碼約定,並且總是讓程序員在調用時指定模塊(沒有默認值)。不方便,但速度很快。或者,您可以在不調試時關閉call_stack。 – 2010-01-08 19:39:37

2

遇到這篇文章時,爲我自己的目的尋找答案。

沒有找到合適的代碼,所以我通過Ruby源代碼挖掘了一個擴展。我已經捆綁它作爲一個偕應該安裝沒有任何問題,只要您使用的1.9.1:

sudo的創業板安裝發件人

不會使用Ruby 1.8的工作因爲1.8具有跟蹤幀的不同模型。

http://rubygems.org/gems/sender

3

一個mixin解決了OP的具體要求(同時+1到灰粉解決「誰給我打電話」情況下,通用的吧!)。

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