fluent-plugin-condition-checker 0.1.0 → 1.0.0
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 +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +18 -0
- data/Gemfile.lock +48 -0
- data/README.md +31 -3
- data/example/fluent.conf +31 -0
- data/example/scenario.json +1 -0
- data/fluent-plugin-condition-checker.gemspec +2 -2
- data/lib/fluent/plugin/out_condition_checker.rb +285 -311
- data/test/plugin/test_out_condition_checker.rb +59 -2
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14c83969fa6928655e996db271f6dab4483b32e7eb2c8282455a4664c96ab904
|
4
|
+
data.tar.gz: e437510a11585f4d31f69adca9bd9a714cf4d084eec45e89081565a44c9bfb47
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eed247f918a990606d53ab539cc11d0c266bc263e3385a34b3db33caa13b60ef6d1f94958ace69debad63ac6355fa1785cf0515692a7029e4d5afb7d518a530a
|
7
|
+
data.tar.gz: 17d4ffaa4def66e7baf802da002ef14f70c4e1007d30aab3451b8e949814cdcdbbb5f365ed2c54cef3748ccda3998663fdd89e1af686cc3bc7d372da424c1449
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg/
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Style/AsciiComments:
|
2
|
+
Enabled: false
|
3
|
+
Metrics/LineLength:
|
4
|
+
Max: 140
|
5
|
+
Naming/UncommunicativeMethodParamName:
|
6
|
+
Enabled: false
|
7
|
+
Metrics/AbcSize:
|
8
|
+
Max: 30
|
9
|
+
Metrics/MethodLength:
|
10
|
+
Max: 30
|
11
|
+
Metrics/PerceivedComplexity:
|
12
|
+
Max: 10
|
13
|
+
Metrics/CyclomaticComplexity:
|
14
|
+
Max: 10
|
15
|
+
Metrics/BlockLength:
|
16
|
+
Max: 45
|
17
|
+
Metrics/ClassLength:
|
18
|
+
Max: 120
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
fluent-plugin-condition-checker (1.0.0)
|
5
|
+
fluentd (>= 0.14.10, < 2)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
concurrent-ruby (1.1.7)
|
11
|
+
cool.io (1.7.0)
|
12
|
+
fluentd (1.11.4)
|
13
|
+
cool.io (>= 1.4.5, < 2.0.0)
|
14
|
+
http_parser.rb (>= 0.5.1, < 0.7.0)
|
15
|
+
msgpack (>= 1.3.1, < 2.0.0)
|
16
|
+
serverengine (>= 2.0.4, < 3.0.0)
|
17
|
+
sigdump (~> 0.2.2)
|
18
|
+
strptime (>= 0.2.2, < 1.0.0)
|
19
|
+
tzinfo (>= 1.0, < 3.0)
|
20
|
+
tzinfo-data (~> 1.0)
|
21
|
+
yajl-ruby (~> 1.0)
|
22
|
+
http_parser.rb (0.6.0)
|
23
|
+
msgpack (1.3.3)
|
24
|
+
power_assert (1.2.0)
|
25
|
+
rake (12.3.3)
|
26
|
+
serverengine (2.2.1)
|
27
|
+
sigdump (~> 0.2.2)
|
28
|
+
sigdump (0.2.4)
|
29
|
+
strptime (0.2.5)
|
30
|
+
test-unit (3.3.6)
|
31
|
+
power_assert
|
32
|
+
tzinfo (2.0.2)
|
33
|
+
concurrent-ruby (~> 1.0)
|
34
|
+
tzinfo-data (1.2020.2)
|
35
|
+
tzinfo (>= 1.0.0)
|
36
|
+
yajl-ruby (1.4.1)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
bundler (~> 2.0)
|
43
|
+
fluent-plugin-condition-checker!
|
44
|
+
rake (~> 12.0)
|
45
|
+
test-unit (~> 3.0)
|
46
|
+
|
47
|
+
BUNDLED WITH
|
48
|
+
2.1.4
|
data/README.md
CHANGED
@@ -28,6 +28,26 @@ $ bundle
|
|
28
28
|
|
29
29
|
## Configuration
|
30
30
|
|
31
|
+
```
|
32
|
+
<match **>
|
33
|
+
@type condition-checker
|
34
|
+
<condition>
|
35
|
+
condition record["faceId"] != nil
|
36
|
+
tag exists_face
|
37
|
+
<data>
|
38
|
+
concept exists_face
|
39
|
+
</data>
|
40
|
+
</condition>
|
41
|
+
<condition>
|
42
|
+
condition record["faceId"] -= nil
|
43
|
+
tag no_face
|
44
|
+
<data>
|
45
|
+
concept no_face
|
46
|
+
</data>
|
47
|
+
</condition>
|
48
|
+
</match>
|
49
|
+
```
|
50
|
+
|
31
51
|
You can generate configuration template:
|
32
52
|
|
33
53
|
```
|
@@ -36,8 +56,16 @@ $ fluent-plugin-config-format output condition-checker
|
|
36
56
|
|
37
57
|
You can copy and paste generated documents here.
|
38
58
|
|
59
|
+
## Development
|
60
|
+
|
61
|
+
1. test!
|
62
|
+
|
63
|
+
```
|
64
|
+
bundle exec rake test
|
65
|
+
```
|
66
|
+
|
39
67
|
## Copyright
|
40
68
|
|
41
|
-
|
42
|
-
|
43
|
-
|
69
|
+
- Copyright(c) 2020- wally
|
70
|
+
- License
|
71
|
+
- Apache License, Version 2.0
|
data/example/fluent.conf
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
<source>
|
2
|
+
@type forward
|
3
|
+
port 24224
|
4
|
+
</source>
|
5
|
+
|
6
|
+
<match **>
|
7
|
+
@type copy
|
8
|
+
<store>
|
9
|
+
@type stdout
|
10
|
+
</store>
|
11
|
+
<store>
|
12
|
+
@type condition-checker
|
13
|
+
tag "speak_condition"
|
14
|
+
<condition>
|
15
|
+
rule record["action"] == "speak"
|
16
|
+
condition "speak_action"
|
17
|
+
<data>
|
18
|
+
word record["word"] + "こんにちは"
|
19
|
+
aditiona_data 1
|
20
|
+
</data>
|
21
|
+
</condition>
|
22
|
+
<condition>
|
23
|
+
rule record["action"] == "alert"
|
24
|
+
condition "alert_action"
|
25
|
+
<data>
|
26
|
+
word record["word"] + "はじめまして"
|
27
|
+
</data>
|
28
|
+
</condition>
|
29
|
+
</store>
|
30
|
+
</match>
|
31
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
{"label":"greeting","priority":2,"limit":30,"action":"greet"}
|
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |spec|
|
5
5
|
spec.name = "fluent-plugin-condition-checker"
|
6
|
-
spec.version = "
|
6
|
+
spec.version = "1.0.0"
|
7
7
|
spec.authors = ["wally"]
|
8
8
|
spec.email = ["u.str.gm@gmail.com"]
|
9
9
|
|
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.test_files = test_files
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
|
23
|
-
spec.add_development_dependency "bundler", "~>
|
23
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
24
24
|
spec.add_development_dependency "rake", "~> 12.0"
|
25
25
|
spec.add_development_dependency "test-unit", "~> 3.0"
|
26
26
|
spec.add_runtime_dependency "fluentd", [">= 0.14.10", "< 2"]
|
@@ -23,362 +23,336 @@ module Fluent
|
|
23
23
|
Fluent::Plugin.register_output("condition_checker", self)
|
24
24
|
|
25
25
|
helpers :event_emitter
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
config_param ('tag' + i.to_s).to_sym, :string, default: nil,
|
51
|
-
desc: 'Specify tag'+i.to_s+' (not necessary)'
|
52
|
-
config_param ('condition' + i.to_s).to_sym, :string, default: nil, # NAME REGEXP
|
53
|
-
desc: 'Specify the condition'+i.to_s+' to evaluate (not necessary)'
|
54
|
-
end
|
26
|
+
PATTERN_MAX_NUM = 20
|
27
|
+
|
28
|
+
config_param :remove_keys, :string, :default => nil,
|
29
|
+
:desc => 'Specify record keys to be removed by a string separated by , (comma).'
|
30
|
+
config_param :keep_keys, :string, :default => nil,
|
31
|
+
:desc => 'Specify record keys to be kept by a string separated by , (comma).'
|
32
|
+
config_param :renew_record, :bool, :default => false,
|
33
|
+
:desc => 'Creates an output record newly without extending (merging) the input record fields.'
|
34
|
+
config_param :renew_time_key, :string, :default => nil,
|
35
|
+
:desc => 'Overwrites the time of events with a value of the record field.'
|
36
|
+
# it should always be true
|
37
|
+
config_param :enable_ruby, :bool, :default => true, # true for lower version compatibility
|
38
|
+
:desc => 'Enable to use ruby codes in placeholders.'
|
39
|
+
# it should always be true
|
40
|
+
config_param :auto_typecast, :bool, :default => true, # false for lower version compatibility
|
41
|
+
:desc => 'Automatically cast the field types.'
|
42
|
+
config_param :tag, :string, :default => 'checked_tag', :desc => "new record tag."
|
43
|
+
|
44
|
+
config_param(
|
45
|
+
"condition".to_sym,
|
46
|
+
:hash,
|
47
|
+
default: nil,
|
48
|
+
desc: 'It is Conditions.'
|
49
|
+
)
|
55
50
|
|
56
|
-
|
57
|
-
:desc => 'Specify the output tag name when the no conditions are true.'
|
51
|
+
BUILTIN_CONFIGURATIONS = %W(@id @type @label type output_tag remove_keys renew_record keep_keys enable_ruby renew_time_key auto_typecast tag_else record_else tag)
|
58
52
|
|
53
|
+
def configure(conf)
|
54
|
+
super
|
55
|
+
# ここで、BUILTIN_CONFIGURATIONS に入っていないものがあった場合はerrorをraise
|
56
|
+
conf.each_pair { |k, v|
|
57
|
+
next if BUILTIN_CONFIGURATIONS.include?(k) || k.match(/^condition\d\d?$/) || k.match(/^tag\d\d?$/)
|
59
58
|
|
60
|
-
|
59
|
+
raise Fluent::ConfigError, 'out_condition_checker: some weird config is set {'+k.to_s+':'+v.to_s+'}'
|
60
|
+
}
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
62
|
+
# conditionsを読み込む
|
63
|
+
@conditions = []
|
64
|
+
conf.elements.select { |element| element.name.match(/^condition?$/) }
|
65
|
+
.each do |param|
|
66
|
+
condition = {}
|
67
|
+
data_record = {}
|
68
|
+
|
69
|
+
param.elements.select { |element| element.name.match(/^data?$/) }.each do |data|
|
70
|
+
data.each_pair do |key, value|
|
71
|
+
data_record.merge!(key => convert_value(value))
|
72
|
+
end
|
73
|
+
end
|
68
74
|
|
69
|
-
|
70
|
-
|
75
|
+
param.each_pair do |key, value|
|
76
|
+
condition.merge!(key => convert_value(value))
|
77
|
+
end
|
71
78
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
next unless conf["tag#{i}"]
|
76
|
-
tags.push(conf["tag#{i}"]) # tags[i+1] で、欲しいtagにアクセスできる
|
77
|
-
end
|
79
|
+
condition.merge!("data" => data_record)
|
80
|
+
@conditions.push(condition)
|
81
|
+
end
|
78
82
|
|
79
|
-
#conditionを読み込み
|
80
|
-
@conditions = []
|
81
|
-
(1..PATTERN_MAX_NUM).each do |i|
|
82
|
-
next unless conf["condition#{i}"]
|
83
|
-
@conditions.push(conf["condition#{i}"])
|
84
|
-
end
|
85
|
-
if tags.size != @conditions.size
|
86
|
-
raise Fluent::ConfigError, 'match the numbers of tags and conditions; number of tags: '+tags.size.to_s+', number of conditions: '+@conditions.size.to_s
|
87
|
-
end
|
88
83
|
|
84
|
+
if @remove_keys
|
85
|
+
@remove_keys = @remove_keys.split(',')
|
86
|
+
end
|
87
|
+
if @keep_keys
|
88
|
+
raise Fluent::ConfigError, 'out_condition_checker: `renew_record` must be true to use `keep_keys`' unless @renew_record
|
89
|
+
@keep_keys = @keep_keys.split(',')
|
90
|
+
end
|
89
91
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
(1..PATTERN_MAX_NUM).each do |i|
|
94
|
-
next unless conf["condition#{i}"] # 対応するcondition{i}が定義されているものだけ読み込む
|
95
|
-
conf.elements.select { |element| element.name == 'record'+i.to_s }.each { |element|
|
96
|
-
recordTmp = {}
|
97
|
-
element.each_pair { |k, v|
|
98
|
-
element.has_key?(k) # to suppress unread configuration warning
|
99
|
-
recordTmp.merge!({k => parse_value(v)})
|
100
|
-
# map_if_false[k] = parse_value(v)
|
92
|
+
placeholder_expander_params = {
|
93
|
+
:log => log,
|
94
|
+
:auto_typecast => @auto_typecast, # It should always be true
|
101
95
|
}
|
102
|
-
maps[i] = recordTmp
|
103
|
-
}
|
104
|
-
end
|
105
96
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
@remove_keys = @remove_keys.split(',')
|
118
|
-
end
|
119
|
-
if @keep_keys
|
120
|
-
raise Fluent::ConfigError, 'out_condition_checker: `renew_record` must be true to use `keep_keys`' unless @renew_record
|
121
|
-
@keep_keys = @keep_keys.split(',')
|
122
|
-
end
|
97
|
+
@placeholder_expander =
|
98
|
+
if @enable_ruby
|
99
|
+
# require utilities which would be used in ruby placeholders
|
100
|
+
require 'pathname'
|
101
|
+
require 'uri'
|
102
|
+
require 'cgi'
|
103
|
+
RubyPlaceholderExpander.new(placeholder_expander_params)
|
104
|
+
else
|
105
|
+
p 'WARN!! Hey! You should enable ruby!!!'
|
106
|
+
PlaceholderExpander.new(placeholder_expander_params)
|
107
|
+
end
|
123
108
|
|
124
|
-
placeholder_expander_params = {
|
125
|
-
:log => log,
|
126
|
-
:auto_typecast => @auto_typecast, # It should always be true
|
127
|
-
}
|
128
|
-
|
129
|
-
@placeholder_expander =
|
130
|
-
if @enable_ruby
|
131
|
-
# require utilities which would be used in ruby placeholders
|
132
|
-
require 'pathname'
|
133
|
-
require 'uri'
|
134
|
-
require 'cgi'
|
135
|
-
RubyPlaceholderExpander.new(placeholder_expander_params)
|
136
|
-
else
|
137
|
-
p 'WARN!! Hey! You should enable ruby!!!'
|
138
|
-
PlaceholderExpander.new(placeholder_expander_params)
|
139
|
-
end
|
140
109
|
|
110
|
+
@hostname = Socket.gethostname
|
111
|
+
end
|
141
112
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
113
|
+
def process(tag, es)
|
114
|
+
tag_parts = tag.split('.')
|
115
|
+
tag_prefix = tag_prefix(tag_parts)
|
116
|
+
tag_suffix = tag_suffix(tag_parts)
|
117
|
+
placeholder_values = {
|
118
|
+
'tag' => tag,
|
119
|
+
'tags' => tag_parts, # for old version compatibility
|
120
|
+
'tag_parts' => tag_parts,
|
121
|
+
'tag_prefix' => tag_prefix,
|
122
|
+
'tag_suffix' => tag_suffix,
|
123
|
+
'hostname' => @hostname,
|
124
|
+
}
|
125
|
+
es.each {|time, record|
|
126
|
+
placeholder_values.merge!({
|
127
|
+
'time' => @placeholder_expander.time_value(time),
|
128
|
+
'record' => record,
|
129
|
+
})
|
130
|
+
|
131
|
+
# TODO: ここの処理よくないって evaluate
|
132
|
+
matched_conditions, aditional_data = evaluate_condition(@conditions, placeholder_values )
|
133
|
+
|
134
|
+
if matched_conditions.size > 0
|
135
|
+
new_record = reform(record, aditional_data, placeholder_values)
|
136
|
+
if @renew_time_key && new_record.has_key?(@renew_time_key)
|
137
|
+
time = new_record[@renew_time_key].to_i
|
138
|
+
end
|
139
|
+
@remove_keys.each {|k| new_record.delete(k) } if @remove_keys
|
140
|
+
router.emit(@tag, time, new_record)
|
141
|
+
end
|
142
|
+
}
|
143
|
+
rescue => e
|
144
|
+
log.warn "condition_checker: #{e.class} #{e.message} #{e.backtrace.first}"
|
145
|
+
end
|
146
146
|
|
147
|
-
|
148
|
-
end
|
147
|
+
private
|
149
148
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
}
|
162
|
-
es.each {|time, record|
|
163
|
-
placeholder_values.merge!({
|
164
|
-
'time' => @placeholder_expander.time_value(time),
|
165
|
-
'record' => record,
|
166
|
-
})
|
167
|
-
|
168
|
-
# TODO: ここの処理よくないって evaluate
|
169
|
-
result, idx = evaluate_condition(@conditions, placeholder_values)
|
170
|
-
placeholder_values.merge!({ 'result' => result })
|
171
|
-
|
172
|
-
if idx
|
173
|
-
new_tag, new_record = reform(@tags[idx], @maps[idx+1], record, placeholder_values)
|
174
|
-
else
|
175
|
-
# TODO: tag_elseは使えなくするoption作る"
|
176
|
-
new_tag, new_record = reform(@tag_else, @map_else, record, placeholder_values)
|
177
|
-
# return
|
149
|
+
def evaluate_condition(conditions, placeholders)
|
150
|
+
matched_conditions = []
|
151
|
+
aditional_data = {}
|
152
|
+
conditions.each_with_index{ |condition, idx|
|
153
|
+
result = expand_placeholders(condition["rule"], placeholders)
|
154
|
+
if result
|
155
|
+
matched_conditions.push(condition["condition"])
|
156
|
+
aditional_data.merge!(condition["data"])
|
157
|
+
end
|
158
|
+
}
|
159
|
+
return matched_conditions, aditional_data
|
178
160
|
end
|
179
161
|
|
180
|
-
|
181
|
-
if
|
182
|
-
|
162
|
+
def parse_value(value_str)
|
163
|
+
if value_str.start_with?('{', '[')
|
164
|
+
JSON.parse(value_str)
|
165
|
+
else
|
166
|
+
value_str
|
183
167
|
end
|
184
|
-
|
185
|
-
|
168
|
+
rescue => e
|
169
|
+
log.warn "failed to parse #{value_str} as json. Assuming #{value_str} is a string", :error_class => e.class, :error => e.message
|
170
|
+
value_str # emit as string
|
186
171
|
end
|
187
|
-
}
|
188
|
-
rescue => e
|
189
|
-
log.warn "condition_checker: #{e.class} #{e.message} #{e.backtrace.first}"
|
190
|
-
end
|
191
172
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
}
|
199
|
-
[@map_else, nil]
|
200
|
-
end
|
201
|
-
|
202
|
-
def parse_value(value_str)
|
203
|
-
if value_str.start_with?('{', '[')
|
204
|
-
JSON.parse(value_str)
|
205
|
-
else
|
206
|
-
value_str
|
207
|
-
end
|
208
|
-
rescue => e
|
209
|
-
log.warn "failed to parse #{value_str} as json. Assuming #{value_str} is a string", :error_class => e.class, :error => e.message
|
210
|
-
value_str # emit as string
|
211
|
-
end
|
173
|
+
def reform(record, aditional_data, placeholder_values)
|
174
|
+
new_record = @renew_record ? {} : record.dup
|
175
|
+
new_record.merge!(create_record(aditional_data, placeholder_values))
|
176
|
+
@keep_keys.each {|k| new_record[k] = record[k]} if @keep_keys and @renew_record
|
177
|
+
return new_record
|
178
|
+
end
|
212
179
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
180
|
+
def create_record(map, placeholders)
|
181
|
+
new_record = {}
|
182
|
+
map.each do |k, v|
|
183
|
+
value = @placeholder_expander.expand(v, placeholders, true)
|
184
|
+
if value.nil?
|
185
|
+
new_record.merge!({ k => convert_num(v) })
|
186
|
+
else
|
187
|
+
new_record.merge!({ k => convert_num(value) })
|
188
|
+
end
|
189
|
+
end
|
190
|
+
pp new_record
|
221
191
|
|
222
|
-
|
223
|
-
|
192
|
+
new_record
|
193
|
+
end
|
224
194
|
|
225
|
-
|
226
|
-
|
195
|
+
def convert_num(value)
|
196
|
+
# Booleanがチェック
|
197
|
+
if value == "true"
|
198
|
+
return true
|
199
|
+
elsif value == "false"
|
200
|
+
return false
|
201
|
+
end
|
202
|
+
|
203
|
+
if value.to_i.to_s == value.to_s
|
204
|
+
return value.to_i
|
205
|
+
else
|
206
|
+
return value
|
207
|
+
end
|
208
|
+
end
|
227
209
|
|
228
|
-
|
229
|
-
|
210
|
+
def convert_value(value)
|
211
|
+
# Booleanがチェック
|
212
|
+
return true if value == 'true'
|
230
213
|
|
231
|
-
|
232
|
-
end
|
214
|
+
return false if value == 'false'
|
233
215
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
return true
|
238
|
-
elsif value == "false"
|
239
|
-
return false
|
240
|
-
end
|
241
|
-
|
242
|
-
if value.to_i.to_s == value.to_s
|
243
|
-
return value.to_i
|
244
|
-
else
|
245
|
-
return value
|
246
|
-
end
|
247
|
-
end
|
216
|
+
# 数値データなら数値で返す
|
217
|
+
return value.to_i if value.to_i.to_s == value.to_s
|
218
|
+
return value.to_f if value.to_f.to_s == value.to_s
|
248
219
|
|
249
|
-
|
250
|
-
if value.is_a?(String)
|
251
|
-
new_value = @placeholder_expander.expand(value, placeholders)
|
252
|
-
elsif value.is_a?(Hash)
|
253
|
-
new_value = {}
|
254
|
-
value.each_pair do |k, v|
|
255
|
-
new_key = @placeholder_expander.expand(k, placeholders, true)
|
256
|
-
new_value[new_key] = expand_placeholders(v, placeholders)
|
220
|
+
value
|
257
221
|
end
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
222
|
+
|
223
|
+
def expand_placeholders(value, placeholders)
|
224
|
+
if value.is_a?(String)
|
225
|
+
new_value = @placeholder_expander.expand(value, placeholders)
|
226
|
+
elsif value.is_a?(Hash)
|
227
|
+
new_value = {}
|
228
|
+
value.each_pair do |k, v|
|
229
|
+
new_key = @placeholder_expander.expand(k, placeholders, true)
|
230
|
+
new_value[new_key] = expand_placeholders(v, placeholders)
|
231
|
+
end
|
232
|
+
elsif value.is_a?(Array)
|
233
|
+
new_value = []
|
234
|
+
value.each_with_index do |v, i|
|
235
|
+
new_value[i] = expand_placeholders(v, placeholders)
|
236
|
+
end
|
237
|
+
else
|
238
|
+
new_value = value
|
239
|
+
end
|
240
|
+
new_value
|
262
241
|
end
|
263
|
-
else
|
264
|
-
new_value = value
|
265
|
-
end
|
266
|
-
new_value
|
267
|
-
end
|
268
242
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
243
|
+
def tag_prefix(tag_parts)
|
244
|
+
return [] if tag_parts.empty?
|
245
|
+
tag_prefix = [tag_parts.first]
|
246
|
+
1.upto(tag_parts.size-1).each do |i|
|
247
|
+
tag_prefix[i] = "#{tag_prefix[i-1]}.#{tag_parts[i]}"
|
248
|
+
end
|
249
|
+
tag_prefix
|
250
|
+
end
|
277
251
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
252
|
+
def tag_suffix(tag_parts)
|
253
|
+
return [] if tag_parts.empty?
|
254
|
+
rev_tag_parts = tag_parts.reverse
|
255
|
+
rev_tag_suffix = [rev_tag_parts.first]
|
256
|
+
1.upto(tag_parts.size-1).each do |i|
|
257
|
+
rev_tag_suffix[i] = "#{rev_tag_parts[i]}.#{rev_tag_suffix[i-1]}"
|
258
|
+
end
|
259
|
+
rev_tag_suffix.reverse!
|
260
|
+
end
|
287
261
|
|
288
|
-
|
289
|
-
|
290
|
-
|
262
|
+
# THIS CLASS MUST BE THREAD-SAFE
|
263
|
+
class RubyPlaceholderExpander
|
264
|
+
attr_reader :log
|
291
265
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
266
|
+
def initialize(params)
|
267
|
+
@log = params[:log]
|
268
|
+
@auto_typecast = params[:auto_typecast]
|
269
|
+
@cleanroom_expander = CleanroomExpander.new
|
270
|
+
end
|
297
271
|
|
298
|
-
|
299
|
-
|
300
|
-
|
272
|
+
def time_value(time)
|
273
|
+
Time.at(time)
|
274
|
+
end
|
301
275
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
276
|
+
# Preprocess record map to convert into ruby string expansion
|
277
|
+
#
|
278
|
+
# @param [Hash|String|Array] value record map config
|
279
|
+
# @param [Boolean] force_stringify the value must be string, used for hash key
|
280
|
+
def preprocess_map(value, force_stringify = false)
|
281
|
+
new_value = nil
|
282
|
+
if value.is_a?(String)
|
283
|
+
if @auto_typecast and !force_stringify
|
284
|
+
num_placeholders = value.scan('${').size
|
285
|
+
if num_placeholders == 1 and value.start_with?('${') && value.end_with?('}')
|
286
|
+
new_value = value[2..-2] # ${..} => ..
|
287
|
+
end
|
288
|
+
end
|
289
|
+
unless new_value
|
290
|
+
new_value = "%Q[#{value.gsub('${', '#{')}]" # xx${..}xx => %Q[xx#{..}xx]
|
291
|
+
end
|
292
|
+
elsif value.is_a?(Hash)
|
293
|
+
new_value = {}
|
294
|
+
value.each_pair do |k, v|
|
295
|
+
new_value[preprocess_map(k, true)] = preprocess_map(v)
|
296
|
+
end
|
297
|
+
elsif value.is_a?(Array)
|
298
|
+
new_value = []
|
299
|
+
value.each_with_index do |v, i|
|
300
|
+
new_value[i] = preprocess_map(v)
|
301
|
+
end
|
302
|
+
else
|
303
|
+
new_value = value
|
313
304
|
end
|
305
|
+
new_value
|
314
306
|
end
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
new_value = {}
|
320
|
-
value.each_pair do |k, v|
|
321
|
-
new_value[preprocess_map(k, true)] = preprocess_map(v)
|
322
|
-
end
|
323
|
-
elsif value.is_a?(Array)
|
324
|
-
new_value = []
|
325
|
-
value.each_with_index do |v, i|
|
326
|
-
new_value[i] = preprocess_map(v)
|
307
|
+
|
308
|
+
# FIXME: 引数返すだけの関数があるので削除
|
309
|
+
def prepare_placeholders(placeholder_values)
|
310
|
+
placeholder_values
|
327
311
|
end
|
328
|
-
else
|
329
|
-
new_value = value
|
330
|
-
end
|
331
|
-
new_value
|
332
|
-
end
|
333
312
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
313
|
+
# Expand string with placeholders
|
314
|
+
#
|
315
|
+
# @param [String] str
|
316
|
+
def expand(str, placeholders, force_stringify = false)
|
317
|
+
# FIXME: tag情報は使用してなさそうなので, 不必要であれば
|
318
|
+
@cleanroom_expander.expand(
|
319
|
+
str,
|
320
|
+
placeholders['tag'],
|
321
|
+
placeholders['time'],
|
322
|
+
placeholders['record'],
|
323
|
+
placeholders['tag_parts'],
|
324
|
+
placeholders['tag_prefix'],
|
325
|
+
placeholders['tag_suffix'],
|
326
|
+
placeholders['hostname']
|
327
|
+
)
|
328
|
+
rescue => e
|
329
|
+
log.warn "record_reformer: failed to expand `#{str}`", :error_class => e.class, :error => e.message
|
330
|
+
log.warn_backtrace
|
331
|
+
nil
|
332
|
+
end
|
338
333
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
@cleanroom_expander.expand(
|
345
|
-
str,
|
346
|
-
placeholders['tag'],
|
347
|
-
placeholders['time'],
|
348
|
-
placeholders['record'],
|
349
|
-
placeholders['tag_parts'],
|
350
|
-
placeholders['tag_prefix'],
|
351
|
-
placeholders['tag_suffix'],
|
352
|
-
placeholders['hostname']
|
353
|
-
)
|
354
|
-
rescue => e
|
355
|
-
log.warn "record_reformer: failed to expand `#{str}`", :error_class => e.class, :error => e.message
|
356
|
-
log.warn_backtrace
|
357
|
-
nil
|
358
|
-
end
|
334
|
+
class CleanroomExpander
|
335
|
+
def expand(__str_to_eval__, tag, time, record, tag_parts, tag_prefix, tag_suffix, hostname, force_stringify = true)
|
336
|
+
Thread.current[:record_reformer_record] = record # for old version compatibility
|
337
|
+
instance_eval(__str_to_eval__)
|
338
|
+
end
|
359
339
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
340
|
+
# for old version compatibility
|
341
|
+
def method_missing(name)
|
342
|
+
key = name.to_s
|
343
|
+
record = Thread.current[:record_reformer_record]
|
344
|
+
if record.has_key?(key)
|
345
|
+
record[key]
|
346
|
+
else
|
347
|
+
raise NameError, "undefined local variable or method `#{key}'"
|
348
|
+
end
|
349
|
+
end
|
365
350
|
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
record = Thread.current[:record_reformer_record]
|
370
|
-
if record.has_key?(key)
|
371
|
-
record[key]
|
372
|
-
else
|
373
|
-
raise NameError, "undefined local variable or method `#{key}'"
|
351
|
+
(Object.instance_methods).each do |m|
|
352
|
+
undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/
|
353
|
+
end
|
374
354
|
end
|
375
355
|
end
|
376
|
-
|
377
|
-
(Object.instance_methods).each do |m|
|
378
|
-
undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/
|
379
|
-
end
|
380
|
-
end
|
381
356
|
end
|
382
357
|
end
|
383
358
|
end
|
384
|
-
|
@@ -6,8 +6,65 @@ class ConditionCheckerOutputTest < Test::Unit::TestCase
|
|
6
6
|
Fluent::Test.setup
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
def create_driver(conf)
|
10
|
+
Fluent::Test::Driver::Output.new(Fluent::Plugin::ConditionCheckerOutput).configure(conf)
|
11
|
+
end
|
12
|
+
|
13
|
+
test "simple_configure" do
|
14
|
+
conf = config_element(
|
15
|
+
'ROOT',
|
16
|
+
'',
|
17
|
+
{'tag' => "speak_chekc"},
|
18
|
+
[
|
19
|
+
config_element(
|
20
|
+
'condition',
|
21
|
+
'',
|
22
|
+
{
|
23
|
+
'rule' => 'record["action"] == "speak"',
|
24
|
+
'condition' => 'speaking'
|
25
|
+
},
|
26
|
+
[
|
27
|
+
config_element(
|
28
|
+
'data',
|
29
|
+
'',
|
30
|
+
{
|
31
|
+
'new_word' => 'record["word"] + "こんにちは"',
|
32
|
+
'aaa' => 1
|
33
|
+
},
|
34
|
+
[]
|
35
|
+
)
|
36
|
+
]
|
37
|
+
),
|
38
|
+
config_element(
|
39
|
+
'condition',
|
40
|
+
'',
|
41
|
+
{
|
42
|
+
'rule' => 'record["action"] != "speak"',
|
43
|
+
'condition' => 'no_speak'
|
44
|
+
},
|
45
|
+
[
|
46
|
+
config_element(
|
47
|
+
'data',
|
48
|
+
'',
|
49
|
+
{
|
50
|
+
'new_word' => 'record["word"] + "はじめまして"'
|
51
|
+
},
|
52
|
+
[]
|
53
|
+
)
|
54
|
+
]
|
55
|
+
)
|
56
|
+
]
|
57
|
+
)
|
58
|
+
d = create_driver(conf)
|
59
|
+
d.run(default_tag: 'test') do
|
60
|
+
record = {
|
61
|
+
'action' => "speak",
|
62
|
+
"word" => "aaa"
|
63
|
+
}
|
64
|
+
d.feed(record)
|
65
|
+
events = d.events
|
66
|
+
pp events
|
67
|
+
end
|
11
68
|
end
|
12
69
|
|
13
70
|
private
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-condition-checker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- wally
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-10-
|
11
|
+
date: 2020-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -79,10 +79,15 @@ executables: []
|
|
79
79
|
extensions: []
|
80
80
|
extra_rdoc_files: []
|
81
81
|
files:
|
82
|
+
- ".gitignore"
|
83
|
+
- ".rubocop.yml"
|
82
84
|
- Gemfile
|
85
|
+
- Gemfile.lock
|
83
86
|
- LICENSE
|
84
87
|
- README.md
|
85
88
|
- Rakefile
|
89
|
+
- example/fluent.conf
|
90
|
+
- example/scenario.json
|
86
91
|
- fluent-plugin-condition-checker.gemspec
|
87
92
|
- lib/fluent/plugin/out_condition_checker.rb
|
88
93
|
- test/helper.rb
|