Problem
I currently have a logging setup that looks like this:
require 'active_support'
require 'singleton'
class Worker
def initialize(logger)
@logger = logger
end
def perform
@logger.with_context(["tag1"], "Started work")
Provider.say_hello
end
end
class Vlogger
include Singleton
attr_accessor :logger
def logger
@logger ||= ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
end
def with_context(tags, msg)
@logger.tagged(*tags) { @logger.info msg }
end
end
class Provider
def self.logger
Vlogger.instance
end
def self.say_hello
logger.with_context(["tag2"], "hello")
end
end
v = Vlogger.instance
v.logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
Worker.new(v).perform
My objective with this is to avoid having to pass around the @logger
instance variable found in my Worker class. Ideally, I want the Vlogger class to be available to all classes. I’m finding that I’m having to use this pattern quite a bit in my code:
def self.logger
Vlogger.instance
end
Is there a better way to do this? Is my OO design pattern here inherently flawed? Ideally I’m trying to avoid passing around objects when really the object has no state and it should be available to various classes without introducing class or instance methods. Thoughts?
Solution
You might be better off just using a module with some static methods, e.g.:
module Vlogger
class << self
def logger
@logger ||= ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
end
def with_context(tags, message)
logger.tagged(*tags) { logger.info message }
end
end
end
Add attribute access as needed.
Now you can simply call Vlogger.with_context
directly when you need it without having to use instance
or otherwise keeping a reference to things elsewhere.
class Worker
def perform
Vlogger.with_context(["tag1"], "Started work")
Provider.say_hello
end
end
class Provider
def self.say_hello
Vlogger.with_context(["tag2"], "hello")
end
end
It’s an option, at least.