diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..87cdb25 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,23 @@ +# CHANGELOG for `contextual_logger` + +Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.5.1] - 2019-03-10 [diff](https://github.com/Invoca/contextual_logger/compare/v0.5.0...0.5.1) + +### Changed + +- Refactored debug, info, error... etc methods to call the base class `add(severity, message, progrname)` method since + ActiveSupport::Logger.broadcast reimplements that to broadcast to multiple logger instances, such as + Rails::Server logging to `STDOUT` + `development.log`. + Note that the base class `add()` does not have a `context` hash like our `add()` does. + We use the `**` splat to match the `context` hash up to the extra + `**context` argument, if present. If that argument is not present (such as with `broadcast`), Ruby will instead + match the `**context` up to the `progname` argument. + +## [0.5] - 2019-03-06 [diff](https://github.com/Invoca/contextual_logger/compare/v0.4.0...v0.5.0) + +### Added + - Extracted normalize_log_level to a public class method so we can call it elsewhere where we allow log_level to be + configured to text values like 'debug'. diff --git a/Gemfile.lock b/Gemfile.lock index 2215cb9..245c073 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - contextual_logger (0.5.0) + contextual_logger (0.5.1) activesupport json diff --git a/contextual_logger.gemspec b/contextual_logger.gemspec index 2f3093c..ecd55c9 100644 --- a/contextual_logger.gemspec +++ b/contextual_logger.gemspec @@ -2,9 +2,8 @@ Gem::Specification.new do |spec| spec.name = 'contextual_logger' - spec.version = '0.5.0' + spec.version = '0.5.1' spec.license = 'MIT' - spec.date = '2018-10-12' spec.summary = 'Add context to your logger' spec.description = 'A way to add context to the logs you have' spec.authors = ['James Ebentier'] diff --git a/lib/contextual_logger.rb b/lib/contextual_logger.rb index 4c580ec..622b2d8 100644 --- a/lib/contextual_logger.rb +++ b/lib/contextual_logger.rb @@ -59,38 +59,48 @@ def current_context_for_thread end def debug(message = nil, context = {}) - add_if_enabled(Logger::Severity::DEBUG, message || yield, context: context) + add(Logger::Severity::DEBUG, message || yield, **context) end def info(message = nil, context = {}) - add_if_enabled(Logger::Severity::INFO, message || yield, context: context) + add(Logger::Severity::INFO, message || yield, **context) end def warn(message = nil, context = {}) - add_if_enabled(Logger::Severity::WARN, message || yield, context: context) + add(Logger::Severity::WARN, message || yield, **context) end def error(message = nil, context = {}) - add_if_enabled(Logger::Severity::ERROR, message || yield, context: context) + add(Logger::Severity::ERROR, message || yield, **context) end def fatal(message = nil, context = {}) - add_if_enabled(Logger::Severity::FATAL, message || yield, context: context) + add(Logger::Severity::FATAL, message || yield, **context) end def unknown(message = nil, context = {}) - add_if_enabled(Logger::Severity::UNKNOWN, message || yield, context: context) + add(Logger::Severity::UNKNOWN, message || yield, **context) end def log_level_enabled?(severity) severity >= level end - def add_if_enabled(severity, message, context:) + def add(init_severity, message = nil, init_progname = nil, **context) # Ruby will prefer to match hashes up to last ** argument + severity = init_severity || UNKNOWN if log_level_enabled?(severity) - @progname ||= nil - write_entry_to_log(severity, Time.now, @progname, message, context: current_context_for_thread.deep_merge(context)) + progname = init_progname || @progname + if message.nil? + if block_given? + message = yield + else + message = init_progname + progname = @progname + end + end + write_entry_to_log(severity, Time.now, progname, message, context: current_context_for_thread.deep_merge(context)) end + true end diff --git a/spec/lib/contextual_logger_spec.rb b/spec/lib/contextual_logger_spec.rb index d91f2e9..cccc7b6 100644 --- a/spec/lib/contextual_logger_spec.rb +++ b/spec/lib/contextual_logger_spec.rb @@ -87,6 +87,34 @@ def expect_log_line_to_be_written(log_line) expect(log_message_levels).to eq(["unknown"]) end end + + describe 'when used with ActiveSupport::Logger.broadcast' do + let(:log_level) { Logger::Severity::ERROR } + let(:console_log_stream) { StringIO.new } + let(:console_logger) { Logger.new(console_log_stream) } + let(:broadcast_logger) { logger.extend(ActiveSupport::Logger.broadcast(console_logger)) } + + it 'properly broadcasts to both logs when level-named method is called' do + log_at_every_level(broadcast_logger, service: 'test_service') + expect(log_message_levels).to eq(["error", "fatal", "unknown"]) + # note: context lands in `progname` arg + expect(console_log_stream.string.gsub(/\[[^]]+\]/, '[]')).to eq(<<~EOS) + D, [] DEBUG -- {:service=>\"test_service\"}: debug message + I, [] INFO -- {:service=>\"test_service\"}: info message + W, [] WARN -- {:service=>\"test_service\"}: warn message + E, [] ERROR -- {:service=>\"test_service\"}: error message + F, [] FATAL -- {:service=>\"test_service\"}: fatal message + A, [] ANY -- {:service=>\"test_service\"}: unknown message + EOS + end + + it 'properly broadcasts to both logs when add is called' do + broadcast_logger.add(Logger::Severity::ERROR, "error message", service: 'test_service') + expect(log_message_levels).to eq(["error"]) + # note: context lands in `progname` arg + expect(console_log_stream.string.gsub(/\[[^]]+\]/, '[]')).to eq("E, [] ERROR -- {:service=>\"test_service\"}: error message\n") + end + end end describe 'inline context' do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 781caa6..ee92320 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,13 +4,13 @@ Coveralls.wear! module Helpers - def log_at_every_level(logger) - logger.debug("debug message") - logger.info("info message") - logger.warn("warn message") - logger.error("error message") - logger.fatal("fatal message") - logger.unknown("unknown message") + def log_at_every_level(logger, context = {}) + logger.debug("debug message", context) + logger.info("info message", context) + logger.warn("warn message", context) + logger.error("error message", context) + logger.fatal("fatal message", context) + logger.unknown("unknown message", context) end def log_message_levels