test/logger_test.rb in semantic_logger-4.1.1 vs test/logger_test.rb in semantic_logger-4.2.0
- old
+ new
@@ -1,258 +1,304 @@
require_relative 'test_helper'
# Unit Test for SemanticLogger::Logger
class LoggerTest < Minitest::Test
describe SemanticLogger::Logger do
- before do
- # Use a mock logger that just keeps the last logged entry in an instance
- # variable
- SemanticLogger.default_level = :trace
- SemanticLogger.backtrace_level = nil
- @mock_logger = MockLogger.new
- @appender = SemanticLogger.add_appender(logger: @mock_logger)
+ include InMemoryAppenderHelper
- # Use this test's class name as the application name in the log output
- @logger = SemanticLogger[LoggerTest]
- @hash = {session_id: 'HSSKLEU@JDK767', tracking_number: 12345}
- @hash_str = @hash.inspect.sub("{", "\\{").sub("}", "\\}")
- @thread_name = Thread.current.name
- @file_name_reg_exp = ' logger_test.rb:\d+'
-
- assert_equal [], SemanticLogger.tags
- assert_equal 65535, SemanticLogger.backtrace_level_index
+ let :dimensions do
+ {action: 'hit', user: 'jbloggs', state: 'FL'}
end
- after do
- SemanticLogger.remove_appender(@appender)
- end
-
# Ensure that any log level can be logged
SemanticLogger::LEVELS.each do |level|
- level_char = level.to_s.upcase[0]
describe "##{level}" do
describe 'positional parameter' do
it 'logs message' do
- @logger.send(level, 'hello world')
- SemanticLogger.flush
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- hello world/, @mock_logger.message)
+ logger.send(level, 'hello world')
+
+ assert log = log_message
+ assert_equal 'hello world', log.message
end
it 'adds message from block' do
- @logger.send(level, 'hello world') { 'Calculations' }
- SemanticLogger.flush
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- hello world -- Calculations/, @mock_logger.message)
+ logger.send(level, 'hello world') { 'Calculations' }
+
+ assert log = log_message
+ assert_equal 'hello world -- Calculations', log.message
end
it 'logs message and payload' do
- hash = {tracking_number: '123456', even: 2, more: 'data'}
- hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
- @logger.send(level, 'Hello world', hash)
- SemanticLogger.flush
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
- end
+ logger.send(level, 'hello world', payload)
- it 'does not log an empty payload' do
- hash = {}
- @logger.send(level, 'Hello world', hash)
- SemanticLogger.flush
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world/, @mock_logger.message)
+ assert log = log_message
+ assert_equal 'hello world', log.message
+ assert_equal payload, log.payload
end
it 'logs with backtrace' do
SemanticLogger.stub(:backtrace_level_index, 0) do
- @logger.send(level, 'hello world', @hash) { 'Calculations' }
- SemanticLogger.flush
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}#{@file_name_reg_exp}\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, @mock_logger.message)
+ logger.send(level, 'hello world', payload) { 'Calculations' }
+
+ assert log = log_message
+ assert_equal 'hello world -- Calculations', log.message
+ assert_equal payload, log.payload
+ assert log.backtrace
+ assert log.backtrace.size > 0, log.backtrace
end
end
it 'logs with backtrace and exception' do
SemanticLogger.stub(:backtrace_level_index, 0) do
exc = RuntimeError.new('Test')
- @logger.send(level, 'hello world', exc)
- SemanticLogger.flush
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}#{@file_name_reg_exp}\] LoggerTest -- hello world -- Exception: RuntimeError: Test/, @mock_logger.message)
+ logger.send(level, 'hello world', exc)
+
+ assert log = log_message
+ assert_equal 'hello world', log.message
+ assert log.backtrace
+ assert log.backtrace.size > 0, log.backtrace
+
+ assert log.exception
+ refute log.exception.backtrace
+ assert_equal 'RuntimeError', log.exception.class.name
end
end
end
- describe 'named parameters' do
+ describe 'keyword arguments' do
it 'logs message' do
- @logger.send(level, message: 'Hello world')
- SemanticLogger.flush
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world/, @mock_logger.message)
+ logger.send(level, message: 'hello world')
+
+ assert log = log_message
+ assert_equal 'hello world', log.message
end
it 'logs payload and message' do
- @logger.send(level, message: 'Hello world', payload: {tracking_number: '123456', even: 2, more: 'data'})
- hash = {tracking_number: '123456', even: 2, more: 'data'}
- SemanticLogger.flush
- hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
+ logger.send(level, message: 'hello world', payload: payload)
+
+ assert log = log_message
+ assert_equal 'hello world', log.message
+ assert_equal payload, log.payload
end
it 'logs payload and message from block' do
- @logger.send(level) { {message: 'Hello world', payload: {tracking_number: '123456', even: 2, more: 'data'}} }
- hash = {tracking_number: '123456', even: 2, more: 'data'}
- SemanticLogger.flush
- hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
+ logger.send(level) { {message: 'hello world', payload: payload} }
+
+ assert log = log_message
+ assert_equal 'hello world', log.message
+ assert_equal payload, log.payload
end
it 'logs payload only' do
- hash = {tracking_number: '123456', even: 2, more: 'data'}
- @logger.send(level, payload: hash)
- SemanticLogger.flush
- hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- #{hash_str}/, @mock_logger.message)
+ logger.send(level, payload: payload)
+
+ assert log = log_message
+ refute log.message
+ assert_equal payload, log.payload
end
it 'logs duration' do
- @logger.send(level, duration: 123.44, message: 'Hello world', payload: {tracking_number: '123456', even: 2, more: 'data'})
- hash = {tracking_number: '123456', even: 2, more: 'data'}
- SemanticLogger.flush
- hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
- duration_match = SemanticLogger::Formatters::Base::PRECISION == 3 ? '\(123ms\)' : '\(123\.4ms\)'
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] #{duration_match} LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
+ logger.send(level, duration: 123.44, message: 'hello world', payload: payload)
+
+ assert log = log_message
+ assert_equal 'hello world', log.message
+ assert_equal payload, log.payload
+ assert_equal 123.44, log.duration
end
it 'does not log when below min_duration' do
- @logger.send(level, min_duration: 200, duration: 123.45, message: 'Hello world', payload: {tracking_number: '123456', even: 2, more: 'data'})
- SemanticLogger.flush
- assert_nil @mock_logger.message
+ logger.send(level, min_duration: 200, duration: 123.45, message: 'hello world', payload: {tracking_number: '123456', even: 2, more: 'data'})
+
+ refute log_message
end
it 'logs metric' do
- # Add mock metric subscriber
- $last_metric = nil
- SemanticLogger.on_metric do |log|
- $last_metric = log.dup
+ metric_name = '/my/custom/metric'
+ logger.send(level, metric: metric_name, duration: 123.44, message: 'hello world', payload: payload)
+
+ assert log = log_message
+ assert_equal 'hello world', log.message
+ assert_equal payload, log.payload
+ assert_equal 123.44, log.duration
+ assert_equal metric_name, log.metric
+ end
+
+ describe 'metrics appender' do
+ let :appender do
+ InMemoryMetricsAppender.new
end
- metric_name = '/my/custom/metric'
- @logger.send(level, metric: metric_name, duration: 123.44, message: 'Hello world', payload: {tracking_number: '123456', even: 2, more: 'data'})
- hash = {tracking_number: '123456', even: 2, more: 'data'}
- SemanticLogger.flush
- hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
- duration_match = SemanticLogger::Formatters::Base::PRECISION == 3 ? '\(123ms\)' : '\(123\.4ms\)'
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] #{duration_match} LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
- assert metric_name, $last_metric.metric
+ it 'logs metric only events' do
+ metric_name = '/my/custom/metric'
+ logger.send(level, metric: metric_name, dimensions: dimensions)
+
+ assert log = log_message
+ assert_equal metric_name, log.metric
+ assert_equal dimensions, log.dimensions
+ refute log.message
+ end
end
+ it 'for compatibility handles random payload logged as keyword arguments' do
+ logger.send(level, payload)
+
+ assert log = log_message
+ refute log.message
+ refute log.exception
+ refute log.metric
+ assert_equal payload, log.payload
+ end
end
describe '#filter' do
- it 'Proc' do
- @appender.filter = Proc.new { |l| (/\AExclude/ =~ l.message).nil? }
- @logger.send(level, 'Exclude this log message', @hash) { 'Calculations' }
- SemanticLogger.flush
- assert_nil @mock_logger.message
+ describe 'at the appender level' do
+ it 'Proc' do
+ appender.filter = -> log { (/\AExclude/ =~ log.message).nil? }
+ logger.send(level, 'Exclude this log message', @hash) { 'Calculations' }
+
+ refute log_message
+ end
+
+ it 'RegExp' do
+ filter = /\ALogger/
+ appender.filter = -> log { (/\AExclude/ =~ log.message).nil? }
+ logger.send(level, 'Exclude this log message', @hash) { 'Calculations' }
+
+ refute log_message
+ end
end
- it 'RegExp' do
- filter = /\ALogger/
- @appender.filter = filter
- logger = SemanticLogger::Logger.new('NotLogger', :trace, filter)
- logger.send(level, 'Ignore all log messages from this class', @hash) { 'Calculations' }
- SemanticLogger.flush
- assert_nil @mock_logger.message
+ describe 'at the logger level' do
+ it 'Proc' do
+ logger.filter = -> log { (/\AExclude/ =~ log.message).nil? }
+ logger.send(level, 'Exclude this log message', @hash) { 'Calculations' }
+
+ refute log_message
+ end
+
+ it 'RegExp' do
+ filter = /\ALogger/
+ logger.filter = -> log { (/\AExclude/ =~ log.message).nil? }
+ logger.send(level, 'Exclude this log message', @hash) { 'Calculations' }
+
+ refute log_message
+ end
end
+
end
end
end
+ describe 'when level is too high' do
+ it 'does not log' do
+ SemanticLogger.default_level = :error
+ logger.info('Exclude this log message')
+
+ refute log_message
+ end
+ end
+
describe 'Compatibility' do
# Ensure that any log level can be logged
Logger::Severity.constants.each do |level|
it "log Ruby logger #{level} info" do
- @logger.level = Logger::Severity.const_get(level)
+ logger.level = Logger::Severity.const_get(level)
if level.to_s == 'UNKNOWN'
- assert_equal Logger::Severity.const_get('ERROR')+1, @logger.send(:level_index)
+ assert_equal Logger::Severity.const_get('ERROR')+1, logger.send(:level_index)
else
- assert_equal Logger::Severity.const_get(level)+1, @logger.send(:level_index)
+ assert_equal Logger::Severity.const_get(level)+1, logger.send(:level_index)
end
end
end
end
describe '#level?' do
it 'return true for debug? with :trace level' do
SemanticLogger.default_level = :trace
- assert_equal :trace, @logger.level
- assert_equal true, @logger.debug?
- assert_equal true, @logger.trace?
+ assert_equal :trace, logger.level
+ assert_equal true, logger.debug?
+ assert_equal true, logger.trace?
end
it 'return false for debug? with global :debug level' do
SemanticLogger.default_level = :debug
- assert_equal :debug, @logger.level, @logger.inspect
- assert_equal true, @logger.debug?, @logger.inspect
- assert_equal false, @logger.trace?, @logger.inspect
+ assert_equal :debug, logger.level, logger.inspect
+ assert_equal true, logger.debug?, logger.inspect
+ assert_equal false, logger.trace?, logger.inspect
end
it 'return true for debug? with global :info level' do
SemanticLogger.default_level = :info
- assert_equal :info, @logger.level, @logger.inspect
- assert_equal false, @logger.debug?, @logger.inspect
- assert_equal false, @logger.trace?, @logger.inspect
+ assert_equal :info, logger.level, logger.inspect
+ assert_equal false, logger.debug?, logger.inspect
+ assert_equal false, logger.trace?, logger.inspect
end
it 'return false for debug? with instance :debug level' do
- @logger.level = :debug
- assert_equal :debug, @logger.level, @logger.inspect
- assert_equal true, @logger.debug?, @logger.inspect
- assert_equal false, @logger.trace?, @logger.inspect
+ logger.level = :debug
+ assert_equal :debug, logger.level, logger.inspect
+ assert_equal true, logger.debug?, logger.inspect
+ assert_equal false, logger.trace?, logger.inspect
end
it 'return true for debug? with instance :info level' do
- @logger.level = :info
- assert_equal :info, @logger.level, @logger.inspect
- assert_equal false, @logger.debug?, @logger.inspect
- assert_equal false, @logger.trace?, @logger.inspect
+ logger.level = :info
+ assert_equal :info, logger.level, logger.inspect
+ assert_equal false, logger.debug?, logger.inspect
+ assert_equal false, logger.trace?, logger.inspect
end
end
describe '.tagged' do
+ it 'sets global defaults' do
+ assert_equal [], SemanticLogger.tags
+ assert_equal 0, SemanticLogger.backtrace_level_index
+ end
+
it 'add tags to log entries' do
- @logger.tagged('12345', 'DJHSFK') do
- @logger.info('Hello world')
- SemanticLogger.flush
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \[12345\] \[DJHSFK\] LoggerTest -- Hello world/, @mock_logger.message)
+ logger.tagged('12345', 'DJHSFK') do
+ logger.info('hello world')
+
+ assert log = log_message
+ assert_equal 'hello world', log.message
+ assert_equal %w(12345 DJHSFK), log.tags
end
end
it 'add embedded tags to log entries' do
- @logger.tagged('First Level', 'tags') do
- @logger.tagged('Second Level') do
- @logger.info('Hello world')
- SemanticLogger.flush
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \[First Level\] \[tags\] \[Second Level\] LoggerTest -- Hello world/, @mock_logger.message)
+ logger.tagged('First Level', 'tags') do
+ logger.tagged('Second Level') do
+ assert_equal ['First Level', 'tags', 'Second Level'], logger.tags
+ logger.info('hello world')
+
+ assert log = log_message
+ assert_equal 'hello world', log.message
+ assert_equal ['First Level', 'tags', 'Second Level'], log.tags
end
- assert_equal 2, @logger.tags.count, @logger.tags
- assert_equal 'First Level', @logger.tags.first
- assert_equal 'tags', @logger.tags.last
+ assert_equal ['First Level', 'tags'], logger.tags
end
end
it 'also supports named tagging' do
- @logger.tagged(level1: 1) do
+ logger.tagged(level1: 1) do
assert_equal({level1: 1}, SemanticLogger.named_tags)
- @logger.tagged(level2: 2, more: 'data') do
+ logger.tagged(level2: 2, more: 'data') do
assert_equal({level1: 1, level2: 2, more: 'data'}, SemanticLogger.named_tags)
- @logger.tagged(level3: 3) do
+ logger.tagged(level3: 3) do
assert_equal({level1: 1, level2: 2, more: 'data', level3: 3}, SemanticLogger.named_tags)
end
end
end
end
it 'is compatible with rails logging that uses arrays and nils' do
- @logger.tagged('', ['12345', 'DJHSFK'], nil) do
- @logger.info('Hello world')
- SemanticLogger.flush
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \[12345\] \[DJHSFK\] LoggerTest -- Hello world/, @mock_logger.message)
+ logger.tagged('', ['12345', 'DJHSFK'], nil) do
+ logger.info('hello world')
+
+ assert log = log_message
+ assert_equal 'hello world', log.message
+ assert_equal %w(12345 DJHSFK), log.tags
end
end
end
end