logstash-filter-aggregate 2.10.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e30c90c81bac3cd99cf2a01d8e66e010a89acf87
4
- data.tar.gz: 5733c4b4a64b9a6b7032fd093f289ad0d2e84f2e
2
+ SHA256:
3
+ metadata.gz: e58c8dca379dfba4361b616d161cd03b8c32211f48fd696b1acc977e4506c3d3
4
+ data.tar.gz: a6ec0abe65bb04db42f28c2db73095d5bf20f0f23c5c8710547a1834572975dc
5
5
  SHA512:
6
- metadata.gz: 809dbbdba440d501fb460ab5d60cbaaabb397654a054cd668a2d38ed1de31b99876839896cbd0c16634572d702ba8e944f094616d95e916935009a3290de8d36
7
- data.tar.gz: 6cb68ae7e22433d0bc0a49803a95e1836de98f8bb36c937812b2bbb6981d5624590df1ce27694ee34cb7fef53774ab18e9b823b0253b62c3687ea8f83895b82e
6
+ metadata.gz: 222a895a6d0106f19bd642a131babb8f4ec2dee84fc1b608d901a3c1865e062e252dc966971e5adb71321128c7292a4d4dd8845b6eea60878d3011ccea968406
7
+ data.tar.gz: e4380712a5b97a69dd7d3e53e634f2fa8caed0fc373f9fdae899d9ae73b2d5e724c07883c1ad582c8851c1f51101cd96c528639a4c0c123fe2b169d762d77de1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 2.11.0
2
+ - new feature: log a warning message when the number of tasks stored in memory exceeds the configured threshold (#125)
3
+
1
4
  ## 2.10.0
2
5
  - new feature: add ability to generate new event during code execution (#116)
3
6
 
data/docs/index.asciidoc CHANGED
@@ -26,7 +26,7 @@ include::{include_path}/plugin_header.asciidoc[]
26
26
  The aim of this filter is to aggregate information available among several events (typically log lines) belonging to a same task,
27
27
  and finally push aggregated information into final task event.
28
28
 
29
- You should be very careful to set Logstash filter workers to 1 (`-w 1` flag) for this filter to work correctly
29
+ You should be very careful to set Logstash filter workers to 1 (`-w 1` in [command-line flag](https://www.elastic.co/guide/en/logstash/current/running-logstash-command-line.html#command-line-flags)) for this filter to work correctly
30
30
  otherwise events may be processed out of sequence and unexpected results will occur.
31
31
 
32
32
 
@@ -364,6 +364,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
364
364
  | <<plugins-{type}s-{plugin}-timeout_tags>> |<<array,array>>|No
365
365
  | <<plugins-{type}s-{plugin}-timeout_task_id_field>> |<<string,string>>|No
366
366
  | <<plugins-{type}s-{plugin}-timeout_timestamp_field>> |<<string,string>>|No
367
+ | <<plugins-{type}s-{plugin}-map_count_warning_threshold>> |<<number,number>>|No
367
368
  |=======================================================================
368
369
 
369
370
  Also see <<plugins-{type}s-{plugin}-common-options>> for a list of options supported by all
@@ -614,6 +615,29 @@ Example:
614
615
  }
615
616
  }
616
617
 
618
+ [id="plugins-{type}s-{plugin}-map_count_warning_threshold"]
619
+ ===== `map_count_warning_threshold`
620
+
621
+ * Value type is <<number,number>>
622
+ * Default value is `5000`
623
+
624
+ Defines the threshold for the number of tasks in memory before a warning is logged.
625
+ When the number of maps for a task_id pattern exceeds this threshold, a warning message is logged to help identify potential memory issues caused by unterminated tasks.
626
+
627
+ The warning is repeated every 20% of the threshold events (e.g., with threshold 5000, warnings appear every 1000 events while above threshold).
628
+
629
+ Set to `0` to disable memory warnings.
630
+
631
+ Example:
632
+ [source,ruby]
633
+ filter {
634
+ aggregate {
635
+ task_id => "%{taskid}"
636
+ code => "map['count'] ||= 0; map['count'] += 1"
637
+ map_count_warning_threshold => 10000
638
+ }
639
+ }
640
+
617
641
 
618
642
  [id="plugins-{type}s-{plugin}-common-options"]
619
643
  include::{include_path}/{type}.asciidoc[]
@@ -42,6 +42,8 @@ class LogStash::Filters::Aggregate < LogStash::Filters::Base
42
42
 
43
43
  config :timeout_tags, :validate => :array, :required => false, :default => []
44
44
 
45
+ config :map_count_warning_threshold, :validate => :number, :required => false, :default => 5000
46
+
45
47
 
46
48
  # ################## #
47
49
  # INSTANCE VARIABLES #
@@ -62,6 +64,9 @@ class LogStash::Filters::Aggregate < LogStash::Filters::Base
62
64
  # Default timeout (in seconds) when not defined in plugin configuration
63
65
  DEFAULT_TIMEOUT = 1800
64
66
 
67
+ # Warning frequency divisor: warn every (threshold / divisor) events when above threshold
68
+ WARNING_FREQUENCY_DIVISOR = 5
69
+
65
70
  # Store all shared aggregate attributes per pipeline id
66
71
  @@pipelines = {}
67
72
 
@@ -138,6 +143,9 @@ class LogStash::Filters::Aggregate < LogStash::Filters::Base
138
143
  @current_pipeline.aggregate_maps[@task_id] ||= {}
139
144
  update_aggregate_maps_metric()
140
145
 
146
+ # calculate warning frequency (warn every threshold/divisor events, minimum 1)
147
+ @map_count_warning_frequency = [@map_count_warning_threshold / WARNING_FREQUENCY_DIVISOR, 1].max
148
+
141
149
  end
142
150
  end
143
151
 
@@ -180,6 +188,8 @@ class LogStash::Filters::Aggregate < LogStash::Filters::Base
180
188
  # protect aggregate_maps against concurrent access, using a mutex
181
189
  @current_pipeline.mutex.synchronize do
182
190
 
191
+ check_map_count_warning()
192
+
183
193
  # if timeout is based on event timestamp, check if task_id map is expired and should be removed
184
194
  if @timeout_timestamp_field
185
195
  event_to_yield = remove_expired_map_based_on_event_timestamp(task_id, event)
@@ -485,6 +495,26 @@ class LogStash::Filters::Aggregate < LogStash::Filters::Base
485
495
  end
486
496
  end
487
497
 
498
+ # checks if map count exceeds warning threshold and logs a warning if so
499
+ def check_map_count_warning()
500
+ return if @map_count_warning_threshold == 0
501
+
502
+ map_count = @current_pipeline.aggregate_maps[@task_id].length
503
+ if map_count >= @map_count_warning_threshold
504
+ @events_since_last_warning ||= 0
505
+ if @events_since_last_warning == 0
506
+ @logger.warn("Aggregate filter memory warning: task_id pattern '#{@task_id}' has #{map_count} maps in memory (threshold: #{@map_count_warning_threshold}).",
507
+ :task_id_pattern => @task_id,
508
+ :map_count => map_count,
509
+ :threshold => @map_count_warning_threshold)
510
+ end
511
+ @events_since_last_warning = (@events_since_last_warning + 1) % @map_count_warning_frequency
512
+ else
513
+ @events_since_last_warning = 0
514
+ end
515
+
516
+ end
517
+
488
518
  end # class LogStash::Filters::Aggregate
489
519
 
490
520
  # Element of "aggregate_maps"
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-filter-aggregate'
3
- s.version = '2.10.0'
3
+ s.version = '2.11.0'
4
4
  s.licenses = ['Apache-2.0']
5
5
  s.summary = 'Aggregates information from several events originating with a single task'
6
6
  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'
@@ -433,4 +433,37 @@ describe LogStash::Filters::Aggregate do
433
433
 
434
434
  end
435
435
 
436
+ context "map_count_warning_threshold option" do
437
+ describe "when threshold is set to 0 (disabled)" do
438
+ it "should not log any warning" do
439
+ filter = setup_filter({ "task_id" => "%{warn_id}", "code" => "", "map_count_warning_threshold" => 0 })
440
+ expect(filter.logger).not_to receive(:warn)
441
+ 3.times { |i| filter.filter(event({"warn_id" => "task_#{i}"})) }
442
+ end
443
+ end
444
+
445
+ describe "when map count reaches threshold" do
446
+ it "should log a warning" do
447
+ filter = setup_filter({ "task_id" => "%{warn_id}", "code" => "", "map_count_warning_threshold" => 3 })
448
+ expect(filter.logger).to receive(:warn).with(
449
+ /Aggregate filter memory warning.*has 3 maps in memory/,
450
+ hash_including(:task_id_pattern => "%{warn_id}", :map_count => 3, :threshold => 3)
451
+ ).once
452
+ 4.times { |i| filter.filter(event({"warn_id" => "task_#{i}"})) }
453
+ end
454
+
455
+ it "should log warning every 20% of map_count_warning_threshold occurrences" do
456
+ filter = setup_filter({ "task_id" => "%{warn_id}", "code" => "", "map_count_warning_threshold" => 5 })
457
+ expect(filter.logger).to receive(:warn).twice
458
+ 7.times { |i| filter.filter(event({"warn_id" => "task_#{i}"})) }
459
+ end
460
+ end
461
+
462
+ describe "when using default threshold" do
463
+ it "should have default threshold of 5000" do
464
+ filter = setup_filter({ "task_id" => "%{warn_id}", "code" => "" })
465
+ expect(filter.map_count_warning_threshold).to eq(5000)
466
+ end
467
+ end
468
+ end
436
469
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-filter-aggregate
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.10.0
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  - Fabien Baligand
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2021-10-11 00:00:00.000000000 Z
11
+ date: 2026-02-06 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
14
+ name: logstash-core-plugin-api
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -20,9 +20,8 @@ dependencies:
20
20
  - - "<="
21
21
  - !ruby/object:Gem::Version
22
22
  version: '2.99'
23
- name: logstash-core-plugin-api
24
- prerelease: false
25
23
  type: :runtime
24
+ prerelease: false
26
25
  version_requirements: !ruby/object:Gem::Requirement
27
26
  requirements:
28
27
  - - ">="
@@ -32,14 +31,14 @@ dependencies:
32
31
  - !ruby/object:Gem::Version
33
32
  version: '2.99'
34
33
  - !ruby/object:Gem::Dependency
34
+ name: logstash-devutils
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
39
  version: '0'
40
- name: logstash-devutils
41
- prerelease: false
42
40
  type: :development
41
+ prerelease: false
43
42
  version_requirements: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - ">="
@@ -71,7 +70,6 @@ licenses:
71
70
  metadata:
72
71
  logstash_plugin: 'true'
73
72
  logstash_group: filter
74
- post_install_message:
75
73
  rdoc_options: []
76
74
  require_paths:
77
75
  - lib
@@ -86,9 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
84
  - !ruby/object:Gem::Version
87
85
  version: '0'
88
86
  requirements: []
89
- rubyforge_project:
90
- rubygems_version: 2.6.14.1
91
- signing_key:
87
+ rubygems_version: 3.6.3
92
88
  specification_version: 4
93
89
  summary: Aggregates information from several events originating with a single task
94
90
  test_files: