mirror of
https://github.com/meineerde/rackstash.git
synced 2026-01-21 04:32:54 +00:00
414 lines
13 KiB
Ruby
414 lines
13 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Copyright 2017 Holger Just
|
|
#
|
|
# This software may be modified and distributed under the terms
|
|
# of the MIT license. See the LICENSE.txt file for details.
|
|
|
|
require 'spec_helper'
|
|
|
|
require 'rackstash/logger'
|
|
|
|
describe Rackstash::Logger do
|
|
let(:target) { StringIO.new }
|
|
let(:logger) { described_class.new(target) }
|
|
|
|
describe '#formatter' do
|
|
it 'defaults to a Rackstash::Formatter' do
|
|
expect(logger.formatter).to be_a Rackstash::Formatter
|
|
end
|
|
|
|
it 'allows to set a custom formatter' do
|
|
formatter = ->(_severity, _time, _progname, msg) { msg.reverse }
|
|
logger.formatter = formatter
|
|
expect(logger.formatter).to equal formatter
|
|
end
|
|
end
|
|
|
|
describe '#level' do
|
|
it 'defaults to DEBUG' do
|
|
expect(logger.level).to eql 0
|
|
end
|
|
|
|
it 'can be set as an integer' do
|
|
logger.level = 3
|
|
expect(logger.level).to eql 3
|
|
|
|
logger.level = 42
|
|
expect(logger.level).to eql 42
|
|
|
|
logger.level = -25
|
|
expect(logger.level).to eql(-25)
|
|
end
|
|
|
|
it 'can be set as a symbol' do
|
|
%i[debug info warn error fatal unknown].each_with_index do |level, i|
|
|
logger.level = level
|
|
expect(logger.level).to eql i
|
|
end
|
|
|
|
%i[DeBuG InFo WaRn ErRoR FaTaL UnKnOwN].each_with_index do |level, i|
|
|
logger.level = level
|
|
expect(logger.level).to eql i
|
|
end
|
|
end
|
|
|
|
it 'can be set as a string' do
|
|
%w[debug info warn error fatal unknown].each_with_index do |level, i|
|
|
logger.level = level
|
|
expect(logger.level).to eql i
|
|
end
|
|
|
|
%w[DeBuG InFo WaRn ErRoR FaTaL UnKnOwN].each_with_index do |level, i|
|
|
logger.level = level
|
|
expect(logger.level).to eql i
|
|
end
|
|
end
|
|
|
|
it 'rejects invalid values' do
|
|
expect { logger.level = 'invalid' }.to raise_error(ArgumentError)
|
|
expect { logger.level = Object.new }.to raise_error(ArgumentError)
|
|
expect { logger.level = nil }.to raise_error(ArgumentError)
|
|
expect { logger.level = false }.to raise_error(ArgumentError)
|
|
expect { logger.level = true }.to raise_error(ArgumentError)
|
|
end
|
|
|
|
it 'can set all the levels' do
|
|
levels = %i[debug info warn error fatal unknown]
|
|
|
|
levels.each_with_index do |level, number|
|
|
logger.level = level
|
|
expect(logger.level).to eql number
|
|
|
|
# only severities larger then the selected one are logged
|
|
levels.each_with_index do |check_level, check_number|
|
|
expect(logger.public_send(:"#{check_level}?")).to eql number <= check_number
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#progname' do
|
|
it 'defaults to PROGNAME' do
|
|
expect(logger.progname).to match %r{\Arackstash/v\d+(\..+)*\z}
|
|
end
|
|
|
|
it 'can be set to a custom value' do
|
|
logger.progname = 'my app'
|
|
expect(logger.progname).to eql 'my app'
|
|
end
|
|
end
|
|
|
|
describe '#sink' do
|
|
it 'returns the created sink' do
|
|
expect(logger.sink).to be_a Rackstash::Sink
|
|
end
|
|
end
|
|
|
|
describe '#fields' do
|
|
it 'gets the current buffer\'s fields' do
|
|
buffer = instance_double('Rackstash::Buffer')
|
|
expect(logger).to receive(:buffer).and_return(buffer)
|
|
expect(buffer).to receive(:fields)
|
|
|
|
logger.fields
|
|
end
|
|
|
|
it 'returns a Rackstash::Fields::Hash' do
|
|
expect(logger.fields).to be_a Rackstash::Fields::Hash
|
|
end
|
|
end
|
|
|
|
describe '#tags' do
|
|
it 'gets the current buffer\'s tags' do
|
|
buffer = instance_double('Rackstash::Buffer')
|
|
expect(logger).to receive(:buffer).and_return(buffer)
|
|
expect(buffer).to receive(:tags)
|
|
|
|
logger.tags
|
|
end
|
|
|
|
it 'returns a Rackstash::Fields::Tags' do
|
|
expect(logger.tags).to be_a Rackstash::Fields::Tags
|
|
end
|
|
end
|
|
|
|
describe '#add' do
|
|
let(:messages) { [] }
|
|
|
|
let(:buffer) {
|
|
double('Rackstash::Buffer').tap do |buffer|
|
|
expect(buffer).to receive(:add_message) { |message| messages << message }
|
|
.at_least(:once)
|
|
end
|
|
}
|
|
|
|
let(:buffer_stack) {
|
|
double('Rackstash::BufferStack').tap do |buffer_stack|
|
|
expect(buffer_stack).to receive(:current)
|
|
.at_least(:once)
|
|
.and_return(buffer)
|
|
end
|
|
}
|
|
|
|
before do
|
|
class_double('Rackstash::Message').as_stubbed_const.tap do |klass|
|
|
expect(klass).to receive(:new) { |msg, **kwargs| { message: msg, **kwargs } }
|
|
.at_least(:once)
|
|
end
|
|
expect(logger).to receive(:buffer_stack)
|
|
.at_least(:once)
|
|
.and_return(buffer_stack)
|
|
end
|
|
|
|
it 'sets the current time as UTC to the message' do
|
|
logger.add(nil, 'msg')
|
|
expect(messages.last[:time]).to be_a(Time).and be_frozen.and be_utc
|
|
end
|
|
|
|
it 'sets the provided a severity' do
|
|
logger.log(Rackstash::DEBUG, 'Debug message')
|
|
expect(messages.last).to include message: "Debug message\n", severity: 0
|
|
|
|
logger.log(Rackstash::INFO, 'Info message')
|
|
expect(messages.last).to include message: "Info message\n", severity: 1
|
|
|
|
logger.log(Rackstash::WARN, 'Warn message')
|
|
expect(messages.last).to include message: "Warn message\n", severity: 2
|
|
|
|
logger.log(Rackstash::ERROR, 'Error message')
|
|
expect(messages.last).to include message: "Error message\n", severity: 3
|
|
|
|
logger.log(Rackstash::FATAL, 'Fatal message')
|
|
expect(messages.last).to include message: "Fatal message\n", severity: 4
|
|
|
|
logger.log(Rackstash::UNKNOWN, 'Unknown message')
|
|
expect(messages.last).to include message: "Unknown message\n", severity: 5
|
|
|
|
# Positive severities are passed along
|
|
logger.log(42, 'The answer')
|
|
expect(messages.last).to include message: "The answer\n", severity: 42
|
|
|
|
# nil is changed to UNKNOWN
|
|
logger.log(nil, 'Missing')
|
|
expect(messages.last).to include message: "Missing\n", severity: 5
|
|
|
|
# Non-number arguments result in an error
|
|
expect { logger.log(:debug, 'Missing') }.to raise_error(TypeError)
|
|
expect { logger.log('debug', 'Missing') }.to raise_error(ArgumentError)
|
|
end
|
|
|
|
it 'defaults to severity to UNKNOWN' do
|
|
logger.add(nil, 'test')
|
|
expect(messages.last).to include severity: 5
|
|
end
|
|
|
|
it 'formats the message' do
|
|
formatter = double('formatter')
|
|
logger.formatter = formatter
|
|
expect(formatter).to receive(:call)
|
|
.with('DEBUG', instance_of(Time), Rackstash::PROGNAME, 'Hello World')
|
|
|
|
logger.add(0, 'Hello World')
|
|
end
|
|
|
|
it 'calls the block if message is nil' do
|
|
temp = 0
|
|
expect do
|
|
logger.log(nil, nil, 'TestApp') do
|
|
temp = 1 + 1
|
|
end
|
|
end.to_not raise_error
|
|
expect(temp).to eql 2
|
|
end
|
|
|
|
it 'ignores the block if the message is not nil' do
|
|
temp = 0
|
|
expect do
|
|
logger.log(nil, 'not nil', 'TestApp') do
|
|
temp = 1 + 1
|
|
end
|
|
end.to_not raise_error
|
|
expect(temp).to eql 0
|
|
end
|
|
|
|
it 'follows Ruby\'s logger logic to find the message' do
|
|
# If there is a message, it will be logged
|
|
logger.add(0, 'Hello', nil)
|
|
expect(messages.last).to include(
|
|
message: "Hello\n", severity: 0, progname: Rackstash::PROGNAME
|
|
)
|
|
|
|
logger.add(4, 'Hello', 'prog')
|
|
expect(messages.last).to include(
|
|
message: "Hello\n", severity: 4, progname: 'prog'
|
|
)
|
|
|
|
logger.add(5, 'Hello', 'prog') { 'block' }
|
|
expect(messages.last).to include(
|
|
message: "Hello\n", severity: 5, progname: 'prog'
|
|
)
|
|
|
|
logger.add(nil, 'Hello', nil)
|
|
expect(messages.last).to include(
|
|
message: "Hello\n", severity: 5, progname: Rackstash::PROGNAME
|
|
)
|
|
|
|
# If there is no message, we use the block
|
|
logger.add(1, nil, 'prog') { 'Hello' }
|
|
expect(messages.last).to include(
|
|
message: "Hello\n", severity: 1, progname: 'prog'
|
|
)
|
|
logger.add(1, nil, nil) { 'Hello' }
|
|
expect(messages.last).to include(
|
|
message: "Hello\n", severity: 1, progname: Rackstash::PROGNAME
|
|
)
|
|
|
|
# If there is no block either, we use the progname and pass the default
|
|
# progname to the message
|
|
logger.add(2, nil, 'prog')
|
|
expect(messages.last).to include(
|
|
message: "prog\n", severity: 2, progname: Rackstash::PROGNAME
|
|
)
|
|
# ... which defaults to `Rackstash::BufferedLogger::PROGNAME`
|
|
logger.add(3, nil, nil)
|
|
expect(messages.last).to include(
|
|
message: "#{Rackstash::PROGNAME}\n", severity: 3, progname: Rackstash::PROGNAME
|
|
)
|
|
|
|
# If we resolve the message to a blank string, we still add it
|
|
logger.add(1, '', nil) { 'Hello' }
|
|
expect(messages.last).to include(
|
|
message: "\n", severity: 1, progname: Rackstash::PROGNAME
|
|
)
|
|
# Same with nil which is later inspect'ed by the formatter
|
|
logger.add(0, nil, 'prog') { nil }
|
|
expect(messages.last).to include(
|
|
message: "nil\n", severity: 0, progname: 'prog'
|
|
)
|
|
end
|
|
|
|
it 'can use debug shortcut' do
|
|
expect(logger).to receive(:add).with(0, 'Debug').and_call_original
|
|
logger.debug('Debug')
|
|
expect(messages.last).to include message: "Debug\n", severity: 0
|
|
end
|
|
|
|
it 'can use debug shortcut with a block' do
|
|
expect(logger).to receive(:add).with(0, nil).and_call_original
|
|
logger.debug { 'Debug' }
|
|
expect(messages.last).to include message: "Debug\n", severity: 0
|
|
end
|
|
|
|
it 'can use info shortcut' do
|
|
expect(logger).to receive(:add).with(1, 'Info').and_call_original
|
|
logger.info('Info')
|
|
expect(messages.last).to include message: "Info\n", severity: 1
|
|
end
|
|
|
|
it 'can use info shortcut with a block' do
|
|
expect(logger).to receive(:add).with(1, nil).and_call_original
|
|
logger.info { 'Info' }
|
|
expect(messages.last).to include message: "Info\n", severity: 1
|
|
end
|
|
|
|
it 'can use warn shortcut' do
|
|
expect(logger).to receive(:add).with(2, 'Warn').and_call_original
|
|
logger.warn('Warn')
|
|
expect(messages.last).to include message: "Warn\n", severity: 2
|
|
end
|
|
|
|
it 'can use warn shortcut with a block' do
|
|
expect(logger).to receive(:add).with(2, nil).and_call_original
|
|
logger.warn { 'Warn' }
|
|
expect(messages.last).to include message: "Warn\n", severity: 2
|
|
end
|
|
|
|
it 'can use error shortcut' do
|
|
expect(logger).to receive(:add).with(3, 'Error').and_call_original
|
|
logger.error('Error')
|
|
expect(messages.last).to include message: "Error\n", severity: 3
|
|
end
|
|
|
|
it 'can use error shortcut with a block' do
|
|
expect(logger).to receive(:add).with(3, nil).and_call_original
|
|
logger.error { 'Error' }
|
|
expect(messages.last).to include message: "Error\n", severity: 3
|
|
end
|
|
|
|
it 'can use fatal shortcut' do
|
|
expect(logger).to receive(:add).with(4, 'Fatal').and_call_original
|
|
logger.fatal('Fatal')
|
|
expect(messages.last).to include message: "Fatal\n", severity: 4
|
|
end
|
|
|
|
it 'can use fatal shortcut with a block' do
|
|
expect(logger).to receive(:add).with(4, nil).and_call_original
|
|
logger.fatal { 'Fatal' }
|
|
expect(messages.last).to include message: "Fatal\n", severity: 4
|
|
end
|
|
|
|
it 'can use unknown shortcut' do
|
|
expect(logger).to receive(:add).with(5, 'Unknown').and_call_original
|
|
logger.unknown('Unknown')
|
|
expect(messages.last).to include message: "Unknown\n", severity: 5
|
|
end
|
|
|
|
it 'can use unknown shortcut with a block' do
|
|
expect(logger).to receive(:add).with(5, nil).and_call_original
|
|
logger.unknown { 'Unknown' }
|
|
expect(messages.last).to include message: "Unknown\n", severity: 5
|
|
end
|
|
|
|
it 'can add a raw message with <<' do
|
|
logger << :raw_value
|
|
expect(messages.last).to include(
|
|
message: :raw_value,
|
|
severity: 5,
|
|
time: instance_of(Time)
|
|
)
|
|
end
|
|
end
|
|
|
|
describe '#with_buffer' do
|
|
it 'requires a block' do
|
|
expect { logger.with_buffer }.to raise_error ArgumentError
|
|
end
|
|
|
|
it 'adds a new buffer' do
|
|
expect(logger.send(:buffer_stack)).to receive(:push).and_call_original
|
|
expect(logger.send(:buffer_stack)).to receive(:flush_and_pop).and_call_original
|
|
|
|
logger.fields['key'] = 'outer'
|
|
logger.with_buffer do
|
|
expect(logger.fields['key']).to be nil
|
|
logger.fields['key'] = 'inner'
|
|
end
|
|
expect(logger.fields['key']).to eql 'outer'
|
|
end
|
|
|
|
it 'buffers multiple messages' do
|
|
expect(logger.sink).to receive(:flush).once
|
|
|
|
logger.with_buffer do
|
|
logger.add 1, 'Hello World'
|
|
logger.add 0, 'I feel great'
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'with multiple threads' do
|
|
it '#buffer_stack maintains thread-local stacks' do
|
|
first_stack = logger.send(:buffer_stack)
|
|
expect(first_stack).to be_a Rackstash::BufferStack
|
|
|
|
Thread.new do
|
|
second_stack = logger.send(:buffer_stack)
|
|
expect(second_stack).to be_a Rackstash::BufferStack
|
|
|
|
expect(second_stack).to_not eql first_stack
|
|
end.join
|
|
end
|
|
end
|
|
end
|