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 +5 -5
- data/CHANGELOG.md +15 -0
- data/CONTRIBUTORS +11 -0
- data/Gemfile +8 -0
- data/README.md +17 -5
- data/docs/index.asciidoc +207 -0
- data/lib/logstash/filters/math.rb +104 -41
- data/lib/logstash/filters/math_calculation_elements.rb +128 -0
- data/lib/logstash/filters/math_functions.rb +142 -0
- data/logstash-filter-math.gemspec +8 -8
- data/spec/filters/math_spec.rb +316 -32
- data/spec/spec_helper.rb +4 -0
- metadata +28 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bcecb6c0a2a2be1670c7c579a48b0565b796609329d51ef1f12f2a6603ff25eb
|
4
|
+
data.tar.gz: 2ff472b3df566011a47c83bad03066c05ad7028f0a9be7aa4b29b11ae4f86bd6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
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
|
-
|
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
|
+
|
data/docs/index.asciidoc
ADDED
@@ -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
|
+
|
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
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
|
2
3
|
require "logstash/namespace"
|
3
|
-
|
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
|
-
# [ "
|
9
|
-
# [ "
|
10
|
-
# [ "
|
11
|
-
# [ "
|
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
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
66
|
-
end
|
128
|
+
end
|
129
|
+
end end end
|
67
130
|
|
68
131
|
|