2017-04-17 47 views
1

我喜歡記錄很多。在我的Rails應用我有很多的類似的方法:如何分離功能和登錄紅寶石方法

def my_method(argument1:, argument2:) 
    logger.info "Starting my_method with arguments: #{argument1} and #{argument2}" 
    result = argument1 + argument2 
    logger.info "Finished my_method with result: #{result}" 
end 

如何分離的功能和方法的記錄?

理想的結果會是這個樣子(借用Rails的回調概念只是作爲一個例子):

before_method: :my_method_log_start, only: :my_method 
after_method: :my_method_log_end, only: :my_method 

def my_method(argument1:, argument2:) 
    result = argument1 + argument2 
end 

private 

def my_method_log_start 
    logger.info "Starting my_method with arguments: #{argument1} and #{argument2}" 
end 

def my_method_log_end 
    logger.info "Finished my_method with result: #{result}" 
end 

我知道這是代碼行方面效率較低,它更可讀(我的想法是)。

我已閱讀關於Aspect Orient Programming以及Aquarius等寶石的一些內容,但看起來像是一種矯枉過正的做法,只是爲了記錄而添加了新的範例。

+4

有[性能開銷(http://guides.rubyonrails.org/debugging_rails_applications.html#impact-of-logs-on-performance)還加入了一堆日誌語句 - 我建議你學習如何使用調試器或寫測試,而不是依靠日誌作爲糟糕技術的柺杖。 – max

回答

3

我認爲Avdi Grimm對您可以使用的技術有很好的解釋。這個想法是提取日誌(或其他東西)監聽器類和事件發佈到該偵聽器,基本的例子是

class Task 
    # ... 
    def add_listener(listener) 
    (@listeners ||= []) << listener 
    end 
    # ... 

    def notify_listeners(event_name, *args) 
    @listeners && @listeners.each do |listener| 
     if listener.respond_to?(event_name) 
     listener.public_send(event_name, self, *args) 
     end 
    end 
    end 
end 

和做某事像

task = Task.new 
task.add_lestener(YourLoggerClass.new) 
task.notify_listeners(:start_logging) 
task.notify_listeners(:end_logging) 
+0

基本上是[觀察者模式](https://en.wikipedia.org/wiki/Observer_pattern) – max

2

如果這是僅用於本地調試,它是TracePoint類的良好用例。這裏是代碼:

tp1 = TracePoint.new do |tp| 
    if tp.event == :call 
    method = tp.defined_class.method(tp.method_id) 
    arguments = method.parameters.map do |param| 
     "#{param[1]}: #{tp.binding.local_variable_get(param[1])}" 
    end.join(", ") 
    puts "Starting #{tp.method_id} with arguments #{arguments}" 
    elsif tp.event.to_s == "return" 
    puts "Finished #{tp.method_id} with result: #{tp.return_value}" 
    end 
end 

tp1.enable 

def my_method1(a, b) 
    a + b 
end 

puts my_method1(2, 3) 

我推薦閱讀這個類的文檔,它有非常好的功能。當然,你需要修改這些代碼來處理一些邊緣情況。您可以添加一些過濾器來僅爲您關心的方法調用跟蹤塊。或者您可以根據代碼的某些部分啓用/禁用此功能。

0

你可以通過它的名稱調用方法,或者將它轉換爲proc並傳遞給另一個方法。所以,你可以寫這樣的事情:

def foo(a, b) 
    a + b 
end 

def call_with_logging(method_name, *args) 
    args_as_string = args.map(&:to_s).join(' ') 
    puts "Starting my_method with arguments #{args_as_string}" 
    result = Object.send(method_name, *args) 
    puts "Finished my_method with result: #{result}" 
end 

call_with_logging :foo, 1, 2