Ruby singleton for logging

Posted on

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.

Leave a Reply

Your email address will not be published. Required fields are marked *