1
0
Fork 0
mirror of https://github.com/mperham/sidekiq.git synced 2022-11-09 13:52:34 -05:00
mperham--sidekiq/lib/sidekiq/logger.rb
2019-09-25 15:34:47 -07:00

147 lines
3.6 KiB
Ruby

# frozen_string_literal: true
require "logger"
require "time"
module Sidekiq
module LogContext
def with_context(hash)
ctx.merge!(hash)
yield
ensure
hash.each_key { |key| ctx.delete(key) }
end
def ctx
Thread.current[:sidekiq_context] ||= {}
end
end
module LoggerThreadSafeLevel
LOG_LEVEL_MAP = Hash[Logger::Severity.constants.map { |c| [c.to_s, Logger::Severity.const_get(c)] }]
LOG_LEVEL_MAP.default_proc = proc do |_, level|
Sidekiq.logger.info("Invalid log level: #{level.inspect}")
nil
end
Logger::Severity.constants.each do |severity|
define_method("#{severity.downcase}?") do
Logger.const_get(severity) >= level
end
end
def local_level
Thread.current[:sidekiq_log_level]
end
def local_level=(level)
case level
when Integer
Thread.current[:sidekiq_log_level] = level
when Symbol, String
Thread.current[:sidekiq_log_level] = LOG_LEVEL_MAP[level.to_s.upcase]
when nil
Thread.current[:sidekiq_log_level] = nil
else
raise ArgumentError, "Invalid log level: #{level.inspect}"
end
end
def level
local_level || super
end
# Change the thread-local level for the duration of the given block.
def log_at(level)
old_local_level = local_level
self.local_level = level
yield
ensure
self.local_level = old_local_level
end
# Redefined to check severity against #level, and thus the thread-local level, rather than +@level+.
# FIXME: Remove when the minimum Ruby version supports overriding Logger#level.
def add(severity, message = nil, progname = nil, &block)
severity ||= UNKNOWN
progname ||= @progname
return true if @logdev.nil? || severity < level
if message.nil?
if block_given?
message = yield
else
message = progname
progname = @progname
end
end
@logdev.write \
format_message(format_severity(severity), Time.now, progname, message)
end
end
class Logger < ::Logger
include LogContext
include LoggerThreadSafeLevel
def initialize(*args)
super
self.formatter = Sidekiq.log_formatter
end
module Formatters
class Base < ::Logger::Formatter
def tid
Thread.current["sidekiq_tid"] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36)
end
def ctx
Thread.current[:sidekiq_context] ||= {}
end
def format_context
if ctx.any?
" " + ctx.compact.map { |k, v|
case v
when Array
"#{k}=#{v.join(",")}"
else
"#{k}=#{v}"
end
}.join(" ")
end
end
end
class Pretty < Base
def call(severity, time, program_name, message)
"#{time.utc.iso8601(3)} pid=#{::Process.pid} tid=#{tid}#{format_context} #{severity}: #{message}\n"
end
end
class WithoutTimestamp < Pretty
def call(severity, time, program_name, message)
"pid=#{::Process.pid} tid=#{tid}#{format_context} #{severity}: #{message}\n"
end
end
class JSON < Base
def call(severity, time, program_name, message)
hash = {
ts: time.utc.iso8601(3),
pid: ::Process.pid,
tid: tid,
lvl: severity,
msg: message,
}
c = ctx
hash["ctx"] = c unless c.empty?
Sidekiq.dump_json(hash) << "\n"
end
end
end
end
end