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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7acec65c8e0272d6a835d61e803de1b244cf838d649930dfaf8649e45c3388d0
|
4
|
+
data.tar.gz: 4ca406f2e0403317e20aaf74463c61b834399aa4840ef6a69d81357a24373d6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a005e6bf35f50b0e18207c875cab6d4878ad49088b8fe90bc1210946610cee915f281f427851407f5927a81e7ebea1dce4d942ec2078da501ded4a70a85e0ce5
|
7
|
+
data.tar.gz: 4dc84a9bd0a94b1c4ae727485f0ef6ba26e4d4c4ff96dbbb14edd59dbde45a101b6ba32da9ba77c389893a188e13c0642ae6a9a9a8a4498784d30068700caafa
|
data/CHANGELOG.md
CHANGED
@@ -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
|
83
|
-
right_element = MathCalculationElements.build(operand2, 2
|
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
|
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
|
-
|
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(
|
116
|
-
operand2 = right_element.get(
|
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,
|
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
|
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
|
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
|
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,
|
46
|
+
def set(value, event_register_context)
|
44
47
|
# raise usage error if called when position != 3 ??
|
45
|
-
|
48
|
+
event_register_context.set(self, value)
|
46
49
|
end
|
47
50
|
|
48
|
-
def get(
|
49
|
-
|
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,
|
75
|
-
|
82
|
+
def set(value, event_register_context)
|
83
|
+
event_register_context.set(self, value)
|
76
84
|
end
|
77
85
|
|
78
|
-
def get(
|
79
|
-
value =
|
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(
|
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.
|
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"
|
data/spec/filters/math_spec.rb
CHANGED
@@ -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.
|
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-
|
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
|