logstash-filter-math 1.1.0 → 1.1.1

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
2
  SHA256:
3
- metadata.gz: bcecb6c0a2a2be1670c7c579a48b0565b796609329d51ef1f12f2a6603ff25eb
4
- data.tar.gz: 2ff472b3df566011a47c83bad03066c05ad7028f0a9be7aa4b29b11ae4f86bd6
3
+ metadata.gz: 7acec65c8e0272d6a835d61e803de1b244cf838d649930dfaf8649e45c3388d0
4
+ data.tar.gz: 4ca406f2e0403317e20aaf74463c61b834399aa4840ef6a69d81357a24373d6d
5
5
  SHA512:
6
- metadata.gz: af24bac7497bfd33eaf330480cabbee1598896c939cccafbfd55bb170cb41e566a8cd98552c7e1d1eb49e143f60ce678f1849cc5a9a7fd5b26b1bd68db859eb1
7
- data.tar.gz: 7b34a8f23971a80328ca1bc33f909a618d01ebddf5b0d47e24d531ed45a350b5e0fea820e0f08d9a7beb93b27646dbd0c18d8e03a5c3a6dc27c9e444d0cfa538
6
+ metadata.gz: a005e6bf35f50b0e18207c875cab6d4878ad49088b8fe90bc1210946610cee915f281f427851407f5927a81e7ebea1dce4d942ec2078da501ded4a70a85e0ce5
7
+ data.tar.gz: 4dc84a9bd0a94b1c4ae727485f0ef6ba26e4d4c4ff96dbbb14edd59dbde45a101b6ba32da9ba77c389893a188e13c0642ae6a9a9a8a4498784d30068700caafa
@@ -1,3 +1,6 @@
1
+ ## 1.1.1
2
+ - Fix to make registers threadsafe. [math filter #10](https://github.com/logstash-plugins/logstash-filter-math/issues/10)
3
+
1
4
  ## 1.1.0
2
5
  - Bumping to this version as this plugin was published to rubygems at v1.0
3
6
  - Fixed add backward compatible Operator reference aliases `'sub', 'mpx'` [math filter #8](https://github.com/logstash-plugins/logstash-filter-math/pull/8)
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ module LogStash module Filters
4
+ class EventRegisterContext
5
+
6
+ attr_reader :event, :register
7
+
8
+ def initialize(event)
9
+ @event = event
10
+ @register = []
11
+ end
12
+
13
+ def get(element)
14
+ case element
15
+ when MathCalculationElements::RegisterElement
16
+ @register[element.key]
17
+ when MathCalculationElements::FieldElement
18
+ @event.get(element.key)
19
+ end
20
+ end
21
+
22
+ def set(element, value)
23
+ case element
24
+ when MathCalculationElements::RegisterElement
25
+ @register[element.key] = value
26
+ when MathCalculationElements::FieldElement
27
+ @event.set(element.key, value)
28
+ end
29
+ end
30
+ end
31
+ end end
@@ -3,6 +3,7 @@
3
3
  require "logstash/namespace"
4
4
  require "logstash/filters/base"
5
5
 
6
+ require_relative "event_register_context"
6
7
  require_relative "math_functions"
7
8
  require_relative "math_calculation_elements"
8
9
 
@@ -58,7 +59,6 @@ module LogStash module Filters class Math < LogStash::Filters::Base
58
59
  # is exactly 4 fields and the first field is a valid calculation operator name.
59
60
  @calculate_copy = []
60
61
  all_function_keys = functions.keys
61
- @register = []
62
62
  calculate.each do |calculation|
63
63
  if calculation.size != 4
64
64
  raise LogStash::ConfigurationError, I18n.t(
@@ -79,8 +79,8 @@ module LogStash module Filters class Math < LogStash::Filters::Base
79
79
  end
80
80
  function = functions[function_key]
81
81
 
82
- left_element = MathCalculationElements.build(operand1, 1, @register)
83
- right_element = MathCalculationElements.build(operand2, 2, @register)
82
+ left_element = MathCalculationElements.build(operand1, 1)
83
+ right_element = MathCalculationElements.build(operand2, 2)
84
84
  if right_element.literal?
85
85
  lhs = left_element.literal? ? left_element.get : 1
86
86
  warning = function.invalid?(lhs, right_element.get)
@@ -93,7 +93,7 @@ module LogStash module Filters class Math < LogStash::Filters::Base
93
93
  )
94
94
  end
95
95
  end
96
- result_element = MathCalculationElements.build(target, 3, @register)
96
+ result_element = MathCalculationElements.build(target, 3)
97
97
  @calculate_copy << [function, left_element, right_element, result_element]
98
98
  end
99
99
  if @calculate_copy.last.last.is_a?(MathCalculationElements::RegisterElement)
@@ -108,18 +108,18 @@ module LogStash module Filters class Math < LogStash::Filters::Base
108
108
 
109
109
  def filter(event)
110
110
  event_changed = false # can exit if none of the calculations are are suitable
111
- @register.clear # don't carry over register results from one event to the next.
111
+ context = EventRegisterContext.new(event) # creates a new registers array, each element can use the event or register from the store
112
112
  @calculate_copy.each do |function, left_element, right_element, result_element|
113
113
  logger.debug("executing", "function" => function.name, "left_field" => left_element, "right_field" => right_element, "target" => result_element)
114
114
  # TODO add support for automatic conversion to Numeric if String
115
- operand1 = left_element.get(event)
116
- operand2 = right_element.get(event)
115
+ operand1 = left_element.get(context)
116
+ operand2 = right_element.get(context)
117
117
  # allow all the validation warnings to be logged before we skip to next
118
118
  next if operand1.nil? || operand2.nil?
119
119
  next if function.invalid?(operand1, operand2, event)
120
120
 
121
121
  result = function.call(operand1, operand2)
122
- result_element.set(result, event)
122
+ result_element.set(result, context)
123
123
  logger.debug("calculation result stored", "function" => function.name, "target" => result_element, "result" => result)
124
124
  event_changed = true
125
125
  end
@@ -5,7 +5,7 @@ module LogStash module Filters
5
5
  module MathCalculationElements
6
6
  REGISTER_REFERENCE_RE = /^MEM\[(\d+)]$/
7
7
 
8
- def self.build(reference, position, register)
8
+ def self.build(reference, position)
9
9
  case reference
10
10
  when Numeric
11
11
  if position == 3
@@ -17,7 +17,7 @@ module LogStash module Filters
17
17
  when String
18
18
  match = REGISTER_REFERENCE_RE.match(reference)
19
19
  if match
20
- RegisterElement.new(reference, position, match[1].to_i, register)
20
+ RegisterElement.new(reference, position, match[1].to_i)
21
21
  else
22
22
  FieldElement.new(reference, position)
23
23
  end
@@ -28,25 +28,28 @@ module LogStash module Filters
28
28
 
29
29
  class RegisterElement
30
30
  # supports `get` and `set`
31
- def initialize(reference, position, index, register)
31
+ def initialize(reference, position, index)
32
32
  @reference = reference
33
33
  @position = position
34
34
  @index = index
35
- @register = register
36
35
  @description = (position == 3 ? "#{@index}" : "operand #{@position}").prepend("register ").concat(": '#{@reference}'")
37
36
  end
38
37
 
38
+ def key
39
+ @index
40
+ end
41
+
39
42
  def literal?
40
43
  false
41
44
  end
42
45
 
43
- def set(value, event)
46
+ def set(value, event_register_context)
44
47
  # raise usage error if called when position != 3 ??
45
- @register[@index] = value
48
+ event_register_context.set(self, value)
46
49
  end
47
50
 
48
- def get(event)
49
- @register[@index] #log warning if nil
51
+ def get(event_register_context)
52
+ event_register_context.get(self) #log warning if nil
50
53
  end
51
54
 
52
55
  def inspect
@@ -60,6 +63,7 @@ module LogStash module Filters
60
63
 
61
64
  class FieldElement
62
65
  include LogStash::Util::Loggable
66
+
63
67
  # supports `get` and `set`
64
68
  def initialize(field, position)
65
69
  @field = field
@@ -67,18 +71,22 @@ module LogStash module Filters
67
71
  @description = (position == 3 ? "result" : "operand #{@position}").prepend("event ").concat(": '#{@field}'")
68
72
  end
69
73
 
74
+ def key
75
+ @field
76
+ end
77
+
70
78
  def literal?
71
79
  false
72
80
  end
73
81
 
74
- def set(value, event)
75
- event.set(@field, value)
82
+ def set(value, event_register_context)
83
+ event_register_context.set(self, value)
76
84
  end
77
85
 
78
- def get(event)
79
- value = event.get(@field)
86
+ def get(event_register_context)
87
+ value = event_register_context.get(self)
80
88
  if value.nil?
81
- logger.warn("field not found", "field" => @field, "event" => event.to_hash)
89
+ logger.warn("field not found", "field" => @field, "event" => event_register_context.event.to_hash)
82
90
  return nil
83
91
  end
84
92
  case value
@@ -87,7 +95,7 @@ module LogStash module Filters
87
95
  when LogStash::Timestamp, Time
88
96
  value.to_f
89
97
  else
90
- logger.warn("field value is not numeric or time", "field" => @field, "value" => value, "event" => event.to_hash)
98
+ logger.warn("field value is not numeric or time", "field" => @field, "value" => value, "event" => event_register_context.event.to_hash)
91
99
  nil
92
100
  end
93
101
  end
@@ -108,11 +116,15 @@ module LogStash module Filters
108
116
  @position = position
109
117
  end
110
118
 
119
+ def key
120
+ nil
121
+ end
122
+
111
123
  def literal?
112
124
  true
113
125
  end
114
126
 
115
- def get(event = nil)
127
+ def get(event_register_context = nil)
116
128
  @literal
117
129
  end
118
130
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-filter-math'
3
- s.version = '1.1.0'
3
+ s.version = '1.1.1'
4
4
  s.licenses = ['Apache License (2.0)']
5
5
  s.summary = "Do simple math functions on numeric fields."
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/plugin install gemname. This gem is not a stand-alone program"
@@ -443,6 +443,43 @@ describe LogStash::Filters::Math do
443
443
  end
444
444
  end
445
445
 
446
+ describe "multithreading" do
447
+ it "should still calculate correctly" do
448
+ array = [
449
+ [ "+", "[var1]", "[var2]", "MEM[0]" ],
450
+ [ "-", "[var3]", "[var4]", "MEM[1]" ],
451
+ [ "*", "MEM[0]", "MEM[1]", "[result]" ]
452
+ ]
453
+
454
+ math_hash = {"calculate" => array}
455
+
456
+ event1 = LogStash::Event.new("var1" => 3.4, "var2" => 6.6, "var3" => 4.4, "var4" => 2.4)
457
+ event2 = LogStash::Event.new("var1" => 6.8, "var2" => 13.2, "var3" => 8.8, "var4" => 4.8)
458
+ plugin = described_class.new(math_hash)
459
+ plugin.register
460
+ expect do
461
+ thread1 = Thread.new(plugin, event1) do |plugin, event|
462
+ 100.times do
463
+ plugin.filter(event)
464
+ result = event.get("result")
465
+ raise "Thread 1 failed, result is: #{result}" if result != 20.000000000000004
466
+ sleep 0.011
467
+ end
468
+ end
469
+ thread2 = Thread.new(plugin, event2) do |plugin, event|
470
+ 100.times do
471
+ plugin.filter(event)
472
+ result = event.get("result")
473
+ raise "Thread 2 failed, result is: #{result}" if result != 80.00000000000001
474
+ sleep 0.01
475
+ end
476
+ end
477
+ thread1.join
478
+ thread2.join
479
+ end.not_to raise_exception
480
+ end
481
+ end
482
+
446
483
  describe "Sequence" do
447
484
  # The logstash config.
448
485
  config <<-CONFIG
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-filter-math
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-29 00:00:00.000000000 Z
11
+ date: 2018-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -58,6 +58,7 @@ files:
58
58
  - LICENSE
59
59
  - README.md
60
60
  - docs/index.asciidoc
61
+ - lib/logstash/filters/event_register_context.rb
61
62
  - lib/logstash/filters/math.rb
62
63
  - lib/logstash/filters/math_calculation_elements.rb
63
64
  - lib/logstash/filters/math_functions.rb