diff --git a/lib/rackstash/filters.rb b/lib/rackstash/filters.rb new file mode 100644 index 0000000..e1ff56b --- /dev/null +++ b/lib/rackstash/filters.rb @@ -0,0 +1,27 @@ +# 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 'rackstash/filters/skip_event' + +module Rackstash + # Filters are part of a {Flow} where they can alter the log event before it is + # passed to the encoder and finally to the adapter. With filters, you can add, + # change or delete fields. Since each flow uses its own copy of a log event, + # you can use a different set of filters per flow and can adapt the event + # anyway you require. + # + # You can e.g. remove unenessary fields, anonymize logged IP addresses or + # filter messages. In its `call` method, the passed event hash can be mutated + # in any way. Since the event hash includes an array of {Message} objects in + # `event["messages"]` which provide the original severity and timestamp of + # each logged message, you can also retrospectively filter the logged messages. + # + # A filter can be any object responding to `call`, e.g. a Proc or a concrete + # class inside this module. + module Filters + end +end diff --git a/lib/rackstash/filters/skip_event.rb b/lib/rackstash/filters/skip_event.rb new file mode 100644 index 0000000..9933f4a --- /dev/null +++ b/lib/rackstash/filters/skip_event.rb @@ -0,0 +1,46 @@ +# 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. + +module Rackstash + module Filters + # Skip the further processing of the event of the condition is `true`. + # + # This filter is a basic example of how you can write filters which abort + # further processing of an event. You can write your own filters which + # provide similar (but probably more useful) behavior. + class SkipEvent + # @param skip_if [#call] a callable object (e.g. a `Proc`) which returns a + # truethy or falsey value on `call` with an `event` hash. If it returns + # something truethy, we abort any further processing of the event. If the + # `skip_if` filter is not given, we expect a block to be provided which + # is used instead. + def initialize(skip_if = nil, &block) + if skip_if.respond_to?(:call) + @skip_if = skip_if + elsif block_given? + @skip_if = block + else + raise TypeError, 'must provide a skip condition' + end + end + + # Run the filter against the passed `event` hash. + # + # We fill call the `skip_if` object with the passed event. If the return + # value is truethy, we abort any further processing of the event. This + # filter does not change the `event` hash in any way on its own. + # + # @param event [Hash] an event hash + # return [Hash, false] the given `event` or `false` if the `skip_if` + # condition was evaluated + def call(event) + return false if @skip_if.call(event) + event + end + end + end +end diff --git a/spec/rackstash/filters/skip_event_spec.rb b/spec/rackstash/filters/skip_event_spec.rb new file mode 100644 index 0000000..8528531 --- /dev/null +++ b/spec/rackstash/filters/skip_event_spec.rb @@ -0,0 +1,46 @@ +# 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/filters/skip_event' + +describe Rackstash::Filters::SkipEvent do + describe '#initialize' do + it 'expects a condition' do + expect { described_class.new }.to raise_error TypeError + end + + it 'accepts a callable object' do + expect { described_class.new(->(event) {}) }.not_to raise_error + end + + it 'accepts a block' do + expect { described_class.new { } }.not_to raise_error + end + end + + describe '#call' do + it 'returns the event if the condition is falsey' do + event = {'foo' => 'bar'} + + expect(described_class.new(->(_event) { false }).call(event)).to equal event + expect(described_class.new(->(_event) { nil }).call(event)).to equal event + expect(described_class.new { |_event| false }.call(event)).to equal event + expect(described_class.new { |_event| nil }.call(event)).to equal event + end + + it 'returns false if the condition is truethy' do + event = {'foo' => 'bar'} + + expect(described_class.new(->(_event) { true }).call(event)).to be false + expect(described_class.new(->(_event) { event }).call(event)).to be false + expect(described_class.new { |_event| true }.call(event)).to be false + expect(described_class.new { |_event| event }.call(event)).to be false + end + end +end