1
0
mirror of https://github.com/meineerde/rackstash.git synced 2025-12-19 15:01:12 +00:00

Add Callable adapter to handle a log in a custom way

Users can provide a "callable", i.e. a proc or block which will be
called for each written log. This allows users to custom handle the
logs without having to write a full adapter.

Usually, users should still write a full adapter to handle all cases of
their wrapped log device.
This commit is contained in:
Holger Just 2017-06-07 13:56:46 +02:00
parent 0aa39483dd
commit aad1660135
3 changed files with 133 additions and 0 deletions

View File

@ -56,3 +56,4 @@ end
require 'rackstash/logger' require 'rackstash/logger'
require 'rackstash/adapters/io' require 'rackstash/adapters/io'
require 'rackstash/adapters/callable'

View File

@ -0,0 +1,69 @@
# 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 'rackstash/adapters/adapter'
require 'rackstash/encoders/raw'
module Rackstash
module Adapters
# This adapter calls a user-provided "callable", i.e., a `Proc` or block for
# each written log line. This allows users to custom handle the logs without
# having to write a full custom adapter class.
#
# You can pass the callable as a block to {#initialize} or as a Proc or any
# other object responding to `call`. For each written log, we call the block
# once.
#
# Note that we do not ensure that the calls are sequentially. If multiple
# threads are concurrently writing logs to the logger, the calable might be
# called concurrently from multiple threads too.
#
# To create an adapter instance, you can use this example:
#
# Rackstash::Adapters::Callable.new do |log|
# # handle the log as required
# end
class Callable < Adapter
register_for ::Proc, :call
# Create a new Callable adapter by wrapping a proc. You can pass the proc
# either as the firat parameter to {#initialize} or as a block which is
# then transformed into a proc internally.
#
# @param callable [Proc, #call] a callable object, usually a proc or
# lambda
def initialize(callable = nil, &block)
if callable.respond_to?(:call)
@callable = callable
elsif block_given?
@callable = block
else
raise TypeError, "#{callable.inspect} does not appear to be callable"
end
end
# By default, we use an {Rackstash::Encoders::Raw} to encode the events.
# This ensures that the raw event is passed through to to the callable by
# default.
#
# You can define a custom encoder in the responsible {Flow}.
#
# @return [Rackstash::Encoders::Raw] a new Raw encoder
def default_encoder
Rackstash::Encoders::Raw.new
end
# Write a single log line by calling the defined `callable` given in
# {#initialize}.
#
# @param log [Object] the encoded log event
# @return [nil]
def write_single(log)
@callable.call(log)
nil
end
end
end
end

View File

@ -0,0 +1,63 @@
# 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/adapters/callable'
describe Rackstash::Adapters::Callable do
let(:callable) { ->(log) { log } }
let(:adapter) { Rackstash::Adapters::Callable.new(callable) }
describe '#initialize' do
it 'accepts a callable' do
expect { Rackstash::Adapters::Callable.new(->{}) }.not_to raise_error
expect { Rackstash::Adapters::Callable.new(proc {}) }.not_to raise_error
expect { Rackstash::Adapters::Callable.new(Struct.new(:call).new) }.not_to raise_error
expect { Rackstash::Adapters::Callable.new { |log| log } }.not_to raise_error
end
it 'rejects non-IO objects' do
expect { Rackstash::Adapters::Callable.new(nil) }.to raise_error TypeError
expect { Rackstash::Adapters::Callable.new('hello') }.to raise_error TypeError
expect { Rackstash::Adapters::Callable.new(Object.new) }.to raise_error TypeError
expect { Rackstash::Adapters::Callable.new([]) }.to raise_error TypeError
expect { Rackstash::Adapters::Callable.new(Struct.new(:foo).new) }.to raise_error TypeError
end
end
describe '.default_encoder' do
it 'returns a Raw encoder' do
expect(adapter.default_encoder).to be_instance_of Rackstash::Encoders::Raw
end
end
describe '#close' do
it 'does nothing' do
expect(callable).not_to receive(:close)
adapter.close
end
end
describe '#reopen' do
it 'does nothing' do
expect(callable).not_to receive(:close)
adapter.reopen
end
end
describe '#write_single' do
it 'calls the callable with the log' do
expect(callable).to receive(:call).with('a log line')
adapter.write('a log line')
end
it 'passes through the original object' do
expect(callable).to receive(:call).with([123, 'hello'])
adapter.write([123, 'hello'])
end
end
end