mirror of
https://github.com/meineerde/rackstash.git
synced 2026-02-01 01:37:12 +00:00
Rename the DropIf filter to Drop and allow it to drop a percentage of events
With this, we also drop the ability to define conditions in the filter itself. When adding a filter, users can still setup a condition using the common functionality of all filters.
This commit is contained in:
parent
9152b67df0
commit
8a19dea76c
@ -183,7 +183,7 @@ require 'rackstash/filter/anonymize_ip_mask'
|
||||
require 'rackstash/filter/clear_color'
|
||||
require 'rackstash/filter/default_fields'
|
||||
require 'rackstash/filter/default_tags'
|
||||
require 'rackstash/filter/drop_if'
|
||||
require 'rackstash/filter/drop'
|
||||
require 'rackstash/filter/rename'
|
||||
require 'rackstash/filter/replace'
|
||||
require 'rackstash/filter/truncate_message'
|
||||
|
||||
72
lib/rackstash/filter/drop.rb
Normal file
72
lib/rackstash/filter/drop.rb
Normal file
@ -0,0 +1,72 @@
|
||||
# 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/filter'
|
||||
|
||||
module Rackstash
|
||||
module Filter
|
||||
# This filter skips a certain percentage of events passed through it. It
|
||||
# does not change the `event` hash in any way on its own.
|
||||
#
|
||||
# You can select the events to be filtered be using an `:if` or `:unless`
|
||||
# guard when adding the filter to the {FilterChain}.
|
||||
#
|
||||
# @example
|
||||
# Rackstash::Flow.new(STDOUT) do
|
||||
# # Drop half of all the events which have a 'debug' tag
|
||||
# filter :drop, percent: 50, if: ->(event) { event['tags'].include?('debug') }
|
||||
# end
|
||||
class Drop
|
||||
# @return [Integer] the percentage of events dropped by this filter
|
||||
attr_reader :percent
|
||||
|
||||
# @param percent [Integer] the percentage of events passed through this
|
||||
# filter which are dropped. Can be an integer between 0 and 100
|
||||
# (inclusive).
|
||||
def initialize(percent: 100)
|
||||
@percent = Integer(percent)
|
||||
unless percent.between?(0, 100)
|
||||
raise ArgumentError, "percent must be an Integer between 0 and 100"
|
||||
end
|
||||
|
||||
@rand = Random.new
|
||||
end
|
||||
|
||||
# Run the filter against the passed `event` hash.
|
||||
#
|
||||
# We drop a defined percentage of log events passing through the filter.
|
||||
# If an `event` is selected to be dropped, we return `false`, else we just
|
||||
# return the passed event.
|
||||
#
|
||||
# @param event [Hash] an event hash
|
||||
# @return [Hash, false] the given `event` or `false` if the event is
|
||||
# dropped
|
||||
def call(event)
|
||||
return false if drop?
|
||||
event
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# @return [Bool] `true` is the event should be dropped based on the
|
||||
# defined drop percentage, `false` otherwise.
|
||||
def drop?
|
||||
return true if @percent == 100
|
||||
return true if random_percentage < @percent
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
# @return [Integer] a random number between 0 and 99 (inclusive).
|
||||
def random_percentage
|
||||
@rand.rand(100)
|
||||
end
|
||||
end
|
||||
|
||||
register Drop, :drop
|
||||
end
|
||||
end
|
||||
@ -1,58 +0,0 @@
|
||||
# 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/filter'
|
||||
|
||||
module Rackstash
|
||||
module Filter
|
||||
# Skip the further processing of the event if the provided condition is
|
||||
# truethy. In that case, the event will be dropped and not be written to the
|
||||
# log adapter.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# @example
|
||||
# Rackstash::Flow.new(STDOUT) do
|
||||
# # Drop the event if it has the 'debug' tag
|
||||
# filter :drop_if, ->(event) { event['tags'].include?('debug') }
|
||||
# end
|
||||
class DropIf
|
||||
# @param drop_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
|
||||
# `drop_if` filter is not given, we expect a block to be provided which
|
||||
# is used instead.
|
||||
def initialize(drop_if = nil, &block)
|
||||
if drop_if.respond_to?(:call)
|
||||
@drop_if = drop_if
|
||||
elsif block_given?
|
||||
@drop_if = block
|
||||
else
|
||||
raise ArgumentError, 'must provide a condition when to drop the event'
|
||||
end
|
||||
end
|
||||
|
||||
# Run the filter against the passed `event` hash.
|
||||
#
|
||||
# We will call the `drop_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 `drop_if`
|
||||
# condition was evaluated
|
||||
def call(event)
|
||||
return false if @drop_if.call(event)
|
||||
event
|
||||
end
|
||||
end
|
||||
|
||||
register DropIf, :drop_if
|
||||
end
|
||||
end
|
||||
@ -1,46 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
#
|
||||
# Copyright 2017 - 2018 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/filter/drop_if'
|
||||
|
||||
RSpec.describe Rackstash::Filter::DropIf do
|
||||
describe '#initialize' do
|
||||
it 'expects a condition' do
|
||||
expect { described_class.new }.to raise_error ArgumentError
|
||||
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
|
||||
68
spec/rackstash/filter/drop_spec.rb
Normal file
68
spec/rackstash/filter/drop_spec.rb
Normal file
@ -0,0 +1,68 @@
|
||||
# frozen_string_literal: true
|
||||
#
|
||||
# Copyright 2017 - 2018 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/filter/drop'
|
||||
|
||||
RSpec.describe Rackstash::Filter::Drop do
|
||||
let(:event) {
|
||||
{what: :ever}
|
||||
}
|
||||
|
||||
describe '#initialize' do
|
||||
it 'accepts a percentage' do
|
||||
filter = described_class.new(percent: 23)
|
||||
expect(filter.percent).to eql 23
|
||||
end
|
||||
|
||||
it 'defaults to 100%' do
|
||||
expect(described_class.new.percent).to eql 100
|
||||
end
|
||||
|
||||
it 'only accepts valid percentages' do
|
||||
expect { described_class.new(percent: -1) }.to raise_error ArgumentError
|
||||
expect { described_class.new(percent: 101) }.to raise_error ArgumentError
|
||||
expect { described_class.new(percent: 'value') }.to raise_error ArgumentError
|
||||
expect { described_class.new(percent: :value) }.to raise_error TypeError
|
||||
expect { described_class.new(percent: false) }.to raise_error TypeError
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe '#call' do
|
||||
it 'always returns the event with percent: 0' do
|
||||
drop_all = described_class.new(percent: 0)
|
||||
|
||||
expect(1_000.times.count { drop_all.call(event) == event }).to eql 1_000
|
||||
end
|
||||
|
||||
it 'drops about half of the events with percent: 50' do
|
||||
drop_half = described_class.new(percent: 50)
|
||||
expect(drop_half).to receive(:random_percentage)
|
||||
.and_return(*[0, 99] * 500)
|
||||
|
||||
expect(1_000.times.count { drop_half.call(event) == event })
|
||||
.to eql 500
|
||||
end
|
||||
|
||||
it 'drops 99% of the events with percent: 99' do
|
||||
drop_most = described_class.new(percent: 99)
|
||||
expect(drop_most).to receive(:random_percentage)
|
||||
.and_return(*(0..99).to_a.shuffle * 10)
|
||||
|
||||
expect(1_000.times.count { drop_most.call(event) == event })
|
||||
.to eql 10
|
||||
end
|
||||
|
||||
it 'always returns false with percent: 100' do
|
||||
drop_all = described_class.new(percent: 100)
|
||||
|
||||
expect(1_000.times.count { drop_all.call(event) == event }).to eql 0
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
x
Reference in New Issue
Block a user