rubyloggingpapertrail-app

how can I change logger settings based on ENV variable in ruby using logger?


I have set up the following using this: Ruby - share logger instance among module/classes

EDIT: Based on the comments below, I updated the code but still have issues logging.

module Logging

  # in classes needing to be logged use 'include Logger'
  require 'logger'
  require 'remote_syslog_logger'
  require_relative 'env'

  class << self
    def logger

      return @logger if @logger

      if ENV['ENVIRONMENT'] == 'production' #may need to change this

        @logger ||= Logger.new($stdout)

        @logger.level = Logger::WARN
        @logger.datetime_format = "%N "

      elsif ENV['ENVIRONMENT'] == 'development'

        binding.pry

        #$logger = Logger.new(STDOUT)
        @logger = RemoteSyslogLogger.new('logs2.papertrailapp.com',39257)
        @logger.level = Logger::DEBUG
        @logger.datetime_format = "%N "

      end 

    end

    def logger=(logger)
      @logger = logger
    end
  end

  # Addition
  def self.included(base)
    class << base
      def logger
        Logging.logger
      end
    end
  end

  def logger
    Logging.logger
  end


end

How I log:

class CronCheck
  require_relative 'module_logger.rb'
  include Logging

  def self.run
    begin
      logger.debug "**** running cron_check_schedule.rb #{Time.now}  #{Time.now.to_i}****"
    rescue
  end
end

Question: How can I modify the module so that this type of logic can be defined once, and all I have to do is pass an ENV value for all the classes and methods to log in the same way?

I get an error at logger.debug: undefined method `debug' for "%N ":String


Solution

  • Your code is almost exactly right. What you need to do, though, is set Logging.logger, not $logger:

    def self.instantiate_logger
      logger = Logger.new(STDOUT)
      logger.datetime_format = "%N "
    
      if ENV['ENVIRONMENT'] == 'production'
        logger.level = Logger::WARN
      elsif ENV['ENVIRONMENT'] == 'development'
        logger.level = Logger::DEBUG
      end
    
      Logging.logger = logger
    end
    

    It's not clear from your question where this method lives, but it should be somewhere you can call it during your app's initialization.

    You'll notice that I removed the code related to Pry; since that code's not directly related to logging, it should probably go somewhere else.

    I would make one more improvement, though, which is to make it more declarative by putting the log levels in a hash keyed by their respective environments:

    LOG_LEVELS = {
      "production" => Logger::WARN,
      "development" => Logger::DEBUG
    }
    
    def self.instantiate_logger
      Logging.logger = Logger.new(STDOUT).tap do |logger|
        logger.datetime_format = "%N "
        logger.level = LOG_LEVELS[ENV['ENVIRONMENT']] || LOG_LEVELS["development"]
      end
    end