diff --git a/CHANGELOG.md b/CHANGELOG.md index e715cee..d4e6a48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 4.1.0 + - Added option `keep_start_event` to manage what to do when several messages matched + as a start event were received before the end event for the specified ID. + [#35](https://github.com/logstash-plugins/logstash-filter-elapsed/pull/35) + ## 4.0.5 - Fixed default to true for the periodic_flush option in order for the caching expiration to work [#36](https://github.com/logstash-plugins/logstash-filter-elapsed/pull/36) diff --git a/docs/index.asciidoc b/docs/index.asciidoc index ffd9403..7760d91 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -106,6 +106,7 @@ This plugin supports the following configuration options plus the <> |<>|Yes | <> |<>|No | <> |<>|Yes +| <> |<>|No |======================================================================= Also see <> for a list of options supported by all @@ -162,6 +163,17 @@ The name of the field containing the task ID. This value must uniquely identify the task in the system, otherwise it's impossible to match the couple of events. +[id="plugins-{type}s-{plugin}-keep_start_event"] +===== `keep_start_event` + + * Value type is <> + * Default value is `first` + +This property manages what to do when several events matched as a start one +were received before the end event for the specified ID. There are two +supported values: `first` or `last`. If it's set to `first` (default value), +the first event matched as a start will be used; if it's set to `last`, +the last one will be used. [id="plugins-{type}s-{plugin}-common-options"] diff --git a/lib/logstash/filters/elapsed.rb b/lib/logstash/filters/elapsed.rb index b270b16..7e9456c 100644 --- a/lib/logstash/filters/elapsed.rb +++ b/lib/logstash/filters/elapsed.rb @@ -109,6 +109,12 @@ class LogStash::Filters::Elapsed < LogStash::Filters::Base # to the "end event"; if it's set to `true` a new "match event" is created. config :new_event_on_match, :validate => :boolean, :required => false, :default => false + # This property manage what to do when several "start events" were received + # before an "end event" for a concrete ID. If it's set to `first` (default + # value), the first "start event" will be used; if it's set to `last`, + # the last "start event" will be used. + config :keep_start_event, :validate => ['first', 'last'], :required => false, :default => 'first' + # This filter must have its flush function called periodically to be able to purge # expired stored start events. config :periodic_flush, :validate => :boolean, :default => true @@ -139,7 +145,7 @@ def filter(event) @logger.debug("Elapsed, 'start event' received", start_tag: @start_tag, unique_id_field: @unique_id_field) @mutex.synchronize do - unless(@start_events.has_key?(unique_id)) + unless(@keep_start_event == 'first' && @start_events.has_key?(unique_id)) @start_events[unique_id] = LogStash::Filters::Elapsed::Element.new(event) end end diff --git a/logstash-filter-elapsed.gemspec b/logstash-filter-elapsed.gemspec index 7898ec8..7a149fe 100644 --- a/logstash-filter-elapsed.gemspec +++ b/logstash-filter-elapsed.gemspec @@ -1,7 +1,7 @@ Gem::Specification.new do |s| s.name = 'logstash-filter-elapsed' - s.version = '4.0.5' + s.version = '4.1.0' s.licenses = ['Apache License (2.0)'] s.summary = "Calculates the elapsed time between a pair of events" s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program" diff --git a/spec/filters/elapsed_spec.rb b/spec/filters/elapsed_spec.rb index 1f2ac9f..c1be2b2 100644 --- a/spec/filters/elapsed_spec.rb +++ b/spec/filters/elapsed_spec.rb @@ -74,16 +74,36 @@ def setup_filter(config = {}) end describe "receiving two 'start events' for the same id field" do - it "keeps the first one and does not save the second one" do - args = {"tags" => [START_TAG], ID_FIELD => "id123"} - first_event = event(args) - second_event = event(args) + context "if 'keep_start_event' is set to 'last'" do + before(:each) do + setup_filter("keep_start_event" => 'last') + end - @filter.filter(first_event) - @filter.filter(second_event) + it "keeps the second one and does not save the first one" do + args = {"tags" => [START_TAG], ID_FIELD => "id123"} + first_event = event(args) + second_event = event(args) - insist { @filter.start_events.size } == 1 - insist { @filter.start_events["id123"].event } == first_event + @filter.filter(first_event) + @filter.filter(second_event) + + insist { @filter.start_events.size } == 1 + insist { @filter.start_events["id123"].event } == second_event + end + end + + context "if 'keep_start_event' is set to 'first'" do + it "keeps the first one and does not save the second one" do + args = {"tags" => [START_TAG], ID_FIELD => "id123"} + first_event = event(args) + second_event = event(args) + + @filter.filter(first_event) + @filter.filter(second_event) + + insist { @filter.start_events.size } == 1 + insist { @filter.start_events["id123"].event } == first_event + end end end end