diff --git a/lib/rackstash/filters/replace.rb b/lib/rackstash/filters/replace.rb new file mode 100644 index 0000000..f574cba --- /dev/null +++ b/lib/rackstash/filters/replace.rb @@ -0,0 +1,52 @@ +# 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 + # Replace fields in the given event with new values. A new value can be + # specified as either a fixed value or as a Proc (or any other object + # responding to `call`). In the latter case, the callable object will be + # called with the event as its argument. It is then expectd to return the + # new value which is set on the key + # + # @example + # Rackstash::Flow.new(STDOUT) do + # filter :replace, { + # "sample" => ->(event) { "#{event['source_host']}: #{event['sample']}" } + # } + # end + # + # You should make sure to only set a new object of the basic types here, + # namely `String`, `Integer`, `Float`, `nil`, `true`, or `false`. + class Replace + # @param spec [Hash<#to_s => #call,Object>] a `Hash` specifying new field + # values for the named keys. Values can be given in the form of a fixed + # value or a callable object (e.g. a `Proc`) which accepts the event as + # its argument and returns the new value. + def initialize(spec) + @replace = {} + Hash(spec).each_pair do |key, value| + @replace[key.to_s] = value + end + end + + # Replace field values in the event to a new value. If a specified field + # does not exist in the event hah, it will be created with the goven (or + # calculated) value anyway. + # + # @param event [Hash] an event hash + # return [Hash] the given `event` with the fields renamed + def call(event) + @replace.each_pair do |key, value| + value = value.call(event) if value.respond_to?(:call) + event[key] = value + end + event + end + end + end +end diff --git a/spec/rackstash/filters/replace_spec.rb b/spec/rackstash/filters/replace_spec.rb new file mode 100644 index 0000000..32db849 --- /dev/null +++ b/spec/rackstash/filters/replace_spec.rb @@ -0,0 +1,52 @@ +# 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/replace' + +describe Rackstash::Filters::Replace do + let(:event) { + { + 'foo' => 'foo value', + 'bar' => 'bar value' + } + } + + def filter!(spec) + described_class.new(spec).call(event) + end + + it 'sets evaluates values from callable objects' do + filter!('foo' => ->(event) { event['foo'].upcase } ) + expect(event).to eql 'foo' => 'FOO VALUE', 'bar' => 'bar value' + end + + it 'sets raw values' do + filter!('bar' => 123 ) + expect(event).to eql 'foo' => 'foo value', 'bar' => 123 + end + + it 'always sets fields' do + filter!('baz' => 42, 'boing' => ->(event) { 'quark' }) + expect(event).to eql( + 'foo' => 'foo value', + 'bar' => 'bar value', + 'baz' => 42, + 'boing' => 'quark' + ) + end + + it 'stringifies keys' do + filter!(foo: ->(event) { event['foo'].upcase } ) + expect(event).to eql 'foo' => 'FOO VALUE', 'bar' => 'bar value' + end + + it 'returns the given event object' do + expect(filter!('bar' => 'baz')).to equal event + end +end