2011-07-15 29 views
0

以下是Log4r中的一些現有日誌記錄代碼的工作方式。正如你可以在WorkerX :: a_method中看到的那樣,每當我記錄一條消息時,我都希望包含類名和調用方法(我不希望所有的調用者歷史或任何其他噪聲,這是我的目的LgrHelper)。使用Log4r進行上下文記錄

class WorkerX 

    include LgrHelper 

    def initialize(args = {}) 
    @logger = Lgr.new({:debug => args[:debug], :logger_type => 'WorkerX'}) 
    end 

    def a_method 
    error_msg("some error went down here") 
    # This prints out: "WorkerX::a_method - some error went down here" 
    end 

end 


class Lgr 
    require 'log4r' 
    include Log4r 

    def initialize(args = {}) # args: debug boolean, logger type 
    @debug = args[:debug] 
    @logger_type = args[:logger_type] 

    @logger = Log4r::Logger.new(@logger_type) 
    format = Log4r::PatternFormatter.new(:pattern => "%l:\t%d - %m") 
    outputter = Log4r::StdoutOutputter.new('console', :formatter => format) 
    @logger.outputters = outputter 

    if @debug then 
     @logger.level = DEBUG 
    else 
     @logger.level = INFO 
    end 
    end 

    def debug(msg) 
    @logger.debug(msg) 
    end 

    def info(msg) 
    @logger.info(msg) 
    end 

    def warn(msg) 
    @logger.warn(msg) 
    end 

    def error(msg) 
    @logger.error(msg) 
    end 

    def level 
    @logger.level 
    end 

end 


module LgrHelper 

    # This module should only be included in a class that has a @logger instance variable, obviously. 

    protected 

    def info_msg(msg) 
    @logger.info(log_intro_msg(self.method_caller_name) + msg) 
    end 

    def debug_msg(msg) 
    @logger.debug(log_intro_msg(self.method_caller_name) + msg) 
    end 

    def warn_msg(msg) 
    @logger.warn(log_intro_msg(self.method_caller_name) + msg) 
    end 

    def error_msg(msg) 
    @logger.error(log_intro_msg(self.method_caller_name) + msg) 
    end 

    def log_intro_msg(method) 
    msg = class_name 
    msg += '::' 
    msg += method 
    msg += ' - ' 

    msg 
    end 

    def class_name 
    self.class.name 
    end 

    def method_caller_name 
    if /`(.*)'/.match(caller[1]) then # caller.first 
     $1 
    else 
     nil 
    end 
    end 

end 

我真的不喜歡這種方法。我寧願使用現有的@logger實例變量來打印消息,並且足夠聰明以瞭解上下文。如何做到這一點或者類似的簡單方法?

我的環境是Rails 2.3.11(現在!)。

回答

1

發佈使用extend我的回答後,(請參閱「編輯」,下同),我想我會嘗試使用set_trace_func保持一種堆棧跟蹤的像我張貼的討論。這是我的最終解決方案;調用set_trace_proc將被放入初始化程序或類似程序中。

#!/usr/bin/env ruby 

# Keep track of the classes that invoke each "call" event 
# and the method they called as an array of arrays. 
# The array is in the format: [calling_class, called_method] 
set_trace_func proc { |event, file, line, id, bind, klass| 
    if event == "call" 
    Thread.current[:callstack] ||= [] 
    Thread.current[:callstack].push [klass, id] 
    elsif event == "return" 
    Thread.current[:callstack].pop 
    end 
} 

class Lgr 
    require 'log4r' 
    include Log4r 

    def initialize(args = {}) # args: debug boolean, logger type 
    @debug = args[:debug] 
    @logger_type = args[:logger_type] 

    @logger = Log4r::Logger.new(@logger_type) 
    format = Log4r::PatternFormatter.new(:pattern => "%l:\t%d - %m") 
    outputter = Log4r::StdoutOutputter.new('console', :formatter => format) 
    @logger.outputters = outputter 

    if @debug then 
     @logger.level = DEBUG 
    else 
     @logger.level = INFO 
    end 
    end 

    def debug(msg) 
    @logger.debug(msg) 
    end 

    def info(msg) 
    @logger.info(msg) 
    end 

    def warn(msg) 
    @logger.warn(msg) 
    end 

    def error(msg) 
    @logger.error(msg) 
    end 

    def level 
    @logger.level 
    end 

    def invoker 
    Thread.current[:callstack] ||= [] 
    (Thread.current[:callstack][-2] || ['Kernel', 'main']) 
    end 
end 

class CallingMethodLogger < Lgr 
    [:info, :debug, :warn, :error].each do |meth| 
    define_method(meth) { |msg| super("#{invoker[0]}::#{invoker[1]} - #{msg}") } 
    end 
end 

class WorkerX 
    def initialize(args = {}) 
    @logger = CallingMethodLogger.new({:debug => args[:debug], :logger_type => 'WorkerX'}) 
    end 

    def a_method 
    @logger.error("some error went down here") 
    # This prints out: "WorkerX::a_method - some error went down here" 
    end 
end 

w = WorkerX.new 
w.a_method 

我不知道有多少,如果有的話,該PROC的通話將影響應用程序的性能;如果它最終成爲一個問題,或許不像調用類的智能(比如我下面的舊答案)會更好。

[編輯:下面是我的老答案,上面提到的。]

有關使用extend如何?這裏有一個我的代碼放在一起的快速而骯髒的腳本來測試它;我不得不重新安排事情,以避免錯誤,但代碼與LgrHelper例外(我改名爲CallingMethodLogger)和WorkerX的初始化函數的第二行是相同的:

#!/usr/bin/env ruby 

module CallingMethodLogger 
    def info(msg) 
    super("#{@logger_type}::#{method_caller_name} - " + msg) 
    end 

    def debug(msg) 
    super("#{@logger_type}::#{method_caller_name} - " + msg) 
    end 

    def warn(msg) 
    super("#{@logger_type}::#{method_caller_name} - " + msg) 
    end 

    def error(msg) 
    super("#{@logger_type}::#{method_caller_name} - " + msg) 
    end 

    def method_caller_name 
    if /`(.*)'/.match(caller[1]) then # caller.first 
     $1 
    else 
     nil 
    end 
    end 
end 

class Lgr 
    require 'log4r' 
    include Log4r 

    def initialize(args = {}) # args: debug boolean, logger type 
    @debug = args[:debug] 
    @logger_type = args[:logger_type] 

    @logger = Log4r::Logger.new(@logger_type) 
    format = Log4r::PatternFormatter.new(:pattern => "%l:\t%d - %m") 
    outputter = Log4r::StdoutOutputter.new('console', :formatter => format) 
    @logger.outputters = outputter 

    if @debug then 
     @logger.level = DEBUG 
    else 
     @logger.level = INFO 
    end 
    end 

    def debug(msg) 
    @logger.debug(msg) 
    end 

    def info(msg) 
    @logger.info(msg) 
    end 

    def warn(msg) 
    @logger.warn(msg) 
    end 

    def error(msg) 
    @logger.error(msg) 
    end 

    def level 
    @logger.level 
    end 
end 

class WorkerX 
    def initialize(args = {}) 
    @logger = Lgr.new({:debug => args[:debug], :logger_type => 'WorkerX'}) 
    @logger.extend CallingMethodLogger 
    end 

    def a_method 
    @logger.error("some error went down here") 
    # This prints out: "WorkerX::a_method - some error went down here" 
    end 
end 

w = WorkerX.new 
w.a_method 

輸出是:

ERROR: 2011-07-24 20:01:40 - WorkerX::a_method - some error went down here 

缺點是,通過這種方法,調用者的類名不會自動計算出來;它基於@logger_type明確傳入Lgr實例。但是,您可能可以使用其他方法獲取課程的實際名稱 - 可能類似call_stack gem或使用Kernel#set_trace_func - 請參閱this thread

+0

這是一些漂亮的東西!奇蹟般有效 – keruilin

相關問題