diff --git a/lib/rackstash/buffer_stack.rb b/lib/rackstash/buffer_stack.rb index 77d59a8..b4d302f 100644 --- a/lib/rackstash/buffer_stack.rb +++ b/lib/rackstash/buffer_stack.rb @@ -29,5 +29,31 @@ module Rackstash @stack.push buffer end end + + # Push a new {Buffer} to the internal stack. The new Buffer will buffer + # messages by default until it is explicitly flushed with {#flush_and_pop}. + # + # All new logged messages, and any access to fields and tags will be sent to + # this new buffer. Previous Buffers will only be visible once the new Buffer + # is poped from the stack with {#flush_and_pop}. + # + # @param buffer_args [Hash Object>] optional arguments for the new + # {Buffer}. See {Buffer#initialize} for allowed values. + # @return [Buffer] the newly created buffer + def push(**buffer_args) + Buffer.new(sink, **buffer_args).tap do |buffer| + @stack.push buffer + end + end + + # Remove the top-most Buffer from the internal stack. + # + # If there was a buffer on the stack and it has pending data, it is flushed + # to the {#sink} before it is returned. + def flush_and_pop + @stack.pop.tap do |buffer| + buffer.flush if buffer + end + end end end diff --git a/spec/rackstash/buffer_stack_spec.rb b/spec/rackstash/buffer_stack_spec.rb index a4d03c4..afe09e9 100644 --- a/spec/rackstash/buffer_stack_spec.rb +++ b/spec/rackstash/buffer_stack_spec.rb @@ -20,5 +20,62 @@ describe Rackstash::BufferStack do it 'repeatedly returns the same buffer' do expect(stack.current).to equal stack.current end + + it 'adds a new implicit buffer' do + expect(stack.current).to be_a Rackstash::Buffer + expect(stack.flush_and_pop).to be_a Rackstash::Buffer + + # no further Buffer on the stack + expect(stack.flush_and_pop).to be nil + + expect(stack.current).to be_a Rackstash::Buffer + expect(stack.flush_and_pop).to be_a Rackstash::Buffer + end + end + + describe '#push' do + it 'adds a new buffer to the stack' do + expect { stack.push } + .to change { stack.instance_variable_get(:@stack).count }.from(0).to(1) + end + + it 'returns the new buffer' do + new_buffer = stack.push + expect(new_buffer).to be_a Rackstash::Buffer + expect(new_buffer).to equal stack.current + end + + it 'pushes a buffering buffer by default' do + stack.push + expect(stack.current.buffering?).to be true + end + + it 'allows to set options on the new buffer' do + stack.push(buffering: false) + expect(stack.current.buffering?).to be false + end + end + + describe '#flush_and_pop' do + it 'removes a buffer from the stack' do + stack.push + expect { stack.flush_and_pop } + .to change { stack.instance_variable_get(:@stack).count }.from(1).to(0) + end + + it 'returns the removed buffer' do + new_buffer = stack.push + expect(stack.flush_and_pop).to equal new_buffer + expect(stack.flush_and_pop).to be nil + end + + it 'flushes the removed buffer' do + new_buffer = stack.push + + expect(new_buffer).to receive(:flush).once + + stack.flush_and_pop + stack.flush_and_pop # nil, thus `#flush` is not called again + end end end