Get caller class

廉价感情. 提交于 2021-02-07 05:10:41

问题


I'm writing Logger and got problem with automatic adding class name, from which I called print_log method. For example something like this:

class Logger
  def self.print_log(string)
    puts Time.now.strftime('%T | ') + *caller_class_name_here* + ' - ' + string 
  end
end

class MyClass
  def initialize
    Logger.print_log 'called .new() method'
  end
end

As result of calling MyClass.new method I wanna see in output:

14:41:23 | MyClass - called .new() method

I'm sure it's possible to do using caller, but yet can't find how


回答1:


After futzing about with caller for a while, it's probably not going to do it for you, and neither is caller_locations. It's possible to track the classes of the last objects instantiated on the current thread, e.g.

class Class
  alias :_new :new
  def new *args
    Thread.current.thread_variable_set :classes, ((Thread.current.thread_variable_get(:classes) || []) << self).last(10)
    _new *args
  end
end

This retains the classes of the last 10 objects, but this isn't directly equivalent to a hierarchy e.g.

class X
  def initialize
    puts Thread.current.thread_variable_get(:classes)
  end
end

class Y
end

class Z
  def initialize
    @y = Y.new
    @x = X.new
  end
end

X.new outputs the following (in a console session)

RubyToken::TkNL
RubyToken::TkEND
RubyToken::TkNL
RubyToken::TkCONSTANT
RubyToken::TkDOT
RubyToken::TkIDENTIFIER
RubyToken::TkNL
Y
Z
X



回答2:


You can use module like that (Rails style):

module Loggable
  extend ActiveSupport::Concern

  def log_prefix
    @log_prefix ||= (self.class == Class ? "#{self.to_s}" : "#{self.class.to_s}").freeze
  end

  included do
    [:debug, :info, :warn, :error, :fatal].each do |level|
      define_method level do |str = nil|
        caller = caller_locations(1,1)[0].label
        prefix = "[#{log_prefix}##{caller}] "
        prefix << level.to_s.upcase[0]
        str = "#{prefix}: #{str}"
        puts str if ENV["DEBUG"]
        Rails.logger.send(level, str)
      end
    end
  end
end

and you code will be:

class MyClass
  include Loggable
  extend Loggable

  def instance_method
    debug "Hello"
  end

  def self.klass_method
    debug "Klass"
  end
end



回答3:


I am not sure if it is possible to get the class name like you want. I would create a logger instance for this to which you can pass in the class name when creating it.

class Logger
  def initialize(class_name)
    @class_name = class_name
  end

  def print_log(message)
    puts Time.now.strftime('%T | ') + @class_name + ' - ' + message
  end
end

class MyClass
  def initalize
    @logger = Logger.new self.class.name
    @logger.print_log 'called .new() method'
  end
end

More verbose than you would like maybe but explicit code that is easy to understand.

For any serious work I recommend using the standard library logger. You may have to wrap it in your own call to get the log messages as you want it but you'll get log rotating and file handling as it should be.



来源:https://stackoverflow.com/questions/19679969/get-caller-class

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!