Replace def #{type}_func with define_singleton_method

When you run multiples pipeline and the config code get evaluated, on
every evaluation the class cached is clear, everytime you were calling a
`func` method you had the latest evaluated code. The `filter_func` and
the `output_func` need to be unique for every instance of the pipeline,
this PR replace the `def` with a `define_single_method` call ensuring
the uniqueness of the code on every instance.

This PR is based on #4254

Fixes #4298
This commit is contained in:
Pier-Hugues Pellerin 2015-12-02 16:44:44 -05:00
parent 2e93758c66
commit da26b88648
2 changed files with 35 additions and 3 deletions

View file

@ -107,7 +107,10 @@ module LogStash; module Config; module AST
["filter", "output"].each do |type|
# defines @filter_func and @output_func
definitions << "def #{type}_func(event)"
# This need to be defined as a singleton method
# so each instance of the pipeline has his own implementation
# of the output/filter function
definitions << "define_singleton_method :#{type}_func do |event|"
definitions << " targeted_outputs = []" if type == "output"
definitions << " events = [event]" if type == "filter"
definitions << " @logger.debug? && @logger.debug(\"#{type} received\", :event => event.to_hash)"
@ -544,4 +547,4 @@ class Treetop::Runtime::SyntaxNode
""
)
end
end
end

View file

@ -47,7 +47,7 @@ class DummyOutput < LogStash::Outputs::Base
def register
end
def receive(event)
@events << event
end
@ -405,4 +405,33 @@ describe LogStash::Pipeline do
pipeline.shutdown
end
end
context "Multiple pipelines" do
before do
allow(LogStash::Plugin).to receive(:lookup).with("input", "generator").and_return(LogStash::Inputs::Generator)
allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(DummyCodec)
allow(LogStash::Plugin).to receive(:lookup).with("filter", "dummyfilter").and_return(DummyFilter)
allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(DummyOutput)
end
let(:pipeline1) { LogStash::Pipeline.new("input { generator {} } filter { dummyfilter {} } output { dummyoutput {}}") }
let(:pipeline2) { LogStash::Pipeline.new("input { generator {} } filter { dummyfilter {} } output { dummyoutput {}}") }
it "should handle evaluating different config" do
# When the functions are compiled from the AST it will generate instance
# variables that are unique to the actual config, the intance are pointing
# to conditionals/plugins.
#
# Before the `defined_singleton_method`, the definition of the method was
# not unique per class, but the `instance variables` were unique per class.
#
# So the methods were trying to access instance variables that did not exist
# in the current instance and was returning an array containing nil values for
# the match.
expect(pipeline1.output_func(LogStash::Event.new)).not_to include(nil)
expect(pipeline1.filter_func(LogStash::Event.new)).not_to include(nil)
expect(pipeline2.output_func(LogStash::Event.new)).not_to include(nil)
expect(pipeline1.filter_func(LogStash::Event.new)).not_to include(nil)
end
end
end