5

I want to have separate logs for my app. I created the following module:

module MyApp
  module MyLog
    def self.included(base)
      base.extend(ClassMethods)
    end

    module ClassMethods
      def logger
        @@logger ||= Logger.new("#{Rails.root}/log/#{self.name.underscore}.log")
      end
    end
  end
end

Then, in any of my models, I can add:

include MyApp::MyLog

and use it as (log file will appear in .../log/cat.log):

Cat.logger.info 'test'

I tried to use this method included on Cat and Dog models, and I have this result:

Cat.new.logger
# => #<Logger:0x007fe4516cf0b0 @progname=nil, ... @dev=#<File:/.../log/cat.log>, ... 
Dog.new.logger
# => #<Logger:0x007fe4516cf0b0 @progname=nil, ... @dev=#<File:/.../log/cat.log>, ... (the same)

If I try to use my logger for Dog model first, I will have a log file with the name dog (/dog.log).

How can I set class variable @@logger from a module for each class with the correct initialized logger?

sawa
  • 165,429
  • 45
  • 277
  • 381
Mr. Rails
  • 89
  • 6

1 Answers1

4

Do not use class variable, use instance_variable that is attached to the class.

module MyApp
  module MyLog

    def self.included(base)
      base.extend(ClassMethods)
    end

    module ClassMethods
      def logger
        @logger ||= Logger.new("#{Rails.root}/log/#{self.name.underscore}.log")
      end
    end

  end
end

Example:

module A
  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods

    def logger
      puts @logger
      @logger ||= name
    end
  end
end

class B
  include A
end

class C
  include A
end

B.logger
#
B.logger
# B
C.logger
#
B.logger
# B
C.logger
# C

First time you call the method it is nil, thus the empty line, second time you call method the value equals to class name, B, and if called on new class it is again nil, check also this answer

Ruby class instance variable vs. class variable

Community
  • 1
  • 1
Nermin
  • 6,118
  • 13
  • 23