logstash-filter-math 1.1.0 → 1.1.1
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
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
|