2012-05-15 22:44:35 -04:00
|
|
|
require 'time'
|
|
|
|
require 'logger'
|
|
|
|
|
|
|
|
module Sidekiq
|
|
|
|
module Logging
|
|
|
|
|
|
|
|
class Pretty < Logger::Formatter
|
2014-12-30 16:01:30 -05:00
|
|
|
SPACE = " "
|
|
|
|
|
2012-05-15 22:44:35 -04:00
|
|
|
# Provide a call() method that returns the formatted message.
|
|
|
|
def call(severity, time, program_name, message)
|
2014-06-20 11:27:47 -04:00
|
|
|
"#{time.utc.iso8601(3)} #{::Process.pid} TID-#{Thread.current.object_id.to_s(36)}#{context} #{severity}: #{message}\n"
|
2012-05-15 22:44:35 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def context
|
|
|
|
c = Thread.current[:sidekiq_context]
|
2014-12-30 16:01:30 -05:00
|
|
|
" #{c.join(SPACE)}" if c && c.any?
|
2012-05-15 22:44:35 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-06-10 13:09:48 -04:00
|
|
|
class WithoutTimestamp < Pretty
|
|
|
|
def call(severity, time, program_name, message)
|
|
|
|
"#{::Process.pid} TID-#{Thread.current.object_id.to_s(36)}#{context} #{severity}: #{message}\n"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-05-15 22:44:35 -04:00
|
|
|
def self.with_context(msg)
|
2014-12-30 16:01:30 -05:00
|
|
|
Thread.current[:sidekiq_context] ||= []
|
|
|
|
Thread.current[:sidekiq_context] << msg
|
2014-12-30 15:51:36 -05:00
|
|
|
yield
|
|
|
|
ensure
|
2014-12-30 16:01:30 -05:00
|
|
|
Thread.current[:sidekiq_context].pop
|
2012-05-15 22:44:35 -04:00
|
|
|
end
|
|
|
|
|
2012-12-12 14:27:27 -05:00
|
|
|
def self.initialize_logger(log_target = STDOUT)
|
2014-03-19 20:11:12 -04:00
|
|
|
oldlogger = defined?(@logger) ? @logger : nil
|
2012-12-12 14:27:27 -05:00
|
|
|
@logger = Logger.new(log_target)
|
|
|
|
@logger.level = Logger::INFO
|
2015-06-10 13:09:48 -04:00
|
|
|
@logger.formatter = ENV['DYNO'] ? WithoutTimestamp.new : Pretty.new
|
2013-06-18 16:44:19 -04:00
|
|
|
oldlogger.close if oldlogger && !$TESTING # don't want to close testing's STDOUT logging
|
2012-12-12 14:27:27 -05:00
|
|
|
@logger
|
2012-12-11 06:32:22 -05:00
|
|
|
end
|
|
|
|
|
2012-05-15 22:44:35 -04:00
|
|
|
def self.logger
|
2014-03-19 20:11:12 -04:00
|
|
|
defined?(@logger) ? @logger : initialize_logger
|
2012-05-15 22:44:35 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.logger=(log)
|
|
|
|
@logger = (log ? log : Logger.new('/dev/null'))
|
|
|
|
end
|
|
|
|
|
2014-02-07 16:27:35 -05:00
|
|
|
# This reopens ALL logfiles in the process that have been rotated
|
|
|
|
# using logrotate(8) (without copytruncate) or similar tools.
|
|
|
|
# A +File+ object is considered for reopening if it is:
|
|
|
|
# 1) opened with the O_APPEND and O_WRONLY flags
|
|
|
|
# 2) the current open file handle does not match its original open path
|
|
|
|
# 3) unbuffered (as far as userspace buffering goes, not O_SYNC)
|
|
|
|
# Returns the number of files reopened
|
|
|
|
def self.reopen_logs
|
|
|
|
to_reopen = []
|
2014-02-07 17:54:49 -05:00
|
|
|
append_flags = File::WRONLY | File::APPEND
|
|
|
|
|
|
|
|
ObjectSpace.each_object(File) do |fp|
|
|
|
|
begin
|
|
|
|
if !fp.closed? && fp.stat.file? && fp.sync && (fp.fcntl(Fcntl::F_GETFL) & append_flags) == append_flags
|
|
|
|
to_reopen << fp
|
|
|
|
end
|
|
|
|
rescue IOError, Errno::EBADF
|
|
|
|
end
|
|
|
|
end
|
2014-02-07 16:27:35 -05:00
|
|
|
|
2014-02-07 17:54:49 -05:00
|
|
|
nr = 0
|
2014-02-07 16:27:35 -05:00
|
|
|
to_reopen.each do |fp|
|
|
|
|
orig_st = begin
|
|
|
|
fp.stat
|
|
|
|
rescue IOError, Errno::EBADF
|
|
|
|
next
|
|
|
|
end
|
|
|
|
|
|
|
|
begin
|
|
|
|
b = File.stat(fp.path)
|
|
|
|
next if orig_st.ino == b.ino && orig_st.dev == b.dev
|
|
|
|
rescue Errno::ENOENT
|
|
|
|
end
|
|
|
|
|
|
|
|
begin
|
|
|
|
File.open(fp.path, 'a') { |tmpfp| fp.reopen(tmpfp) }
|
|
|
|
fp.sync = true
|
|
|
|
nr += 1
|
|
|
|
rescue IOError, Errno::EBADF
|
|
|
|
# not much we can do...
|
|
|
|
end
|
|
|
|
end
|
|
|
|
nr
|
2014-04-22 00:03:08 -04:00
|
|
|
rescue RuntimeError => ex
|
|
|
|
# RuntimeError: ObjectSpace is disabled; each_object will only work with Class, pass -X+O to enable
|
|
|
|
puts "Unable to reopen logs: #{ex.message}"
|
2014-02-07 16:27:35 -05:00
|
|
|
end
|
|
|
|
|
2012-05-15 22:44:35 -04:00
|
|
|
def logger
|
|
|
|
Sidekiq::Logging.logger
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|