2017-04-17 30 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