logstash-filter-math 1.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d4dbbbc58d14856fcd8e53f57c6897c2a2eb7221
4
- data.tar.gz: c939090de8e97cfd20622fb6c84064f59c2e67ae
2
+ SHA256:
3
+ metadata.gz: bcecb6c0a2a2be1670c7c579a48b0565b796609329d51ef1f12f2a6603ff25eb
4
+ data.tar.gz: 2ff472b3df566011a47c83bad03066c05ad7028f0a9be7aa4b29b11ae4f86bd6
5
5
  SHA512:
6
- metadata.gz: 4f9340a61978c42ef4c56436a4b29f15d38f1fffa433bb27bae632888b7b0e9d16232ae785752521cfa157fe4f05b0f6f5c7e47b525fda6cdbdd8ddec0090334
7
- data.tar.gz: 4df67712a02104a781721991bf36221004056efad23a1e50c745fd8048691a8d126b9e8727001743c8b7ed93304869dc081f60b4cc857f431521e2a9f3663a37
6
+ metadata.gz: af24bac7497bfd33eaf330480cabbee1598896c939cccafbfd55bb170cb41e566a8cd98552c7e1d1eb49e143f60ce678f1849cc5a9a7fd5b26b1bd68db859eb1
7
+ data.tar.gz: 7b34a8f23971a80328ca1bc33f909a618d01ebddf5b0d47e24d531ed45a350b5e0fea820e0f08d9a7beb93b27646dbd0c18d8e03a5c3a6dc27c9e444d0cfa538
data/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ ## 1.1.0
2
+ - Bumping to this version as this plugin was published to rubygems at v1.0
3
+ - Fixed add backward compatible Operator reference aliases `'sub', 'mpx'` [math filter #8](https://github.com/logstash-plugins/logstash-filter-math/pull/8)
4
+
5
+ ## 1.0.0
6
+ - This plugin is now in the logstash-plugins GH org
7
+ - Added Memory registers
8
+ - Added More functions Power, Round, Modulo, FloatDivide
9
+ - Added Literals
10
+ - Added Operator reference aliases, e.g. `'*', 'times', 'multiply'` all refer to Multiply.
11
+ - Added asciidoc documentation
12
+ - Above features provided by [math filter #5](https://github.com/logstash-plugins/logstash-filter-math/pull/5)
13
+
14
+ ## 1.0
15
+ - Published to rubygems by Robin Clarke
data/CONTRIBUTORS ADDED
@@ -0,0 +1,11 @@
1
+ The following is a list of people who have contributed ideas, code, bug
2
+ reports, or in general have helped this plugin along its way.
3
+
4
+ Contributors:
5
+ * Robin Clarke (robin13)
6
+ * Guy Boertje (guyboertje)
7
+
8
+ Note: If you've sent us patches, bug reports, or otherwise contributed to
9
+ this plugin, and you aren't on the list above and want to be, please let us know
10
+ and we'll make sure you're here. Contributions from folks like you are what make
11
+ open source awesome.
data/Gemfile CHANGED
@@ -1,2 +1,10 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
+
4
+ logstash_path = ENV["LOGSTASH_PATH"] || "../../logstash"
5
+ use_logstash_source = ENV["LOGSTASH_SOURCE"] && ENV["LOGSTASH_SOURCE"].to_s == "1"
6
+
7
+ if Dir.exist?(logstash_path) && use_logstash_source
8
+ gem 'logstash-core', :path => "#{logstash_path}/logstash-core"
9
+ gem 'logstash-core-plugin-api', :path => "#{logstash_path}/logstash-core-plugin-api"
10
+ end
data/README.md CHANGED
@@ -1,24 +1,25 @@
1
1
  # logstash-filter-math
2
2
 
3
- This plugin provides the ability to do various simple math operations (addition, subtraction,
4
- multiplication and division) on document fields.
3
+ This plugin provides the ability to do various simple math operations (addition, subtraction, multiplication and division) on document fields
5
4
 
6
5
  # Logstash Plugin
7
6
 
7
+ [![Travis Build Status](https://travis-ci.org/logstash-plugins/logstash-filter-math.svg)](https://travis-ci.org/logstash-plugins/logstash-filter-math)
8
+
8
9
  This is a plugin for [Logstash](https://github.com/elastic/logstash).
9
10
 
10
11
  It is fully free and fully open source. The license is Apache 2.0, meaning you are pretty much free to use it however you want in whatever way.
11
12
 
12
13
  ## Documentation
13
14
 
14
- Logstash provides infrastructure to automatically generate documentation for this plugin. We use the asciidoc format to write documentation so any comments in the source code will be first converted into asciidoc and then into html. All plugin documentation are placed under one [central location](http://www.elastic.org/guide/en/logstash/current/).
15
+ Logstash provides infrastructure to automatically generate documentation for this plugin. We use the asciidoc format to write documentation so any comments in the source code will be first converted into asciidoc and then into html. All plugin documentation are placed under one [central location](http://www.elastic.co/guide/en/logstash/current/).
15
16
 
16
17
  - For formatting code or config example, you can use the asciidoc `[source,ruby]` directive
17
18
  - For more asciidoc formatting tips, see the excellent reference here https://github.com/elastic/docs#asciidoc-guide
18
19
 
19
20
  ## Need Help?
20
21
 
21
- Need help? Try #logstash on freenode IRC or the logstash-users@googlegroups.com mailing list.
22
+ Need help? Try #logstash on freenode IRC or the https://discuss.elastic.co/c/logstash discussion forum.
22
23
 
23
24
  ## Developing
24
25
 
@@ -58,7 +59,12 @@ gem "logstash-filter-awesome", :path => "/your/local/logstash-filter-awesome"
58
59
  ```
59
60
  - Install plugin
60
61
  ```sh
62
+ # Logstash 2.3 and higher
63
+ bin/logstash-plugin install --no-verify
64
+
65
+ # Prior to Logstash 2.3
61
66
  bin/plugin install --no-verify
67
+
62
68
  ```
63
69
  - Run Logstash with your plugin
64
70
  ```sh
@@ -76,7 +82,12 @@ gem build logstash-filter-awesome.gemspec
76
82
  ```
77
83
  - Install the plugin from the Logstash home
78
84
  ```sh
79
- bin/plugin install /your/local/plugin/logstash-filter-awesome.gem
85
+ # Logstash 2.3 and higher
86
+ bin/logstash-plugin install --no-verify
87
+
88
+ # Prior to Logstash 2.3
89
+ bin/plugin install --no-verify
90
+
80
91
  ```
81
92
  - Start Logstash and proceed to test the plugin
82
93
 
@@ -89,3 +100,4 @@ Programming is not a required skill. Whatever you've seen about open source and
89
100
  It is more important to the community that you are able to contribute.
90
101
 
91
102
  For more information about contributing, see the [CONTRIBUTING](https://github.com/elastic/logstash/blob/master/CONTRIBUTING.md) file.
103
+
@@ -0,0 +1,207 @@
1
+ :plugin: math
2
+ :type: filter
3
+
4
+ ///////////////////////////////////////////
5
+ START - GENERATED VARIABLES, DO NOT EDIT!
6
+ ///////////////////////////////////////////
7
+ :version: %VERSION%
8
+ :release_date: %RELEASE_DATE%
9
+ :changelog_url: %CHANGELOG_URL%
10
+ :include_path: ../../../../logstash/docs/include
11
+ ///////////////////////////////////////////
12
+ END - GENERATED VARIABLES, DO NOT EDIT!
13
+ ///////////////////////////////////////////
14
+
15
+ [id="plugins-{type}s-{plugin}"]
16
+
17
+ === Math filter plugin
18
+
19
+ include::{include_path}/plugin_header.asciidoc[]
20
+
21
+ ==== Description
22
+
23
+ This filter performs simple arithmetic calculations on Numeric or Logstash Timestamp values taken
24
+ from fields in an event.
25
+
26
+ The following example shows how multiple steps can be calculated.
27
+ Imagine you have two fields that represent distances in kilometers and you need
28
+ to add them together and multiply the result by 1000 to get total
29
+ distance in meters.
30
+
31
+ ["source","json",subs="callouts"]
32
+ -----
33
+ filter {
34
+ math {
35
+ calculate => [
36
+ [ "add", "[walk1_distance]", "[walk2_distance]", "MEM[0]" ], <1>
37
+ [ "multiply", MEM[0], 1000, "[total_distance_m]" ] <2>
38
+ ]
39
+ }
40
+ }
41
+ -----
42
+ <1> This calculation adds the two field's values together and stores the result in a memory register.
43
+ <2> This calculation multiplies the value in the memory register with a literal numeric value.
44
+
45
+ Here's a full example that takes outside and inside air temperatures in degrees
46
+ Fahrenheit and calculates the difference in Celsius. The arithmetic equivalent is:
47
+
48
+ `delta_in_c = round( ((inside - 32) * 5 / 9) - ((outside - 32) * 5 / 9) )`
49
+
50
+ [source,json]
51
+ -----
52
+ input {
53
+ generator {
54
+ message => '{"sensor":"temperature-1", "inside": 71.24, "outside": 61.7 }'
55
+ count => 1
56
+ }
57
+ }
58
+
59
+ filter {
60
+ json {
61
+ source => "message"
62
+ }
63
+ if "_jsonparsefailure" not in [tags] {
64
+ math {
65
+ calculate => [
66
+ [ "fdiv", 5, 9, "MEM[0]" ],
67
+ [ "subtract", "[outside]", 32, "MEM[1]" ],
68
+ [ "multiply", "MEM[1]", "MEM[0]", "MEM[1]" ],
69
+ [ "subtract", "[inside]", 32, "MEM[2]" ],
70
+ [ "multiply", "MEM[2]", "MEM[0]", "MEM[2]" ],
71
+ [ "subtract", "MEM[2]", "MEM[1]", "MEM[3]" ],
72
+ [ "round", "MEM[3]", 1, "[delta_in_c]" ]
73
+ ]
74
+ }
75
+ }
76
+ }
77
+
78
+ output {
79
+ stdout {
80
+ codec => rubydebug
81
+ }
82
+ }
83
+ -----
84
+
85
+ The resulting event looks like this.
86
+
87
+ [source,shell]
88
+ {
89
+ "inside" => 71.24,
90
+ "@timestamp" => 2018-06-23T13:25:22.298Z,
91
+ "sensor" => "temperature-1",
92
+ "delta_in_c" => 5.3,
93
+ "message" => "{\"sensor\":\"temperature-1\", \"inside\": 71.24, \"outside\": 61.7 }",
94
+ "@version" => "1",
95
+ "sequence" => 0,
96
+ "host" => "Elastics-MacBook-Pro.local",
97
+ "outside" => 61.7
98
+ }
99
+
100
+ [id="plugins-{type}s-{plugin}-options"]
101
+ ==== Math Filter Configuration Options
102
+
103
+ This plugin supports the following configuration options plus the <<plugins-{type}s-{plugin}-common-options>> described later.
104
+
105
+ [cols="<,<,<",options="header",]
106
+ |=======================================================================
107
+ |Setting |Input type|Required
108
+ | <<plugins-{type}s-{plugin}-calculate>> |<<array,array>> of <<array,array>>|Yes
109
+ |=======================================================================
110
+
111
+ Also see <<plugins-{type}s-{plugin}-common-options>> for a list of options supported by all
112
+ filter plugins.
113
+
114
+ &nbsp;
115
+
116
+ [id="plugins-{type}s-{plugin}-calculate"]
117
+ ===== `calculate`
118
+
119
+ * This is a required setting.
120
+ * Value type is <<array,array>> of <<array,array>>s
121
+ * There is no default value for this setting.
122
+
123
+ The calculation to be performed. As can be seen from the example above by using
124
+ multiple inner arrays one can perform calculation with multiple steps or multiple
125
+ distinct calculations on a single event.
126
+
127
+ Each inner array *must have 4 elements*
128
+
129
+ The first element must be the operator. Valid operators are:
130
+
131
+ [cols="<,<",options="header",]
132
+ |=======================================================================
133
+ | Operation | Representations
134
+ | Add | '+', 'add', 'plus'
135
+ | Subtract | '-', 'sub', 'subtract'
136
+ | Multiply | '*', 'mpx', 'times', 'multiply'
137
+ | Round | 'round'
138
+ | Power | '**', '^', 'to the power of'
139
+ | Divide | '/', 'div', 'divide'
140
+ | Modulo | 'mod', 'modulo'
141
+ | FloatDivide | 'fdiv', 'float divide'
142
+ |=======================================================================
143
+
144
+ [TIP]
145
+ You may use any of the representations to refer to an operator. For instance, long hand representation
146
+ maybe more clear to read when you or a co-worker looks at your config some months later.
147
+
148
+ The second element is the left hand side operand. It can be a field, a literal or a memory register.
149
+ If referring to a memory register, ensure that it has been set to a value in a previous calculation.
150
+ [NOTE]
151
+ A literal can be a float or an integer. Exponent expressions, e.g. `10e+3` are not supported.
152
+
153
+ The third element is the right hand side operand. It can be a field, a literal or a memory register.
154
+
155
+ The fourth element is the "target". It is where the result is stored and can be a
156
+ memory register or a field in your event. It cannot be a literal.
157
+ [NOTE]
158
+ You will get a warning if the target of the last calculation is a memory register because
159
+ the final result will not be added to the event.
160
+
161
+ ===== Valid Values
162
+ For a calculation to continue, any operand taken from a field in the event must be
163
+ `Numeric` or a `Logstash Timestamp` and not nil. Timestamps are converted to
164
+ floating point seconds since the UNIX epoch (Jan, 1 1970 00:00:00 UTC) before being operated on.
165
+
166
+ ===== Operators
167
+ The operators `Divide`, `FloatDivide` and `Modulo` have a divide by zero check before the operation is executed. +
168
+ The `Power` operator has a check for a negative number being raised to a fractional power as this results in
169
+ a Complex number that can't be stored in an event or serialized to JSON. +
170
+ The `Round` operator can convert integers to floats `round(42, 1) -> 42.0`
171
+ and floats to integers (rounding up or down) `round(0.75, 0) -> 1`.
172
+
173
+ ===== Memory Registers
174
+ You can choose not to use memory registers and store intermediate results in fields instead but then you may
175
+ need to remove the fields later. +
176
+ Memory registers are implemented as a sparse array and the integer between the square brackets is a zero based
177
+ direct index into the array. For example, `MEM[5]`, 5 is a reference to the 6th element in the array.
178
+ The array is cleared for each event, this means that you can't leave a value behind for a later event to use.
179
+ Each math filter will have its own memory register array so you can't share values between math filters
180
+ in the same pipeline or across pipelines.
181
+
182
+ [TIP]
183
+ Use the bracketed notation e.g. `[fieldname]` to better distinguish fields from
184
+ memory register references.
185
+
186
+ ===== Debugging
187
+ There is some logging of the calculation progress at the debug logging level. +
188
+ This is an excerpt from the full example at the top of this page:
189
+ [source,shell]
190
+ [DEBUG][logstash.filters.math ] executing {"function"=>"float_divide", "left_field"=>"operand 1: 5", "right_field"=>"operand 2: 9", "target"=>"register 0: 'MEM[0]'"}
191
+ [DEBUG][logstash.filters.math ] calculation result stored {"function"=>"float_divide", "target"=>"register 0: 'MEM[0]'", "result"=>0.5555555555555556}
192
+ [DEBUG][logstash.filters.math ] executing {"function"=>"subtract", "left_field"=>"event operand 1: '[outside]'", "right_field"=>"operand 2: 32", "target"=>"register 1: 'MEM[1]'"}
193
+ [DEBUG][logstash.filters.math ] calculation result stored {"function"=>"subtract", "target"=>"register 1: 'MEM[1]'", "result"=>#<BigDecimal:2c16adee,'0.297E2',3(4)>}
194
+ [DEBUG][logstash.filters.math ] executing {"function"=>"multiply", "left_field"=>"register operand 1: 'MEM[1]'", "right_field"=>"register operand 2: 'MEM[0]'", "target"=>"register 1: 'MEM[1]'"}
195
+ [DEBUG][logstash.filters.math ] calculation result stored {"function"=>"multiply", "target"=>"register 1: 'MEM[1]'", "result"=>#<BigDecimal:76bc6a4c,'0.1650000000000000132E2',19(20)>}
196
+ [DEBUG][logstash.filters.math ] executing {"function"=>"subtract", "left_field"=>"event operand 1: '[inside]'", "right_field"=>"operand 2: 32", "target"=>"register 2: 'MEM[2]'"}
197
+ [DEBUG][logstash.filters.math ] calculation result stored {"function"=>"subtract", "target"=>"register 2: 'MEM[2]'", "result"=>#<BigDecimal:6761cedc,'0.3924E2',4(8)>}
198
+ [DEBUG][logstash.filters.math ] executing {"function"=>"multiply", "left_field"=>"register operand 1: 'MEM[2]'", "right_field"=>"register operand 2: 'MEM[0]'", "target"=>"register 2: 'MEM[2]'"}
199
+ [DEBUG][logstash.filters.math ] calculation result stored {"function"=>"multiply", "target"=>"register 2: 'MEM[2]'", "result"=>#<BigDecimal:5b03b20a,'0.21800000000000001744E2',20(24)>}
200
+ [DEBUG][logstash.filters.math ] executing {"function"=>"subtract", "left_field"=>"register operand 1: 'MEM[2]'", "right_field"=>"register operand 2: 'MEM[1]'", "target"=>"register 3: 'MEM[3]'"}
201
+ [DEBUG][logstash.filters.math ] calculation result stored {"function"=>"subtract", "target"=>"register 3: 'MEM[3]'", "result"=>#<BigDecimal:2e0e043,'0.5300000000000000424E1',19(20)>}
202
+ [DEBUG][logstash.filters.math ] executing {"function"=>"round", "left_field"=>"register operand 1: 'MEM[3]'", "right_field"=>"operand 2: 1", "target"=>"event result: '[delta_in_c]'"}
203
+ [DEBUG][logstash.filters.math ] calculation result stored {"function"=>"round", "target"=>"event result: '[delta_in_c]'", "result"=>#<BigDecimal:5415cc0,'0.53E1',2(4)>}
204
+
205
+
206
+ [id="plugins-{type}s-{plugin}-common-options"]
207
+ include::{include_path}/{type}.asciidoc[]
@@ -1,14 +1,20 @@
1
- require "logstash/filters/base"
1
+ # encoding: utf-8
2
+
2
3
  require "logstash/namespace"
3
- # Do various simple math operations
4
+ require "logstash/filters/base"
5
+
6
+ require_relative "math_functions"
7
+ require_relative "math_calculation_elements"
8
+
9
+ # Do various simple math functions
4
10
  # Configuration:
5
11
  # filter {
6
12
  # math {
7
13
  # calculate => [
8
- # [ "add", "a_field1", "a_field2", "a_target" ], # a + b => target
9
- # [ "sub", "b_field1", "b_field2", "b_target" ], # a - b => target
10
- # [ "div", "c_field1", "c_field2", "c_target" ], # a / b => target
11
- # [ "mpx", "d_field1", "d_field2", "d_target" ] # a * b => target
14
+ # [ "+", "a_field1", "a_field2", "a_target" ], # a + b => target
15
+ # [ "-", "b_field1", "b_field2", "b_target" ], # a - b => target
16
+ # [ "/", "c_field1", "c_field2", "c_target" ], # a / b => target
17
+ # [ "*", "d_field1", "d_field2", "d_target" ] # a * b => target
12
18
  # ]
13
19
  # }
14
20
  # }
@@ -19,50 +25,107 @@ require "logstash/namespace"
19
25
  #
20
26
  # Works with float and integer values
21
27
 
22
- class LogStash::Filters::Math < LogStash::Filters::Base
28
+ module LogStash module Filters class Math < LogStash::Filters::Base
29
+ # TODO: Add support for unitary functions like abs and negation (-),
30
+ # these would have one operand and may or may not have a target.
31
+ # Add support for constants as either operand, e.g. seconds to millis, 100 / N
32
+ # Add support for conversions: distance(mi <-> km)
33
+ # Add support for percent change
23
34
  config_name "math"
24
35
 
25
36
  # fields - second subtracted from the first
26
37
  config :calculate, :validate => :array, :required => true
27
38
 
28
39
  public
40
+
29
41
  def register
30
- # Do some sanity checks that calculate is actually an array-of-arrays, and that each calculation (sub-array)
31
- # is exactly 4 fields and the first field is a valid calculation opperator name.
32
- for calculation in calculate do
33
- if calculation.length % 4 != 0
34
- abort("Each calculation must have 4 elements, this one had " + calculation.length + " " + calculation.to_s )
35
- end # end calculaction.length is 4
36
- if ! calculation[0].match('^(add|sub|div|mpx)$' )
37
- abort("First element of a calculation must be add|sub|div|mpx, but is: " + calculation[0] )
38
- end # if calculation[0] valid
39
- end # for each calculate
40
- end # def register
42
+ functions = {}
43
+ [
44
+ [MathFunctions::Add.new, '+', 'add', 'plus'],
45
+ [MathFunctions::Subtract.new, '-', 'sub', 'subtract'],
46
+ [MathFunctions::Multiply.new, '*', 'mpx', 'times', 'multiply'],
47
+ [MathFunctions::Round.new, 'round'],
48
+ [MathFunctions::Power.new, '**', '^', 'to the power of'],
49
+ [MathFunctions::Divide.new, '/', 'div', 'divide'],
50
+ [MathFunctions::Modulo.new, 'mod', 'modulo'],
51
+ [MathFunctions::FloatDivide.new, 'fdiv', 'float divide']
52
+ ].each do |list|
53
+ value = list.shift
54
+ list.each{|key| functions[key] = value}
55
+ end
56
+
57
+ # Do some sanity checks that calculate is actually an array of arrays, and that each calculation (inner array)
58
+ # is exactly 4 fields and the first field is a valid calculation operator name.
59
+ @calculate_copy = []
60
+ all_function_keys = functions.keys
61
+ @register = []
62
+ calculate.each do |calculation|
63
+ if calculation.size != 4
64
+ raise LogStash::ConfigurationError, I18n.t(
65
+ "logstash.runner.configuration.invalid_plugin_register",
66
+ :plugin => "filter",
67
+ :type => "math",
68
+ :error => "Invalid number of elements in a calculation setting: expected 4, got: #{calculation.size}. You specified: #{calculation}"
69
+ )
70
+ end
71
+ function_key, operand1, operand2, target = calculation
72
+ if !all_function_keys.include?(function_key)
73
+ raise LogStash::ConfigurationError, I18n.t(
74
+ "logstash.runner.configuration.invalid_plugin_register",
75
+ :plugin => "filter",
76
+ :type => "math",
77
+ :error => "Invalid first element of a calculation: expected one of #{all_function_keys.join(',')}, got: #{function_key}. You specified: #{calculation.join(',')}"
78
+ )
79
+ end
80
+ function = functions[function_key]
81
+
82
+ left_element = MathCalculationElements.build(operand1, 1, @register)
83
+ right_element = MathCalculationElements.build(operand2, 2, @register)
84
+ if right_element.literal?
85
+ lhs = left_element.literal? ? left_element.get : 1
86
+ warning = function.invalid?(lhs, right_element.get)
87
+ unless warning.nil?
88
+ raise LogStash::ConfigurationError, I18n.t(
89
+ "logstash.runner.configuration.invalid_plugin_register",
90
+ :plugin => "filter",
91
+ :type => "math",
92
+ :error => "Numeric literals are specified as in the calculation but the function invalidates with '#{warning}'. You specified: #{calculation.join(',')}"
93
+ )
94
+ end
95
+ end
96
+ result_element = MathCalculationElements.build(target, 3, @register)
97
+ @calculate_copy << [function, left_element, right_element, result_element]
98
+ end
99
+ if @calculate_copy.last.last.is_a?(MathCalculationElements::RegisterElement)
100
+ raise LogStash::ConfigurationError, I18n.t(
101
+ "logstash.runner.configuration.invalid_plugin_register",
102
+ :plugin => "filter",
103
+ :type => "math",
104
+ :error => "The final target is a Register, the overall calculation result will not be set in the event"
105
+ )
106
+ end
107
+ end
41
108
 
42
- public
43
109
  def filter(event)
44
- return unless filter?(event)
45
- for calculation in calculate do
46
- # Check that all the fields exist and are numeric
47
- next unless event.include?(calculation[1])
48
- next unless event.include?(calculation[2])
49
- next unless event.get(calculation[1]) == 0 or event.get(calculation[1]).is_a? Float or event.get(calculation[1]).is_a? Integer
50
- next unless event.get(calculation[2]) == 0 or event.get(calculation[2]).is_a? Float or event.get(calculation[2]).is_a? Integer
51
- case calculation[0]
52
- when "add"
53
- event.set( calculation[3], event.get(calculation[1]) + event.get(calculation[2]) )
54
- when "sub"
55
- event.set(calculation[3], event.get(calculation[1]) - event.get(calculation[2]) )
56
- when "div"
57
- # Avoid division by zero
58
- next if event.get( calculation[2] ) == 0
59
- event.set( calculation[3], event.get( calculation[1]).to_f / event.get(calculation[2]) )
60
- when "mpx"
61
- event.set( calculation[3], event.get( calculation[1]) * event.get( calculation[2] ) )
62
- end # case calculation[0]
63
- end # for each calculate
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.
112
+ @calculate_copy.each do |function, left_element, right_element, result_element|
113
+ logger.debug("executing", "function" => function.name, "left_field" => left_element, "right_field" => right_element, "target" => result_element)
114
+ # TODO add support for automatic conversion to Numeric if String
115
+ operand1 = left_element.get(event)
116
+ operand2 = right_element.get(event)
117
+ # allow all the validation warnings to be logged before we skip to next
118
+ next if operand1.nil? || operand2.nil?
119
+ next if function.invalid?(operand1, operand2, event)
120
+
121
+ result = function.call(operand1, operand2)
122
+ result_element.set(result, event)
123
+ logger.debug("calculation result stored", "function" => function.name, "target" => result_element, "result" => result)
124
+ event_changed = true
125
+ end
126
+ return unless event_changed
64
127
  filter_matched(event)
65
- end # def filter
66
- end # class LogStash::Filters::Math
128
+ end
129
+ end end end
67
130
 
68
131