emas
emas

Reputation: 666

Different log level for Sidekiq workers - Ruby approach?

I have a running environment with a Rails application, Sidekiq and clockwork mod for scheduling purposes.

I have many different workers, filled with logger.debug and logger.info instructions, and I occasionally need to activate debug logging on some of them to know what's going on. I like the Sidekiq logger, and I would like to utilize it because it just need a "logger.debug" instruction in the workers to do its job.

What I miss with my current setup is the possibility to activate the DEBUG level for some workers, while leaving the others in standard INFO.

Now in each of my workers I have this initialize method:

class SendMailOnStart

   include Sidekiq::Worker
   sidekiq_options :retry => false, :queue => :critical

    def initialize
      logger.level = Logger::INFO
    end

    .... ...

But if a change the level in one worker, this level will be overwritten by the level specified in the next one - e.g. if two workers are processed together, the second one will "win".

What's the best way to achieve this in an elegant way?

Coming from Java world, I can think only to create a custom logger and putting it in each worker, copying output format used by Sidekiq logger, adding a logger method in each worker like

def logger
  logger = MyLogger.new
end

and changing the level when I neeed it in initialize method

Is this the best approach in Ruby?

Upvotes: 1

Views: 6004

Answers (2)

gphil
gphil

Reputation: 149

I had a similar question and I found this thread more useful:

Log to different logger based on call from Sidekiq or Rails

You should be able set the log level for Sidekiq workers specifically in the block mentioned there by altering Rails.logger.

Upvotes: 1

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

I have no clue if that’s the best approach, but I would do the following. First of all, let’s prepare the function to retrieve the caller’s filename and/or method:

  def parse_caller
    # magic number 7 below is the amount of calls 
    #   on stack to unwind to get your caller
    if /^(?<file>.+?):(?<line>\d+)(?::in `(?<method>.*)')?/ =~ caller(7).first
      file      = Regexp.last_match[:file]
      line      = Regexp.last_match[:line].to_i
      method    = Regexp.last_match[:method]
      [file, line, method]
    end
  end

Then I would override the default formatter of Logger instance, compelling it to check the caller:

  logger.formatter = lambda do |severity, datetime, progname, msg|
    f,l,m = parse_caller
    # HERE GOES YOUR CHECK
    if f =~ /…/
      …
    end
  end

I know it looks a weird hack, but it works fine for me.

Upvotes: 0

Related Questions