diff --git a/README.md b/README.md index e23afc3..a78c0b9 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,29 @@ Add this line to your application's Gemfile: gem 'turtle', github: 'petlove/turtle' ``` +## Logging + +By default, turtle uses `Rails.logger` when running inside a Rails app, or `Logger.new($stdout)` otherwise. + +To silence output in tests: +```ruby +# spec/spec_helper.rb +RSpec.configure do |config| + config.before(:each) { Turtle.logger = Logger.new(IO::NULL) } + config.after(:each) { Turtle.logger = nil } +end +``` + +To use a custom logger: +```ruby +Turtle.logger = Logger.new('log/turtle.log') +``` + +To restore the default: +```ruby +Turtle.logger = nil +``` + ## Usage ### Queues with priority for shoryuken diff --git a/lib/aws/sns/configurator/logger.rb b/lib/aws/sns/configurator/logger.rb index fdb804c..4f7f6f9 100644 --- a/lib/aws/sns/configurator/logger.rb +++ b/lib/aws/sns/configurator/logger.rb @@ -4,33 +4,25 @@ module AWS module SNS module Configurator module Logger - LOGGER_ENABLED_ENV = ENV.fetch('AWS_SNS_CONFIGURATOR_LOGGER', 'true') + LOGGER_ENABLED_ENV = 'AWS_SNS_CONFIGURATOR_LOGGER' class << self def info(message) - puts log_info(message) if log? - end + return ::Turtle.logger.info(message) if ::Turtle.logger_set? - def error(message) - puts log_error(message) if log? + puts message if log? end - def log_info(message) - log('INFO', message) - end + def error(message) + return ::Turtle.logger.error(message) if ::Turtle.logger_set? - def log_error(message) - log('ERROR', message) + puts message if log? end private def log? - LOGGER_ENABLED_ENV != 'false' - end - - def log(severity_level, message) - "[#{Time.now.iso8601}] [AWS::SNS::Configurator] #{severity_level} -- : #{message}" + ENV[LOGGER_ENABLED_ENV] != 'false' end end end diff --git a/lib/aws/sqs/configurator/logger.rb b/lib/aws/sqs/configurator/logger.rb index 4f3f6fe..820c7a5 100644 --- a/lib/aws/sqs/configurator/logger.rb +++ b/lib/aws/sqs/configurator/logger.rb @@ -8,19 +8,15 @@ module Logger class << self def info(message) - puts log_info(message) if log? - end + return ::Turtle.logger.info(message) if ::Turtle.logger_set? - def error(message) - puts log_error(message) if log? + puts message if log? end - def log_info(message) - log('INFO', message) - end + def error(message) + return ::Turtle.logger.error(message) if ::Turtle.logger_set? - def log_error(message) - log('ERROR', message) + puts message if log? end private @@ -28,10 +24,6 @@ def log_error(message) def log? ENV[LOGGER_ENABLED_ENV] != 'false' end - - def log(severity_level, message) - "[#{Time.now.iso8601}] [AWS::SQS::Configurator] #{severity_level} -- : #{message}" - end end end end diff --git a/lib/turtle.rb b/lib/turtle.rb index b7fb538..2b9ef4c 100644 --- a/lib/turtle.rb +++ b/lib/turtle.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require 'logger' require 'turtle/version' require 'turtle/group' require 'turtle/queue' @@ -14,6 +15,16 @@ module Turtle class << self + attr_writer :logger + + def logger + @logger || build_default_logger + end + + def logger_set? + !@logger.nil? + end + def shoryuken_queues_priorities(options = nil) queues_in_groups = Group.to_h.values.flat_map { |attrs| attrs[:queues].map { |name, _| name } } Queue.shoryuken_priorities(options).reject { |name, _| queues_in_groups.include?(name) } @@ -48,6 +59,12 @@ def retry_intervals private + def build_default_logger + return ::Rails.logger if defined?(::Rails) && ::Rails.logger + + ::Logger.new($stdout) + end + def name_for_model(type, options) case type when :queue diff --git a/lib/turtle/logger.rb b/lib/turtle/logger.rb index f4038a4..70471ef 100644 --- a/lib/turtle/logger.rb +++ b/lib/turtle/logger.rb @@ -2,32 +2,12 @@ module Turtle module Logger - class << self - def info(message) - puts log_info(message) if log? - end - - def error(message) - puts log_error(message) if log? - end - - def log_info(message) - log('INFO', message) - end - - def log_error(message) - log('ERROR', message) - end - - private - - def log? - true - end + def self.info(message) + Turtle.logger.info(message) + end - def log(severity_level, message) - "[#{Time.now.iso8601}] [Turtle] #{severity_level} -- : #{message}" - end + def self.error(message) + Turtle.logger.error(message) end end end diff --git a/spec/aws/sns/configurator/logger_spec.rb b/spec/aws/sns/configurator/logger_spec.rb index 95829d4..0dbdf03 100644 --- a/spec/aws/sns/configurator/logger_spec.rb +++ b/spec/aws/sns/configurator/logger_spec.rb @@ -1,96 +1,70 @@ # frozen_string_literal: true RSpec.describe AWS::SNS::Configurator::Logger, type: :module do - describe '#log_info' do - subject { described_class.log_info('The topic was created successfully') } - - it 'should be an info' do - is_expected.to match(/INFO/) - end - - it 'should have the project name' do - is_expected.to match(/[AWS::SNS::Configurator]/) - end - - it 'should have the message' do - is_expected.to match(/The topic was created successfully/) - end - end - - describe '#log_error' do - subject { described_class.log_error('The topic had an error') } - - it 'should be an error' do - is_expected.to match(/ERROR/) - end - - it 'should have the project name' do - is_expected.to match(/[AWS::SNS:Configurator]/) - end - - it 'should have the message' do - is_expected.to match(/The topic had an error/) - end - end - - describe '#info' do - subject { described_class.info('The topic was created successfully') } - - after { subject } - - context 'when log is disabled' do - before do - stub_const('AWS::SNS::Configurator::Logger::LOGGER_ENABLED_ENV', 'false') + describe '.info' do + context 'when Turtle.logger is set' do + it 'delegates to Turtle.logger' do + expect(Turtle.logger).to receive(:info).with('the message') + described_class.info('the message') end - it 'should not call log_info' do - expect(described_class).to_not receive(:log_info) + it 'ignores the env var' do + allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return('false') + expect(Turtle.logger).to receive(:info).with('the message') + described_class.info('the message') end end - context 'when log is enabled' do - before do - stub_const('AWS::SNS::Configurator::Logger::LOGGER_ENABLED_ENV', 'true') - end + context 'when Turtle.logger is not set' do + before { Turtle.logger = nil } - it 'should call log_info' do - expect(described_class).to receive(:log_info) - .with('The topic was created successfully').once - end + context 'when log is disabled' do + before { allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return('false') } - it 'should print with puts' do - expect(described_class).to receive(:puts).once + it 'does not print' do + expect(described_class).not_to receive(:puts) + described_class.info('the message') + end end - end - end - - describe '#error' do - subject { described_class.error('The topic had an error') } - after { subject } + context 'when log is enabled' do + before { allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return(nil) } - context 'when log is disabled' do - before do - stub_const('AWS::SNS::Configurator::Logger::LOGGER_ENABLED_ENV', 'false') + it 'prints to stdout' do + expect(described_class).to receive(:puts).with('the message').once + described_class.info('the message') + end end + end + end - it 'should not call log_info' do - expect(described_class).to_not receive(:log_error) + describe '.error' do + context 'when Turtle.logger is set' do + it 'delegates to Turtle.logger' do + expect(Turtle.logger).to receive(:error).with('the message') + described_class.error('the message') end end - context 'when log is enabled' do - before do - stub_const('AWS::SNS::Configurator::Logger::LOGGER_ENABLED_ENV', 'true') - end + context 'when Turtle.logger is not set' do + before { Turtle.logger = nil } + + context 'when log is disabled' do + before { allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return('false') } - it 'should call log_info' do - expect(described_class).to receive(:log_error) - .with('The topic had an error').once + it 'does not print' do + expect(described_class).not_to receive(:puts) + described_class.error('the message') + end end - it 'should print with puts' do - expect(described_class).to receive(:puts).once + context 'when log is enabled' do + before { allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return(nil) } + + it 'prints to stdout' do + expect(described_class).to receive(:puts).with('the message').once + described_class.error('the message') + end end end end diff --git a/spec/aws/sqs/configurator/logger_spec.rb b/spec/aws/sqs/configurator/logger_spec.rb index 229e913..5932ed6 100644 --- a/spec/aws/sqs/configurator/logger_spec.rb +++ b/spec/aws/sqs/configurator/logger_spec.rb @@ -1,104 +1,70 @@ # frozen_string_literal: true RSpec.describe AWS::SQS::Configurator::Logger, type: :module do - describe '#log_info' do - subject { described_class.log_info('The topic was created successfully') } - - it 'should be an info' do - is_expected.to match(/INFO/) - end - - it 'should have the project name' do - is_expected.to match(/[AWS::SNS::Configurator]/) - end - - it 'should have the message' do - is_expected.to match(/The topic was created successfully/) - end - end - - describe '#log_error' do - subject { described_class.log_error('The topic had an error') } - - it 'should be an error' do - is_expected.to match(/ERROR/) - end - - it 'should have the project name' do - is_expected.to match(/[AWS::SNS:Configurator]/) - end - - it 'should have the message' do - is_expected.to match(/The topic had an error/) - end - end - - describe '#info' do - subject { described_class.info('The topic was created successfully') } - - after { subject } - - context 'when AWS_SQS_CONFIGURATOR_LOGGER is not set' do - before do - allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return(nil) - end - - it 'should call log_info' do - expect(described_class).to receive(:log_info) - .with('The topic was created successfully').once + describe '.info' do + context 'when Turtle.logger is set' do + it 'delegates to Turtle.logger' do + expect(Turtle.logger).to receive(:info).with('the message') + described_class.info('the message') end - it 'should print with puts' do - expect(described_class).to receive(:puts).once + it 'ignores the env var' do + allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return('false') + expect(Turtle.logger).to receive(:info).with('the message') + described_class.info('the message') end end - context 'when AWS_SQS_CONFIGURATOR_LOGGER is set to false' do - before do - allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return('false') - end + context 'when Turtle.logger is not set' do + before { Turtle.logger = nil } - it 'shouldnt call log_info' do - expect(described_class).to_not receive(:log_info) + context 'when AWS_SQS_CONFIGURATOR_LOGGER is not set' do + before { allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return(nil) } + + it 'prints to stdout' do + expect(described_class).to receive(:puts).with('the message').once + described_class.info('the message') + end end - it 'shouldnt print with puts' do - expect(described_class).to_not receive(:puts) + context 'when AWS_SQS_CONFIGURATOR_LOGGER is set to false' do + before { allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return('false') } + + it 'does not print' do + expect(described_class).not_to receive(:puts) + described_class.info('the message') + end end end end - describe '#error' do - subject { described_class.error('The topic had an error') } - - after { subject } - - context 'when AWS_SQS_CONFIGURATOR_LOGGER is not set' do - before do - allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return(nil) + describe '.error' do + context 'when Turtle.logger is set' do + it 'delegates to Turtle.logger' do + expect(Turtle.logger).to receive(:error).with('the message') + described_class.error('the message') end + end - it 'should call log_info' do - expect(described_class).to receive(:log_error) - .with('The topic had an error').once - end + context 'when Turtle.logger is not set' do + before { Turtle.logger = nil } - it 'should print with puts' do - expect(described_class).to receive(:puts).once - end - end + context 'when AWS_SQS_CONFIGURATOR_LOGGER is not set' do + before { allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return(nil) } - context 'when AWS_SQS_CONFIGURATOR_LOGGER is set to false' do - before do - allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return('false') + it 'prints to stdout' do + expect(described_class).to receive(:puts).with('the message').once + described_class.error('the message') + end end - it 'shouldnt call log_info' do - expect(described_class).to_not receive(:log_error) - end + context 'when AWS_SQS_CONFIGURATOR_LOGGER is set to false' do + before { allow(ENV).to receive(:[]).with(described_class::LOGGER_ENABLED_ENV).and_return('false') } - it 'shouldnt print with puts' do - expect(described_class).to_not receive(:puts) + it 'does not print' do + expect(described_class).not_to receive(:puts) + described_class.error('the message') + end end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 27bd10a..85d7871 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -24,7 +24,12 @@ end FactoryBotConfig.configure(config) + config.before(:each) do + Turtle.logger = ::Logger.new(IO::NULL) + end + config.after(:each) do + Turtle.logger = nil ENV['AWS_REGION'] = nil end end diff --git a/spec/turtle/logger_spec.rb b/spec/turtle/logger_spec.rb index 65b2c8c..237df6b 100644 --- a/spec/turtle/logger_spec.rb +++ b/spec/turtle/logger_spec.rb @@ -1,65 +1,17 @@ # frozen_string_literal: true RSpec.describe Turtle::Logger, type: :module do - describe '#log_info' do - subject { described_class.log_info('The topic was created successfully') } - - it 'should be an info' do - is_expected.to match(/INFO/) - end - - it 'should have the project name' do - is_expected.to match(/[Turtle]/) - end - - it 'should have the message' do - is_expected.to match(/The topic was created successfully/) - end - end - - describe '#log_error' do - subject { described_class.log_error('The topic had an error') } - - it 'should be an error' do - is_expected.to match(/ERROR/) - end - - it 'should have the project name' do - is_expected.to match(/[Turtle]/) - end - - it 'should have the message' do - is_expected.to match(/The topic had an error/) - end - end - - describe '#info' do - subject { described_class.info('The topic was created successfully') } - - after { subject } - - it 'should call log_info' do - expect(described_class).to receive(:log_info) - .with('The topic was created successfully').once - end - - it 'should print with puts' do - expect(described_class).to receive(:puts).once + describe '.info' do + it 'delegates to Turtle.logger' do + expect(Turtle.logger).to receive(:info).with('the message') + described_class.info('the message') end end - describe '#error' do - subject { described_class.error('The topic had an error') } - - after { subject } - - it 'should call log_info' do - expect(described_class).to receive(:log_error) - .with('The topic had an error').once - end - - it 'should print with puts' do - expect(described_class).to receive(:puts).once + describe '.error' do + it 'delegates to Turtle.logger' do + expect(Turtle.logger).to receive(:error).with('the message') + described_class.error('the message') end end end diff --git a/spec/turtle_spec.rb b/spec/turtle_spec.rb index 9b2e178..5ee35b5 100644 --- a/spec/turtle_spec.rb +++ b/spec/turtle_spec.rb @@ -95,6 +95,30 @@ end end + describe '.logger' do + it 'returns a Logger instance by default when Rails is absent' do + Turtle.logger = nil + expect(Turtle.logger).to be_a(::Logger) + end + + it 'returns the assigned logger' do + custom = ::Logger.new(IO::NULL) + Turtle.logger = custom + expect(Turtle.logger).to eq(custom) + end + + it 'is set? after assignment' do + Turtle.logger = ::Logger.new(IO::NULL) + expect(Turtle.logger_set?).to be true + end + + it 'is not set? after reset to nil' do + Turtle.logger = ::Logger.new(IO::NULL) + Turtle.logger = nil + expect(Turtle.logger_set?).to be false + end + end + describe '#name_for' do subject { described_class.name_for(type, 'linqueta', region: 'us-east-1', prefix: 'beagle', environment: 'dev') }