mirror of
https://github.com/mperham/sidekiq.git
synced 2022-11-09 13:52:34 -05:00
JSON Logger Formatter (#4050)
* Check Config File Existence (#4054) * Check config file existence * Eager config file check * Parse expanded path to default sidekiq.yml config file in Rails app * Cleanup * Add minitest-around * Extract context from formatter * Add JSON logger formatter * Adjust job logger to handle elapsed time within context * Add tid test * Rename processor logger * Enforce global state reset in logging tests * Add warning about upcoming refactoring to Sidekiq::Logging * Replace around hook with explicit stub inside test It's implemented with fibers, which means Thread.current returns different values in JRuby. * Fix typo * Concise JSON formatter keys * Add logger_formatter option * Shift context from array of strings to hash Allows more flexibly format context in the different formatters. * Adjust warning message regarding context type change * Add "Formatter" suffix to classes * Fix CLI specs * Replace Sidekiq::Logging with Sidekiq::Logger * Namespace logger formatters * Remove rails 4 appraisal
This commit is contained in:
parent
70216520c1
commit
3845832c20
15 changed files with 687 additions and 430 deletions
|
@ -1,8 +1,3 @@
|
||||||
appraise "rails-4" do
|
|
||||||
gem "rails", "~> 4.2"
|
|
||||||
gem 'activerecord-jdbcsqlite3-adapter', '< 50', platforms: :jruby
|
|
||||||
end
|
|
||||||
|
|
||||||
appraise "rails-5" do
|
appraise "rails-5" do
|
||||||
gem "rails", "~> 5.2"
|
gem "rails", "~> 5.2"
|
||||||
gem 'activerecord-jdbcsqlite3-adapter', '>= 50', platforms: :jruby
|
gem 'activerecord-jdbcsqlite3-adapter', '>= 50', platforms: :jruby
|
||||||
|
|
1
Gemfile
1
Gemfile
|
@ -14,6 +14,7 @@ end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem 'minitest'
|
gem 'minitest'
|
||||||
|
gem 'minitest-around'
|
||||||
gem 'minitest-focus'
|
gem 'minitest-focus'
|
||||||
gem 'minitest-reporters'
|
gem 'minitest-reporters'
|
||||||
gem 'simplecov'
|
gem 'simplecov'
|
||||||
|
|
|
@ -14,6 +14,7 @@ end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem "minitest"
|
gem "minitest"
|
||||||
|
gem "minitest-around"
|
||||||
gem "minitest-focus"
|
gem "minitest-focus"
|
||||||
gem "minitest-reporters"
|
gem "minitest-reporters"
|
||||||
gem "simplecov"
|
gem "simplecov"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
require 'sidekiq/version'
|
require 'sidekiq/version'
|
||||||
fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.4.0." if RUBY_PLATFORM != 'java' && Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4.0')
|
fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.4.0." if RUBY_PLATFORM != 'java' && Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4.0')
|
||||||
|
|
||||||
require 'sidekiq/logging'
|
require 'sidekiq/logger'
|
||||||
require 'sidekiq/client'
|
require 'sidekiq/client'
|
||||||
require 'sidekiq/worker'
|
require 'sidekiq/worker'
|
||||||
require 'sidekiq/redis_connection'
|
require 'sidekiq/redis_connection'
|
||||||
|
@ -178,11 +178,16 @@ module Sidekiq
|
||||||
JSON.generate(object)
|
JSON.generate(object)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.logger
|
class << self
|
||||||
Sidekiq::Logging.logger
|
attr_accessor :logger_formatter
|
||||||
end
|
end
|
||||||
def self.logger=(log)
|
|
||||||
Sidekiq::Logging.logger = log
|
def self.logger
|
||||||
|
@logger ||= Sidekiq::Logger.new(STDOUT, level: Logger::INFO)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.logger=(logger)
|
||||||
|
@logger = logger
|
||||||
end
|
end
|
||||||
|
|
||||||
# How frequently Redis should be checked by a random Sidekiq process for
|
# How frequently Redis should be checked by a random Sidekiq process for
|
||||||
|
|
|
@ -8,8 +8,8 @@ require 'erb'
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
|
|
||||||
require 'sidekiq'
|
require 'sidekiq'
|
||||||
require 'sidekiq/util'
|
|
||||||
require 'sidekiq/launcher'
|
require 'sidekiq/launcher'
|
||||||
|
require 'sidekiq/util'
|
||||||
|
|
||||||
module Sidekiq
|
module Sidekiq
|
||||||
class CLI
|
class CLI
|
||||||
|
@ -339,16 +339,11 @@ module Sidekiq
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize_logger
|
def initialize_logger
|
||||||
Sidekiq::Logging.initialize_logger
|
|
||||||
|
|
||||||
Sidekiq.logger.level = ::Logger::DEBUG if options[:verbose]
|
Sidekiq.logger.level = ::Logger::DEBUG if options[:verbose]
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_config(cfile)
|
def parse_config(path)
|
||||||
opts = {}
|
opts = YAML.load(ERB.new(File.read(path)).result) || {}
|
||||||
if File.exist?(cfile)
|
|
||||||
opts = YAML.load(ERB.new(IO.read(cfile)).result) || opts
|
|
||||||
end
|
|
||||||
|
|
||||||
if opts.respond_to? :deep_symbolize_keys!
|
if opts.respond_to? :deep_symbolize_keys!
|
||||||
opts.deep_symbolize_keys!
|
opts.deep_symbolize_keys!
|
||||||
|
|
|
@ -1,25 +1,52 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Sidekiq
|
module Sidekiq
|
||||||
class JobLogger
|
class JobLogger
|
||||||
|
|
||||||
def call(item, queue)
|
def call(item, queue)
|
||||||
start = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
start = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
||||||
logger.info("start")
|
|
||||||
|
Sidekiq.logger.info("start")
|
||||||
|
|
||||||
yield
|
yield
|
||||||
logger.info("done: #{elapsed(start)} sec")
|
|
||||||
|
with_elapsed_time_context(start) do
|
||||||
|
Sidekiq.logger.info("done")
|
||||||
|
end
|
||||||
rescue Exception
|
rescue Exception
|
||||||
logger.info("fail: #{elapsed(start)} sec")
|
with_elapsed_time_context(start) do
|
||||||
|
Sidekiq.logger.info("fail")
|
||||||
|
end
|
||||||
|
|
||||||
raise
|
raise
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def with_job_hash_context(job_hash, &block)
|
||||||
|
Sidekiq.logger.with_context(job_hash_context(job_hash), &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def job_hash_context(job_hash)
|
||||||
|
# If we're using a wrapper class, like ActiveJob, use the "wrapped"
|
||||||
|
# attribute to expose the underlying thing.
|
||||||
|
{
|
||||||
|
class: job_hash['wrapped'] || job_hash["class"],
|
||||||
|
jid: job_hash['jid'],
|
||||||
|
bid: job_hash['bid']
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_elapsed_time_context(start, &block)
|
||||||
|
Sidekiq.logger.with_context(elapsed_time_context(start), &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def elapsed_time_context(start)
|
||||||
|
{ elapsed: "#{elapsed(start)} sec" }
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def elapsed(start)
|
def elapsed(start)
|
||||||
(::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start).round(3)
|
(::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start).round(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
def logger
|
|
||||||
Sidekiq.logger
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
70
lib/sidekiq/logger.rb
Normal file
70
lib/sidekiq/logger.rb
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'logger'
|
||||||
|
require 'time'
|
||||||
|
|
||||||
|
module Sidekiq
|
||||||
|
class Logger < ::Logger
|
||||||
|
|
||||||
|
def initialize(*args)
|
||||||
|
super
|
||||||
|
|
||||||
|
formatter_class = case Sidekiq.logger_formatter
|
||||||
|
when :json
|
||||||
|
Formatters::JSON
|
||||||
|
else
|
||||||
|
ENV['DYNO'] ? Formatters::WithoutTimestamp : Formatters::Pretty
|
||||||
|
end
|
||||||
|
|
||||||
|
self.formatter = formatter_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def tid
|
||||||
|
Thread.current['sidekiq_tid'] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36)
|
||||||
|
end
|
||||||
|
|
||||||
|
def context
|
||||||
|
Thread.current[:sidekiq_context] ||= {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_context(hash)
|
||||||
|
context.merge!(hash)
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
hash.keys.each { |key| context.delete(key) }
|
||||||
|
end
|
||||||
|
|
||||||
|
module Formatters
|
||||||
|
class Pretty < Logger::Formatter
|
||||||
|
def call(severity, time, program_name, message)
|
||||||
|
"#{time.utc.iso8601(3)} #{::Process.pid} TID-#{Sidekiq.logger.tid}#{format_context(Sidekiq.logger.context)} #{severity}: #{message}\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def format_context(context)
|
||||||
|
' ' + context.compact.map { |k, v| "#{k.upcase}=#{v}" }.join(' ') if context.any?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class WithoutTimestamp < Pretty
|
||||||
|
def call(severity, time, program_name, message)
|
||||||
|
"#{::Process.pid} TID-#{Sidekiq.logger.tid}#{format_context(Sidekiq.logger.context)} #{severity}: #{message}\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class JSON < Logger::Formatter
|
||||||
|
def call(severity, time, program_name, message)
|
||||||
|
Sidekiq.dump_json(
|
||||||
|
ts: time.utc.iso8601(3),
|
||||||
|
pid: ::Process.pid,
|
||||||
|
tid: Sidekiq.logger.tid,
|
||||||
|
ctx: Sidekiq.logger.context,
|
||||||
|
sev: severity,
|
||||||
|
msg: message
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,72 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
require 'time'
|
|
||||||
require 'logger'
|
|
||||||
|
|
||||||
module Sidekiq
|
|
||||||
module Logging
|
|
||||||
|
|
||||||
class Pretty < Logger::Formatter
|
|
||||||
SPACE = " "
|
|
||||||
|
|
||||||
# Provide a call() method that returns the formatted message.
|
|
||||||
def call(severity, time, program_name, message)
|
|
||||||
"#{time.utc.iso8601(3)} #{::Process.pid} TID-#{Sidekiq::Logging.tid}#{context} #{severity}: #{message}\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
def context
|
|
||||||
c = Thread.current[:sidekiq_context]
|
|
||||||
" #{c.join(SPACE)}" if c && c.any?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class WithoutTimestamp < Pretty
|
|
||||||
def call(severity, time, program_name, message)
|
|
||||||
"#{::Process.pid} TID-#{Sidekiq::Logging.tid}#{context} #{severity}: #{message}\n"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.tid
|
|
||||||
Thread.current['sidekiq_tid'] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.job_hash_context(job_hash)
|
|
||||||
# If we're using a wrapper class, like ActiveJob, use the "wrapped"
|
|
||||||
# attribute to expose the underlying thing.
|
|
||||||
klass = job_hash['wrapped'] || job_hash["class"]
|
|
||||||
bid = job_hash['bid']
|
|
||||||
"#{klass} JID-#{job_hash['jid']}#{" BID-#{bid}" if bid}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.with_job_hash_context(job_hash, &block)
|
|
||||||
with_context(job_hash_context(job_hash), &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.with_context(msg)
|
|
||||||
Thread.current[:sidekiq_context] ||= []
|
|
||||||
Thread.current[:sidekiq_context] << msg
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
Thread.current[:sidekiq_context].pop
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.initialize_logger
|
|
||||||
return @logger if defined?(@logger)
|
|
||||||
@logger = Logger.new(STDOUT)
|
|
||||||
@logger.level = Logger::INFO
|
|
||||||
@logger.formatter = ENV['DYNO'] ? WithoutTimestamp.new : Pretty.new
|
|
||||||
@logger
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.logger
|
|
||||||
defined?(@logger) ? @logger : initialize_logger
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.logger=(log)
|
|
||||||
@logger = (log ? log : Logger.new(File::NULL))
|
|
||||||
end
|
|
||||||
|
|
||||||
def logger
|
|
||||||
Sidekiq::Logging.logger
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -37,7 +37,7 @@ module Sidekiq
|
||||||
@thread = nil
|
@thread = nil
|
||||||
@strategy = (mgr.options[:fetch] || Sidekiq::BasicFetch).new(mgr.options)
|
@strategy = (mgr.options[:fetch] || Sidekiq::BasicFetch).new(mgr.options)
|
||||||
@reloader = Sidekiq.options[:reloader]
|
@reloader = Sidekiq.options[:reloader]
|
||||||
@logging = (mgr.options[:job_logger] || Sidekiq::JobLogger).new
|
@job_logger = (mgr.options[:job_logger] || Sidekiq::JobLogger).new
|
||||||
@retrier = Sidekiq::JobRetry.new
|
@retrier = Sidekiq::JobRetry.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -121,9 +121,9 @@ module Sidekiq
|
||||||
# job structure to the Web UI
|
# job structure to the Web UI
|
||||||
pristine = cloned(job_hash)
|
pristine = cloned(job_hash)
|
||||||
|
|
||||||
Sidekiq::Logging.with_job_hash_context(job_hash) do
|
@job_logger.with_job_hash_context(job_hash) do
|
||||||
@retrier.global(pristine, queue) do
|
@retrier.global(pristine, queue) do
|
||||||
@logging.call(job_hash, queue) do
|
@job_logger.call(job_hash, queue) do
|
||||||
stats(pristine, queue) do
|
stats(pristine, queue) do
|
||||||
# Rails 5 requires a Reloader to wrap code execution. In order to
|
# Rails 5 requires a Reloader to wrap code execution. In order to
|
||||||
# constantize the worker and instantiate an instance, we have to call
|
# constantize the worker and instantiate an instance, we have to call
|
||||||
|
@ -236,7 +236,8 @@ module Sidekiq
|
||||||
WORKER_STATE = SharedWorkerState.new
|
WORKER_STATE = SharedWorkerState.new
|
||||||
|
|
||||||
def stats(job_hash, queue)
|
def stats(job_hash, queue)
|
||||||
tid = Sidekiq::Logging.tid
|
tid = Sidekiq.logger.tid
|
||||||
|
|
||||||
WORKER_STATE.set(tid, {:queue => queue, :payload => job_hash, :run_at => Time.now.to_i })
|
WORKER_STATE.set(tid, {:queue => queue, :payload => job_hash, :run_at => Time.now.to_i })
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
@ -267,6 +268,5 @@ module Sidekiq
|
||||||
constant.const_defined?(name, false) ? constant.const_get(name, false) : constant.const_missing(name)
|
constant.const_defined?(name, false) ? constant.const_get(name, false) : constant.const_missing(name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,7 +24,7 @@ module Sidekiq
|
||||||
# next one.
|
# next one.
|
||||||
if conn.zrem(sorted_set, job)
|
if conn.zrem(sorted_set, job)
|
||||||
Sidekiq::Client.push(Sidekiq.load_json(job))
|
Sidekiq::Client.push(Sidekiq.load_json(job))
|
||||||
Sidekiq::Logging.logger.debug { "enqueued #{sorted_set}: #{job}" }
|
Sidekiq.logger.debug { "enqueued #{sorted_set}: #{job}" }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
141
test/test_cli.rb
141
test/test_cli.rb
|
@ -4,23 +4,24 @@ require_relative 'helper'
|
||||||
require 'sidekiq/cli'
|
require 'sidekiq/cli'
|
||||||
|
|
||||||
class TestCLI < Minitest::Test
|
class TestCLI < Minitest::Test
|
||||||
|
describe Sidekiq::CLI do
|
||||||
|
subject { Sidekiq::CLI.new }
|
||||||
|
|
||||||
|
let(:logdev) { StringIO.new }
|
||||||
|
|
||||||
|
around do |test|
|
||||||
|
Sidekiq.stub :options, Sidekiq::DEFAULTS.dup do
|
||||||
|
Sidekiq.stub :logger, Sidekiq::Logger.new(logdev) do
|
||||||
|
test.call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#parse' do
|
describe '#parse' do
|
||||||
before do
|
|
||||||
Sidekiq.options = Sidekiq::DEFAULTS.dup
|
|
||||||
@logger = Sidekiq.logger
|
|
||||||
@logdev = StringIO.new
|
|
||||||
Sidekiq.logger = Logger.new(@logdev)
|
|
||||||
@cli = Sidekiq::CLI.new
|
|
||||||
end
|
|
||||||
|
|
||||||
after do
|
|
||||||
Sidekiq.logger = @logger
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'options' do
|
describe 'options' do
|
||||||
describe 'require' do
|
describe 'require' do
|
||||||
it 'accepts with -r' do
|
it 'accepts with -r' do
|
||||||
@cli.parse(%w[sidekiq -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal './test/fake_env.rb', Sidekiq.options[:require]
|
assert_equal './test/fake_env.rb', Sidekiq.options[:require]
|
||||||
end
|
end
|
||||||
|
@ -28,7 +29,7 @@ class TestCLI < Minitest::Test
|
||||||
|
|
||||||
describe 'concurrency' do
|
describe 'concurrency' do
|
||||||
it 'accepts with -c' do
|
it 'accepts with -c' do
|
||||||
@cli.parse(%w[sidekiq -c 60 -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -c 60 -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal 60, Sidekiq.options[:concurrency]
|
assert_equal 60, Sidekiq.options[:concurrency]
|
||||||
end
|
end
|
||||||
|
@ -43,13 +44,13 @@ class TestCLI < Minitest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'sets concurrency from RAILS_MAX_THREADS env var' do
|
it 'sets concurrency from RAILS_MAX_THREADS env var' do
|
||||||
@cli.parse(%w[sidekiq -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal 9, Sidekiq.options[:concurrency]
|
assert_equal 9, Sidekiq.options[:concurrency]
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'option overrides RAILS_MAX_THREADS env var' do
|
it 'option overrides RAILS_MAX_THREADS env var' do
|
||||||
@cli.parse(%w[sidekiq -c 60 -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -c 60 -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal 60, Sidekiq.options[:concurrency]
|
assert_equal 60, Sidekiq.options[:concurrency]
|
||||||
end
|
end
|
||||||
|
@ -58,20 +59,20 @@ class TestCLI < Minitest::Test
|
||||||
|
|
||||||
describe 'queues' do
|
describe 'queues' do
|
||||||
it 'accepts with -q' do
|
it 'accepts with -q' do
|
||||||
@cli.parse(%w[sidekiq -q foo -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -q foo -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal ['foo'], Sidekiq.options[:queues]
|
assert_equal ['foo'], Sidekiq.options[:queues]
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'when weights are not present' do
|
describe 'when weights are not present' do
|
||||||
it 'accepts queues without weights' do
|
it 'accepts queues without weights' do
|
||||||
@cli.parse(%w[sidekiq -q foo -q bar -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -q foo -q bar -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal ['foo', 'bar'], Sidekiq.options[:queues]
|
assert_equal ['foo', 'bar'], Sidekiq.options[:queues]
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'sets strictly ordered queues' do
|
it 'sets strictly ordered queues' do
|
||||||
@cli.parse(%w[sidekiq -q foo -q bar -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -q foo -q bar -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal true, !!Sidekiq.options[:strict]
|
assert_equal true, !!Sidekiq.options[:strict]
|
||||||
end
|
end
|
||||||
|
@ -79,40 +80,40 @@ class TestCLI < Minitest::Test
|
||||||
|
|
||||||
describe 'when weights are present' do
|
describe 'when weights are present' do
|
||||||
it 'accepts queues with weights' do
|
it 'accepts queues with weights' do
|
||||||
@cli.parse(%w[sidekiq -q foo,3 -q bar -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -q foo,3 -q bar -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal ['foo', 'foo', 'foo', 'bar'], Sidekiq.options[:queues]
|
assert_equal ['foo', 'foo', 'foo', 'bar'], Sidekiq.options[:queues]
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not set strictly ordered queues' do
|
it 'does not set strictly ordered queues' do
|
||||||
@cli.parse(%w[sidekiq -q foo,3 -q bar -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -q foo,3 -q bar -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal false, !!Sidekiq.options[:strict]
|
assert_equal false, !!Sidekiq.options[:strict]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'accepts queues with multi-word names' do
|
it 'accepts queues with multi-word names' do
|
||||||
@cli.parse(%w[sidekiq -q queue_one -q queue-two -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -q queue_one -q queue-two -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal ['queue_one', 'queue-two'], Sidekiq.options[:queues]
|
assert_equal ['queue_one', 'queue-two'], Sidekiq.options[:queues]
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'accepts queues with dots in the name' do
|
it 'accepts queues with dots in the name' do
|
||||||
@cli.parse(%w[sidekiq -q foo.bar -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -q foo.bar -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal ['foo.bar'], Sidekiq.options[:queues]
|
assert_equal ['foo.bar'], Sidekiq.options[:queues]
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'when duplicate queue names' do
|
describe 'when duplicate queue names' do
|
||||||
it 'raises an argument error' do
|
it 'raises an argument error' do
|
||||||
assert_raises(ArgumentError) { @cli.parse(%w[sidekiq -q foo -q foo -r ./test/fake_env.rb]) }
|
assert_raises(ArgumentError) { subject.parse(%w[sidekiq -q foo -q foo -r ./test/fake_env.rb]) }
|
||||||
assert_raises(ArgumentError) { @cli.parse(%w[sidekiq -q foo,3 -q foo,1 -r ./test/fake_env.rb]) }
|
assert_raises(ArgumentError) { subject.parse(%w[sidekiq -q foo,3 -q foo,1 -r ./test/fake_env.rb]) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'when queues are empty' do
|
describe 'when queues are empty' do
|
||||||
it "sets 'default' queue" do
|
it "sets 'default' queue" do
|
||||||
@cli.parse(%w[sidekiq -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal ['default'], Sidekiq.options[:queues]
|
assert_equal ['default'], Sidekiq.options[:queues]
|
||||||
end
|
end
|
||||||
|
@ -121,7 +122,7 @@ class TestCLI < Minitest::Test
|
||||||
|
|
||||||
describe 'timeout' do
|
describe 'timeout' do
|
||||||
it 'accepts with -t' do
|
it 'accepts with -t' do
|
||||||
@cli.parse(%w[sidekiq -t 30 -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -t 30 -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal 30, Sidekiq.options[:timeout]
|
assert_equal 30, Sidekiq.options[:timeout]
|
||||||
end
|
end
|
||||||
|
@ -129,7 +130,7 @@ class TestCLI < Minitest::Test
|
||||||
|
|
||||||
describe 'verbose' do
|
describe 'verbose' do
|
||||||
it 'accepts with -v' do
|
it 'accepts with -v' do
|
||||||
@cli.parse(%w[sidekiq -v -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -v -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal Logger::DEBUG, Sidekiq.logger.level
|
assert_equal Logger::DEBUG, Sidekiq.logger.level
|
||||||
end
|
end
|
||||||
|
@ -137,7 +138,7 @@ class TestCLI < Minitest::Test
|
||||||
|
|
||||||
describe 'config file' do
|
describe 'config file' do
|
||||||
it 'accepts with -C' do
|
it 'accepts with -C' do
|
||||||
@cli.parse(%w[sidekiq -C ./test/config.yml])
|
subject.parse(%w[sidekiq -C ./test/config.yml])
|
||||||
|
|
||||||
assert_equal './test/config.yml', Sidekiq.options[:config_file]
|
assert_equal './test/config.yml', Sidekiq.options[:config_file]
|
||||||
refute Sidekiq.options[:verbose]
|
refute Sidekiq.options[:verbose]
|
||||||
|
@ -149,7 +150,7 @@ class TestCLI < Minitest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'accepts stringy keys' do
|
it 'accepts stringy keys' do
|
||||||
@cli.parse(%w[sidekiq -C ./test/config_string.yml])
|
subject.parse(%w[sidekiq -C ./test/config_string.yml])
|
||||||
|
|
||||||
assert_equal './test/config_string.yml', Sidekiq.options[:config_file]
|
assert_equal './test/config_string.yml', Sidekiq.options[:config_file]
|
||||||
refute Sidekiq.options[:verbose]
|
refute Sidekiq.options[:verbose]
|
||||||
|
@ -161,7 +162,7 @@ class TestCLI < Minitest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'accepts environment specific config' do
|
it 'accepts environment specific config' do
|
||||||
@cli.parse(%w[sidekiq -e staging -C ./test/config_environment.yml])
|
subject.parse(%w[sidekiq -e staging -C ./test/config_environment.yml])
|
||||||
|
|
||||||
assert_equal './test/config_environment.yml', Sidekiq.options[:config_file]
|
assert_equal './test/config_environment.yml', Sidekiq.options[:config_file]
|
||||||
refute Sidekiq.options[:verbose]
|
refute Sidekiq.options[:verbose]
|
||||||
|
@ -174,7 +175,7 @@ class TestCLI < Minitest::Test
|
||||||
|
|
||||||
describe 'when config file is empty' do
|
describe 'when config file is empty' do
|
||||||
it 'sets default options' do
|
it 'sets default options' do
|
||||||
@cli.parse(%w[sidekiq -C ./test/config_empty.yml -r ./test/fake_env.rb])
|
subject.parse(%w[sidekiq -C ./test/config_empty.yml -r ./test/fake_env.rb])
|
||||||
|
|
||||||
assert_equal './test/config_empty.yml', Sidekiq.options[:config_file]
|
assert_equal './test/config_empty.yml', Sidekiq.options[:config_file]
|
||||||
refute Sidekiq.options[:verbose]
|
refute Sidekiq.options[:verbose]
|
||||||
|
@ -187,7 +188,7 @@ class TestCLI < Minitest::Test
|
||||||
|
|
||||||
describe 'when config file and flags' do
|
describe 'when config file and flags' do
|
||||||
it 'merges options' do
|
it 'merges options' do
|
||||||
@cli.parse(%w[sidekiq -C ./test/config.yml
|
subject.parse(%w[sidekiq -C ./test/config.yml
|
||||||
-e snoop
|
-e snoop
|
||||||
-c 100
|
-c 100
|
||||||
-r ./test/fake_env.rb
|
-r ./test/fake_env.rb
|
||||||
|
@ -207,7 +208,7 @@ class TestCLI < Minitest::Test
|
||||||
describe 'default config file' do
|
describe 'default config file' do
|
||||||
describe 'when required path is a directory' do
|
describe 'when required path is a directory' do
|
||||||
it 'tries config/sidekiq.yml' do
|
it 'tries config/sidekiq.yml' do
|
||||||
@cli.parse(%w[sidekiq -r ./test/dummy])
|
subject.parse(%w[sidekiq -r ./test/dummy])
|
||||||
|
|
||||||
assert_equal 'sidekiq.yml', File.basename(Sidekiq.options[:config_file])
|
assert_equal 'sidekiq.yml', File.basename(Sidekiq.options[:config_file])
|
||||||
assert_equal 25, Sidekiq.options[:concurrency]
|
assert_equal 25, Sidekiq.options[:concurrency]
|
||||||
|
@ -220,21 +221,21 @@ class TestCLI < Minitest::Test
|
||||||
describe 'validation' do
|
describe 'validation' do
|
||||||
describe 'when required application path does not exist' do
|
describe 'when required application path does not exist' do
|
||||||
it 'exits with status 1' do
|
it 'exits with status 1' do
|
||||||
exit = assert_raises(SystemExit) { @cli.parse(%w[sidekiq -r /non/existent/path]) }
|
exit = assert_raises(SystemExit) { subject.parse(%w[sidekiq -r /non/existent/path]) }
|
||||||
assert_equal 1, exit.status
|
assert_equal 1, exit.status
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'when required path is a directory without config/application.rb' do
|
describe 'when required path is a directory without config/application.rb' do
|
||||||
it 'exits with status 1' do
|
it 'exits with status 1' do
|
||||||
exit = assert_raises(SystemExit) { @cli.parse(%w[sidekiq -r ./test/fixtures]) }
|
exit = assert_raises(SystemExit) { subject.parse(%w[sidekiq -r ./test/fixtures]) }
|
||||||
assert_equal 1, exit.status
|
assert_equal 1, exit.status
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'when config file path does not exist' do
|
describe 'when config file path does not exist' do
|
||||||
it 'raises argument error' do
|
it 'raises argument error' do
|
||||||
assert_raises(ArgumentError) do
|
assert_raises(ArgumentError) do
|
||||||
@cli.parse(%w[sidekiq -r ./test/fake_env.rb -C /non/existent/path])
|
subject.parse(%w[sidekiq -r ./test/fake_env.rb -C /non/existent/path])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -244,28 +245,19 @@ class TestCLI < Minitest::Test
|
||||||
|
|
||||||
describe '#run' do
|
describe '#run' do
|
||||||
before do
|
before do
|
||||||
Sidekiq.options = Sidekiq::DEFAULTS.dup
|
|
||||||
Sidekiq.options[:require] = './test/fake_env.rb'
|
Sidekiq.options[:require] = './test/fake_env.rb'
|
||||||
@logger = Sidekiq.logger
|
|
||||||
@logdev = StringIO.new
|
|
||||||
Sidekiq.logger = Logger.new(@logdev)
|
|
||||||
@cli = Sidekiq::CLI.new
|
|
||||||
end
|
|
||||||
|
|
||||||
after do
|
|
||||||
Sidekiq.logger = @logger
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'require workers' do
|
describe 'require workers' do
|
||||||
describe 'when path is a rails directory' do
|
describe 'when path is a rails directory' do
|
||||||
before do
|
before do
|
||||||
Sidekiq.options[:require] = './test/dummy'
|
Sidekiq.options[:require] = './test/dummy'
|
||||||
@cli.environment = 'test'
|
subject.environment = 'test'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'requires sidekiq railtie and rails application with environment' do
|
it 'requires sidekiq railtie and rails application with environment' do
|
||||||
@cli.stub(:launch, nil) do
|
subject.stub(:launch, nil) do
|
||||||
@cli.run
|
subject.run
|
||||||
end
|
end
|
||||||
|
|
||||||
assert defined?(Sidekiq::Rails)
|
assert defined?(Sidekiq::Rails)
|
||||||
|
@ -273,8 +265,8 @@ class TestCLI < Minitest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'tags with the app directory name' do
|
it 'tags with the app directory name' do
|
||||||
@cli.stub(:launch, nil) do
|
subject.stub(:launch, nil) do
|
||||||
@cli.run
|
subject.run
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal 'dummy', Sidekiq.options[:tag]
|
assert_equal 'dummy', Sidekiq.options[:tag]
|
||||||
|
@ -283,8 +275,8 @@ class TestCLI < Minitest::Test
|
||||||
|
|
||||||
describe 'when path is file' do
|
describe 'when path is file' do
|
||||||
it 'requires application' do
|
it 'requires application' do
|
||||||
@cli.stub(:launch, nil) do
|
subject.stub(:launch, nil) do
|
||||||
@cli.run
|
subject.run
|
||||||
end
|
end
|
||||||
|
|
||||||
assert $LOADED_FEATURES.any? { |x| x =~ /test\/fake_env/ }
|
assert $LOADED_FEATURES.any? { |x| x =~ /test\/fake_env/ }
|
||||||
|
@ -294,11 +286,11 @@ class TestCLI < Minitest::Test
|
||||||
|
|
||||||
describe 'when development environment and stdout tty' do
|
describe 'when development environment and stdout tty' do
|
||||||
it 'prints banner' do
|
it 'prints banner' do
|
||||||
@cli.stub(:environment, 'development') do
|
subject.stub(:environment, 'development') do
|
||||||
assert_output(/#{Regexp.escape(Sidekiq::CLI.banner)}/) do
|
assert_output(/#{Regexp.escape(Sidekiq::CLI.banner)}/) do
|
||||||
$stdout.stub(:tty?, true) do
|
$stdout.stub(:tty?, true) do
|
||||||
@cli.stub(:launch, nil) do
|
subject.stub(:launch, nil) do
|
||||||
@cli.run
|
subject.run
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -308,23 +300,11 @@ class TestCLI < Minitest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'signal handling' do
|
describe 'signal handling' do
|
||||||
before do
|
|
||||||
@cli = Sidekiq::CLI.new
|
|
||||||
Sidekiq.options = Sidekiq::DEFAULTS.dup
|
|
||||||
@logger = Sidekiq.logger
|
|
||||||
@logdev = StringIO.new
|
|
||||||
Sidekiq.logger = Logger.new(@logdev)
|
|
||||||
end
|
|
||||||
|
|
||||||
after do
|
|
||||||
Sidekiq.logger = @logger
|
|
||||||
end
|
|
||||||
|
|
||||||
%w(INT TERM).each do |sig|
|
%w(INT TERM).each do |sig|
|
||||||
describe sig do
|
describe sig do
|
||||||
it 'raises interrupt error' do
|
it 'raises interrupt error' do
|
||||||
assert_raises Interrupt do
|
assert_raises Interrupt do
|
||||||
@cli.handle_signal(sig)
|
subject.handle_signal(sig)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -339,11 +319,10 @@ class TestCLI < Minitest::Test
|
||||||
quiet = true
|
quiet = true
|
||||||
end
|
end
|
||||||
|
|
||||||
@cli.parse(%w[sidekiq -r ./test/fake_env.rb])
|
subject.launcher = Sidekiq::Launcher.new(Sidekiq.options)
|
||||||
@cli.launcher = Sidekiq::Launcher.new(Sidekiq.options)
|
subject.handle_signal(sig)
|
||||||
@cli.handle_signal(sig)
|
|
||||||
|
|
||||||
assert_match(/Got #{sig} signal/, @logdev.string)
|
assert_match(/Got #{sig} signal/, logdev.string)
|
||||||
assert_equal true, quiet
|
assert_equal true, quiet
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -351,21 +330,21 @@ class TestCLI < Minitest::Test
|
||||||
|
|
||||||
describe 'TTIN' do
|
describe 'TTIN' do
|
||||||
it 'prints backtraces for all threads in the process to the logfile' do
|
it 'prints backtraces for all threads in the process to the logfile' do
|
||||||
@cli.parse(%w[sidekiq -r ./test/fake_env.rb])
|
subject.handle_signal('TTIN')
|
||||||
@cli.handle_signal('TTIN')
|
|
||||||
|
|
||||||
assert_match(/Got TTIN signal/, @logdev.string)
|
assert_match(/Got TTIN signal/, logdev.string)
|
||||||
assert_match(/\bbacktrace\b/, @logdev.string)
|
assert_match(/\bbacktrace\b/, logdev.string)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'UNKNOWN' do
|
describe 'UNKNOWN' do
|
||||||
it 'logs about' do
|
it 'logs about' do
|
||||||
@cli.parse(%w[sidekiq -r ./test/fake_env.rb])
|
# subject.parse(%w[sidekiq -r ./test/fake_env.rb])
|
||||||
@cli.handle_signal('UNKNOWN')
|
subject.handle_signal('UNKNOWN')
|
||||||
|
|
||||||
assert_match(/Got UNKNOWN signal/, @logdev.string)
|
assert_match(/Got UNKNOWN signal/, logdev.string)
|
||||||
assert_match(/No signal handler for UNKNOWN/, @logdev.string)
|
assert_match(/No signal handler for UNKNOWN/, logdev.string)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
56
test/test_job_logger.rb
Normal file
56
test/test_job_logger.rb
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'helper'
|
||||||
|
require 'sidekiq/job_logger'
|
||||||
|
|
||||||
|
class TestJobLogger < Minitest::Test
|
||||||
|
describe Sidekiq::JobLogger do
|
||||||
|
subject { Sidekiq::JobLogger.new }
|
||||||
|
|
||||||
|
let(:logdev) { StringIO.new }
|
||||||
|
|
||||||
|
around do |test|
|
||||||
|
Sidekiq.stub :logger, Sidekiq::Logger.new(logdev) do
|
||||||
|
Sidekiq.logger.stub :tid, 'ouy7z76mx' do
|
||||||
|
Process.stub :pid, 4710 do
|
||||||
|
Time.stub :now, Time.utc(2020, 1, 1) do
|
||||||
|
test.call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
Thread.current[:sidekiq_context] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#call' do
|
||||||
|
describe 'when pretty formatter' do
|
||||||
|
before do
|
||||||
|
Sidekiq.logger.formatter = Sidekiq::Logger::Formatters::Pretty.new
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'logs elapsed time as context' do
|
||||||
|
subject.call('item', 'queue') {}
|
||||||
|
|
||||||
|
assert_match(/2020-01-01T00:00:00\.000Z 4710 TID-ouy7z76mx INFO: start/, logdev.string)
|
||||||
|
assert_match(/2020-01-01T00:00:00\.000Z 4710 TID-ouy7z76mx ELAPSED=.+ sec INFO: done/, logdev.string)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when json formatter' do
|
||||||
|
before do
|
||||||
|
Sidekiq.logger.formatter = Sidekiq::Logger::Formatters::JSON.new
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'logs elapsed time as context' do
|
||||||
|
subject.call('item', 'queue') {}
|
||||||
|
|
||||||
|
assert_match(/ctx.+msg.+start/, logdev.string)
|
||||||
|
assert_match(/ctx.+elapsed.+sec.+msg.+done/, logdev.string)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
235
test/test_logger.rb
Normal file
235
test/test_logger.rb
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'helper'
|
||||||
|
require 'sidekiq/logger'
|
||||||
|
|
||||||
|
class TestLogger < Minitest::Test
|
||||||
|
describe Sidekiq::Logger do
|
||||||
|
let(:logdev) { StringIO.new }
|
||||||
|
|
||||||
|
subject { Sidekiq::Logger.new(logdev) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
Thread.current[:sidekiq_context] = nil
|
||||||
|
Thread.current[:sidekiq_tid] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
Thread.current[:sidekiq_context] = nil
|
||||||
|
Thread.current[:sidekiq_tid] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'initialization' do
|
||||||
|
describe 'formatter' do
|
||||||
|
subject { Sidekiq::Logger.new(logdev).formatter }
|
||||||
|
|
||||||
|
describe 'default formatter' do
|
||||||
|
it 'sets pretty formatter' do
|
||||||
|
assert_kind_of Sidekiq::Logger::Formatters::Pretty, subject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when DYNO env var is present' do
|
||||||
|
around do |test|
|
||||||
|
ENV['DYNO'] = 'dyno identifier'
|
||||||
|
test.call
|
||||||
|
ENV['DYNO'] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sets without timestamp formatter' do
|
||||||
|
assert_kind_of Sidekiq::Logger::Formatters::WithoutTimestamp, subject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when logger formatter :json' do
|
||||||
|
around do |test|
|
||||||
|
Sidekiq.stub :logger_formatter, :json do
|
||||||
|
test.call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sets json formatter' do
|
||||||
|
assert_kind_of Sidekiq::Logger::Formatters::JSON, subject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#tid' do
|
||||||
|
describe 'default' do
|
||||||
|
it 'returns formatted thread id' do
|
||||||
|
Thread.current.stub :object_id, 70286338772540 do
|
||||||
|
Process.stub :pid, 6363 do
|
||||||
|
assert_equal 'owx3jd7mv', subject.tid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'memoization' do
|
||||||
|
before do
|
||||||
|
Thread.current[:sidekiq_tid] = 'abcdefjhi'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'current thread :sidekiq_tid attribute reference' do
|
||||||
|
Thread.current.stub :object_id, 70286338772540 do
|
||||||
|
Process.stub :pid, 6363 do
|
||||||
|
assert_equal 'abcdefjhi', subject.tid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#context' do
|
||||||
|
describe 'default' do
|
||||||
|
it 'returns empty hash' do
|
||||||
|
assert_equal({}, subject.context)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'memoization' do
|
||||||
|
before do
|
||||||
|
Thread.current[:sidekiq_context] = { a: 1 }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns current thread :sidekiq_context attribute reference' do
|
||||||
|
assert_equal({ a: 1 }, subject.context)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#with_context' do
|
||||||
|
it 'adds context to the current thread' do
|
||||||
|
assert_equal({}, subject.context)
|
||||||
|
|
||||||
|
subject.with_context(a: 1) do
|
||||||
|
assert_equal({ a: 1 }, subject.context)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({}, subject.context)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'nested contexts' do
|
||||||
|
it 'adds multiple contexts to the current thread' do
|
||||||
|
assert_equal({}, subject.context)
|
||||||
|
|
||||||
|
subject.with_context(a: 1) do
|
||||||
|
assert_equal({ a: 1 }, subject.context)
|
||||||
|
|
||||||
|
subject.with_context(b: 2, c: 3) do
|
||||||
|
assert_equal({ a: 1, b: 2, c: 3 }, subject.context)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({ a: 1 }, subject.context)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({}, subject.context)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'formatters' do
|
||||||
|
let(:severity) { 'INFO' }
|
||||||
|
let(:utc_time) { Time.utc(2020, 1, 1) }
|
||||||
|
let(:prg) { 'sidekiq' }
|
||||||
|
let(:msg) { 'Old pond frog jumps in sound of water' }
|
||||||
|
|
||||||
|
around do |test|
|
||||||
|
Process.stub :pid, 4710 do
|
||||||
|
Sidekiq.logger.stub :tid, 'ouy7z76mx' do
|
||||||
|
test.call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with context' do
|
||||||
|
subject { Sidekiq::Logger::Formatters::Pretty.new.call(severity, utc_time, prg, msg) }
|
||||||
|
|
||||||
|
let(:context) { { class: 'HaikuWorker', bid: nil } }
|
||||||
|
|
||||||
|
around do |test|
|
||||||
|
Sidekiq.logger.stub :context, context do
|
||||||
|
test.call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'skips context with nil values' do
|
||||||
|
assert_equal "2020-01-01T00:00:00.000Z 4710 TID-ouy7z76mx CLASS=HaikuWorker INFO: Old pond frog jumps in sound of water\n", subject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe Sidekiq::Logger::Formatters::Pretty do
|
||||||
|
describe '#call' do
|
||||||
|
subject { Sidekiq::Logger::Formatters::Pretty.new.call(severity, utc_time, prg, msg) }
|
||||||
|
|
||||||
|
it 'formats with timestamp, pid, tid, severity, message' do
|
||||||
|
assert_equal "2020-01-01T00:00:00.000Z 4710 TID-ouy7z76mx INFO: Old pond frog jumps in sound of water\n", subject
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with context' do
|
||||||
|
let(:context) { { class: 'HaikuWorker', jid: 'dac39c70844dc0ee3f157ced' } }
|
||||||
|
|
||||||
|
around do |test|
|
||||||
|
Sidekiq.logger.stub :context, context do
|
||||||
|
test.call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'formats with timestamp, pid, tid, context, severity, message' do
|
||||||
|
assert_equal "2020-01-01T00:00:00.000Z 4710 TID-ouy7z76mx CLASS=HaikuWorker JID=dac39c70844dc0ee3f157ced INFO: Old pond frog jumps in sound of water\n", subject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe Sidekiq::Logger::Formatters::WithoutTimestamp do
|
||||||
|
describe '#call' do
|
||||||
|
subject { Sidekiq::Logger::Formatters::WithoutTimestamp.new.call(severity, utc_time, prg, msg) }
|
||||||
|
|
||||||
|
it 'formats with pid, tid, severity, message' do
|
||||||
|
assert_equal "4710 TID-ouy7z76mx INFO: Old pond frog jumps in sound of water\n", subject
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with context' do
|
||||||
|
let(:context) { { class: 'HaikuWorker', jid: 'dac39c70844dc0ee3f157ced' } }
|
||||||
|
|
||||||
|
around do |test|
|
||||||
|
Sidekiq.logger.stub :context, context do
|
||||||
|
test.call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'formats with pid, tid, context, severity, message' do
|
||||||
|
assert_equal "4710 TID-ouy7z76mx CLASS=HaikuWorker JID=dac39c70844dc0ee3f157ced INFO: Old pond frog jumps in sound of water\n", subject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe Sidekiq::Logger::Formatters::JSON do
|
||||||
|
describe '#call' do
|
||||||
|
subject { Sidekiq::Logger::Formatters::JSON.new.call(severity, utc_time, prg, msg) }
|
||||||
|
|
||||||
|
it 'formats with pid, tid, severity, message' do
|
||||||
|
assert_equal %q|{"ts":"2020-01-01T00:00:00.000Z","pid":4710,"tid":"ouy7z76mx","ctx":{},"sev":"INFO","msg":"Old pond frog jumps in sound of water"}|, subject
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with context' do
|
||||||
|
let(:context) { { class: 'HaikuWorker', jid: 'dac39c70844dc0ee3f157ced' } }
|
||||||
|
|
||||||
|
around do |test|
|
||||||
|
Sidekiq.logger.stub :context, context do
|
||||||
|
test.call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'formats with pid, tid, context, severity, message' do
|
||||||
|
assert_equal %q|{"ts":"2020-01-01T00:00:00.000Z","pid":4710,"tid":"ouy7z76mx","ctx":{"class":"HaikuWorker","jid":"dac39c70844dc0ee3f157ced"},"sev":"INFO","msg":"Old pond frog jumps in sound of water"}|, subject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,35 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
require_relative 'helper'
|
|
||||||
require 'sidekiq/logging'
|
|
||||||
|
|
||||||
class TestLogging < Minitest::Test
|
|
||||||
describe Sidekiq::Logging do
|
|
||||||
describe "#with_context" do
|
|
||||||
def ctx
|
|
||||||
Sidekiq::Logging.logger.formatter.context
|
|
||||||
end
|
|
||||||
|
|
||||||
it "has no context by default" do
|
|
||||||
assert_nil ctx
|
|
||||||
end
|
|
||||||
|
|
||||||
it "can add a context" do
|
|
||||||
Sidekiq::Logging.with_context "xx" do
|
|
||||||
assert_equal " xx", ctx
|
|
||||||
end
|
|
||||||
assert_nil ctx
|
|
||||||
end
|
|
||||||
|
|
||||||
it "can use multiple contexts" do
|
|
||||||
Sidekiq::Logging.with_context "xx" do
|
|
||||||
assert_equal " xx", ctx
|
|
||||||
Sidekiq::Logging.with_context "yy" do
|
|
||||||
assert_equal " xx yy", ctx
|
|
||||||
end
|
|
||||||
assert_equal " xx", ctx
|
|
||||||
end
|
|
||||||
assert_nil ctx
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -338,7 +338,7 @@ class TestProcessor < Minitest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'custom job logger class' do
|
describe 'custom job logger class' do
|
||||||
class CustomJobLogger
|
class CustomJobLogger < Sidekiq::JobLogger
|
||||||
def call(item, queue)
|
def call(item, queue)
|
||||||
yield
|
yield
|
||||||
rescue Exception
|
rescue Exception
|
||||||
|
@ -348,9 +348,9 @@ class TestProcessor < Minitest::Test
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@mgr = Minitest::Mock.new
|
@mgr = Minitest::Mock.new
|
||||||
@mgr.expect(:options, {:queues => ['default'], :job_logger => CustomJobLogger})
|
@mgr.expect(:options, {:queues => ['default'], job_logger: CustomJobLogger})
|
||||||
@mgr.expect(:options, {:queues => ['default'], :job_logger => CustomJobLogger})
|
@mgr.expect(:options, {:queues => ['default'], job_logger: CustomJobLogger})
|
||||||
@mgr.expect(:options, {:queues => ['default'], :job_logger => CustomJobLogger})
|
@mgr.expect(:options, {:queues => ['default'], job_logger: CustomJobLogger})
|
||||||
@processor = ::Sidekiq::Processor.new(@mgr)
|
@processor = ::Sidekiq::Processor.new(@mgr)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue