fluent-plugin-conditional_filter 0.0.3 → 0.0.4
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/README.md +51 -0
- data/fluent-plugin-conditional_filter.gemspec +2 -2
- data/lib/fluent/plugin/conditional_filter_rule.rb +30 -0
- data/lib/fluent/plugin/filter_conditional.rb +24 -0
- data/lib/fluent/plugin/out_conditional_filter.rb +3 -30
- data/spec/lib/filter_conditional_spec.rb +220 -0
- data/spec/spec_helper.rb +2 -1
- metadata +14 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e96a9f324a32ecb3745e54e5d249407cea733ce
|
4
|
+
data.tar.gz: 853c3cbe3440a42d81b7a72f3642f2592ac16646
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eec6a1bae7039cbdd952e0cd772b584f59e22b4cf9182eff13bcd551383c3d0a880a67954a66f25aeacb811a395c2cb1bd14aed07fe5badfffd299b7d107a7b0
|
7
|
+
data.tar.gz: 0a3dc292804cde6c81b3b19572170ba39eaeca7ff42b83ab0ac2b61eb8eeb75839204fc34e15dbfd9e8af1ce93669abeb709b4d1b66e9c8c572a75263be12cb7
|
data/README.md
CHANGED
@@ -2,6 +2,57 @@
|
|
2
2
|
|
3
3
|
## Component
|
4
4
|
|
5
|
+
### ConditionalFilter
|
6
|
+
|
7
|
+
fluent-plugin-conditional_filter provides a simple filter that filters out key/value pairs that don't satisfy a given condition. This is the filter version of [ConditionalFilterOutput](#conditionalfilteroutput).
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
### Synopsis
|
12
|
+
|
13
|
+
If there's such a configuration as below:
|
14
|
+
|
15
|
+
```
|
16
|
+
<filter test.**>
|
17
|
+
type conditional
|
18
|
+
key_pattern @example\.com$
|
19
|
+
condition 10
|
20
|
+
filter numeric_upward
|
21
|
+
</filter>
|
22
|
+
```
|
23
|
+
|
24
|
+
When the log below reaches:
|
25
|
+
|
26
|
+
```
|
27
|
+
'test' => {
|
28
|
+
'foo@example.com' => 5,
|
29
|
+
'bar@example.com' => 15,
|
30
|
+
'baz@baz.com' => 12,
|
31
|
+
}
|
32
|
+
```
|
33
|
+
|
34
|
+
key/value pairs that don't match either `key_pattern` or the condition designated by `condition` and `filter` are filtered out.
|
35
|
+
|
36
|
+
```
|
37
|
+
'filtered.test' => {
|
38
|
+
'bar@example.com' => 15,
|
39
|
+
}
|
40
|
+
```
|
41
|
+
|
42
|
+
### Params
|
43
|
+
|
44
|
+
#### `key_pattern` (required)
|
45
|
+
|
46
|
+
Key pattern to check.
|
47
|
+
|
48
|
+
#### `condition` (required)
|
49
|
+
|
50
|
+
Condition for the filter below.
|
51
|
+
|
52
|
+
#### `filter` (required)
|
53
|
+
|
54
|
+
Set filtering strategy.
|
55
|
+
|
5
56
|
### ConditionalFilterOutput
|
6
57
|
|
7
58
|
fluent-plugin-conditional_filter provides a simple filter that filters out key/value pairs that don't satisfy a given condition.
|
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'fluent-plugin-conditional_filter'
|
7
|
-
spec.version = '0.0.
|
7
|
+
spec.version = '0.0.4'
|
8
8
|
spec.authors = ['Kentaro Kuribayashi']
|
9
9
|
spec.email = ['kentarok@gmail.com']
|
10
10
|
spec.description = %q{A fluent plugin that provides conditional filters}
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ['lib']
|
19
19
|
|
20
|
-
spec.add_runtime_dependency 'fluentd'
|
20
|
+
spec.add_runtime_dependency 'fluentd', [">= 0.14.0", "< 2"]
|
21
21
|
|
22
22
|
spec.add_development_dependency 'bundler'
|
23
23
|
spec.add_development_dependency 'rake'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'fluent/output'
|
2
|
+
|
3
|
+
module Fluent
|
4
|
+
module ConditionalFilterRule
|
5
|
+
def filter_record(tag, time, record, plugin)
|
6
|
+
super(tag, time, record) if plugin.is_a?(Fluent::Output)
|
7
|
+
case @filter
|
8
|
+
when 'numeric_upward'
|
9
|
+
filter_record = record.select do |key, value|
|
10
|
+
key.match(@key_pattern_regexp) &&
|
11
|
+
record[key].to_f >= @condition.to_f
|
12
|
+
end
|
13
|
+
when 'numeric_downward'
|
14
|
+
filter_record = record.select do |key, value|
|
15
|
+
key.match(@key_pattern_regexp) &&
|
16
|
+
record[key].to_f <= @condition.to_f
|
17
|
+
end
|
18
|
+
when 'string_match'
|
19
|
+
filter_record = record.select do |key, value|
|
20
|
+
key.match(@key_pattern_regexp) &&
|
21
|
+
record[key].match(Regexp.new(@condition))
|
22
|
+
end
|
23
|
+
else
|
24
|
+
raise ArgumentError.new("[conditional_filter_rule] no such filter: #{filter}")
|
25
|
+
end
|
26
|
+
|
27
|
+
filter_record
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'fluent/plugin/conditional_filter_rule'
|
2
|
+
require 'fluent/plugin/filter'
|
3
|
+
|
4
|
+
class Fluent::Plugin::ConditionalFilter < Fluent::Plugin::Filter
|
5
|
+
Fluent::Plugin.register_filter('conditional', self)
|
6
|
+
|
7
|
+
include Fluent::ConditionalFilterRule
|
8
|
+
|
9
|
+
config_param :key_pattern, :string
|
10
|
+
config_param :condition, :string
|
11
|
+
config_param :filter, :string
|
12
|
+
|
13
|
+
def configure(conf)
|
14
|
+
super
|
15
|
+
|
16
|
+
@key_pattern_regexp = Regexp.new(key_pattern)
|
17
|
+
end
|
18
|
+
|
19
|
+
def filter(tag, time, record)
|
20
|
+
record = filter_record(tag, time, record, self)
|
21
|
+
|
22
|
+
record if record.any?
|
23
|
+
end
|
24
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'fluent/plugin/conditional_filter_rule'
|
1
2
|
class Fluent::ConditionalFilterOutput < Fluent::Output
|
2
3
|
Fluent::Plugin.register_output('conditional_filter', self)
|
3
4
|
|
@@ -7,6 +8,7 @@ class Fluent::ConditionalFilterOutput < Fluent::Output
|
|
7
8
|
end
|
8
9
|
|
9
10
|
include Fluent::HandleTagNameMixin
|
11
|
+
include Fluent::ConditionalFilterRule
|
10
12
|
|
11
13
|
config_param :key_pattern, :string
|
12
14
|
config_param :condition, :string
|
@@ -28,7 +30,7 @@ class Fluent::ConditionalFilterOutput < Fluent::Output
|
|
28
30
|
def emit(tag, es, chain)
|
29
31
|
es.each do |time, record|
|
30
32
|
t = tag.dup
|
31
|
-
record = filter_record(t, time, record)
|
33
|
+
record = filter_record(t, time, record, self)
|
32
34
|
|
33
35
|
if record.any?
|
34
36
|
router.emit(t, time, record)
|
@@ -37,33 +39,4 @@ class Fluent::ConditionalFilterOutput < Fluent::Output
|
|
37
39
|
|
38
40
|
chain.next
|
39
41
|
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def filter_record(tag, time, record)
|
44
|
-
super
|
45
|
-
case filter
|
46
|
-
when 'numeric_upward'
|
47
|
-
filter_record = record.select do |key, value|
|
48
|
-
key.match(@key_pattern_regexp) &&
|
49
|
-
record[key].to_f >= condition.to_f
|
50
|
-
end
|
51
|
-
when 'numeric_downward'
|
52
|
-
filter_record = record.select do |key, value|
|
53
|
-
key.match(@key_pattern_regexp) &&
|
54
|
-
record[key].to_f <= condition.to_f
|
55
|
-
end
|
56
|
-
when 'string_match'
|
57
|
-
filter_record = record.select do |key, value|
|
58
|
-
key.match(@key_pattern_regexp) &&
|
59
|
-
record[key].match(Regexp.new(condition))
|
60
|
-
end
|
61
|
-
else
|
62
|
-
raise ArgumentError.new("[out_conditional_filter] no such filter: #{filter}")
|
63
|
-
end
|
64
|
-
|
65
|
-
filter_record
|
66
|
-
end
|
67
42
|
end
|
68
|
-
|
69
|
-
|
@@ -0,0 +1,220 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fluent::Plugin::ConditionalFilter do
|
4
|
+
describe '#configure' do
|
5
|
+
|
6
|
+
context "success" do
|
7
|
+
let(:conf) {
|
8
|
+
%[
|
9
|
+
key_pattern @example\.com$
|
10
|
+
condition 10
|
11
|
+
filter numeric_upward
|
12
|
+
]
|
13
|
+
}
|
14
|
+
|
15
|
+
let(:driver) { Fluent::Test::Driver::Filter.new(described_class).configure(conf) }
|
16
|
+
subject {
|
17
|
+
driver
|
18
|
+
}
|
19
|
+
|
20
|
+
it {
|
21
|
+
expect(subject.instance).to be_an_instance_of described_class
|
22
|
+
expect(subject.instance.key_pattern).to be == "@example\.com$"
|
23
|
+
expect(subject.instance.instance_variable_get(:@key_pattern_regexp)).to be == /@example.com$/
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
context "failure" do
|
28
|
+
context 'key_pattern not set' do
|
29
|
+
let(:conf) {
|
30
|
+
%[
|
31
|
+
condition 10
|
32
|
+
filter numeric_upward
|
33
|
+
]
|
34
|
+
}
|
35
|
+
|
36
|
+
it {
|
37
|
+
expect {
|
38
|
+
Fluent::Test::Driver::Filter.new(described_class).configure(conf)
|
39
|
+
}.to raise_error(Fluent::ConfigError)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'condition not set' do
|
44
|
+
let(:conf) {
|
45
|
+
%[
|
46
|
+
key_pattern @example.com$
|
47
|
+
filter numeric_upward
|
48
|
+
]
|
49
|
+
}
|
50
|
+
|
51
|
+
it {
|
52
|
+
expect {
|
53
|
+
Fluent::Test::Driver::Filter.new(described_class).configure(conf)
|
54
|
+
}.to raise_error(Fluent::ConfigError)
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'filter not set' do
|
59
|
+
let(:conf) {
|
60
|
+
%[
|
61
|
+
key_pattern @example.com$
|
62
|
+
condition 10
|
63
|
+
]
|
64
|
+
}
|
65
|
+
|
66
|
+
it {
|
67
|
+
expect {
|
68
|
+
Fluent::Test::Driver::Filter.new(described_class).configure(conf)
|
69
|
+
}.to raise_error(Fluent::ConfigError)
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#filter" do
|
76
|
+
context('numeric_upward') do
|
77
|
+
let(:conf) {
|
78
|
+
%[
|
79
|
+
key_pattern @example.com$
|
80
|
+
condition 10
|
81
|
+
filter numeric_upward
|
82
|
+
]
|
83
|
+
}
|
84
|
+
|
85
|
+
let(:driver) { Fluent::Test::Driver::Filter.new(described_class).configure(conf) }
|
86
|
+
|
87
|
+
context('with 0 matched key/value pair') do
|
88
|
+
before {
|
89
|
+
driver.run(default_tag: 'test') {
|
90
|
+
driver.feed('foo@example.com' => 8, 'bar@example.com' => 6, 'baz@baz.com' => 15)
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
it {
|
95
|
+
expect(driver.filtered[0]).to be_nil
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
context('with 1 matched key/value pair') do
|
100
|
+
before {
|
101
|
+
driver.run(default_tag: 'test') {
|
102
|
+
driver.feed('foo@example.com' => 12, 'bar@example.com' => 6, 'baz@baz.com' => 15)
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
it {
|
107
|
+
expect(driver.filtered[0][1].keys.length).to be == 1
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
context('with 2 matched key/value pairs') do
|
112
|
+
before {
|
113
|
+
driver.run(default_tag: 'test') {
|
114
|
+
driver.feed('foo@example.com' => 12, 'bar@example.com' => 10, 'baz@baz.com' => 15)
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
it {
|
119
|
+
expect(driver.filtered[0][1].keys.length).to be == 2
|
120
|
+
}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context('numeric_downward') do
|
125
|
+
let(:conf) {
|
126
|
+
%[
|
127
|
+
key_pattern @example.com$
|
128
|
+
condition 10
|
129
|
+
filter numeric_downward
|
130
|
+
]
|
131
|
+
}
|
132
|
+
|
133
|
+
let(:driver) { Fluent::Test::Driver::Filter.new(described_class).configure(conf) }
|
134
|
+
|
135
|
+
context('with 0 matched key/value pair') do
|
136
|
+
before {
|
137
|
+
driver.run(default_tag: 'test') {
|
138
|
+
driver.feed('foo@example.com' => 18, 'bar@example.com' => 26, 'baz@baz.com' => 15)
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
it {
|
143
|
+
expect(driver.filtered[0]).to be_nil
|
144
|
+
}
|
145
|
+
end
|
146
|
+
|
147
|
+
context('with 1 matched key/value pair') do
|
148
|
+
before {
|
149
|
+
driver.run(default_tag: 'test') {
|
150
|
+
driver.feed('foo@example.com' => 11, 'bar@example.com' => 6, 'baz@baz.com' => 5)
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
it {
|
155
|
+
expect(driver.filtered[0][1].keys.length).to be == 1
|
156
|
+
}
|
157
|
+
end
|
158
|
+
|
159
|
+
context('with 2 matched key/value pairs') do
|
160
|
+
before {
|
161
|
+
driver.run(default_tag: 'test') {
|
162
|
+
driver.feed('foo@example.com' => 10, 'bar@example.com' => 5, 'baz@baz.com' => 5)
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
it {
|
167
|
+
expect(driver.filtered[0][1].keys.length).to be == 2
|
168
|
+
}
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context('string_match') do
|
173
|
+
let(:conf) {
|
174
|
+
%[
|
175
|
+
key_pattern @example.com$
|
176
|
+
condition (staff|user)
|
177
|
+
filter string_match
|
178
|
+
]
|
179
|
+
}
|
180
|
+
|
181
|
+
let(:driver) { Fluent::Test::Driver::Filter.new(described_class).configure(conf) }
|
182
|
+
|
183
|
+
context('with 0 matched key/value pair') do
|
184
|
+
before {
|
185
|
+
driver.run(default_tag: 'test') {
|
186
|
+
driver.feed('foo@example.com' => 'guest', 'bar@example.com' => 'guest', 'baz@baz.com' => 'staff')
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
it {
|
191
|
+
expect(driver.filtered[0]).to be_nil
|
192
|
+
}
|
193
|
+
end
|
194
|
+
|
195
|
+
context('with 1 matched key/value pair') do
|
196
|
+
before {
|
197
|
+
driver.run(default_tag: 'test') {
|
198
|
+
driver.feed('foo@example.com' => 'staff', 'bar@example.com' => 'guest', 'baz@baz.com' => 'user')
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
it {
|
203
|
+
expect(driver.filtered[0][1].keys.length).to be == 1
|
204
|
+
}
|
205
|
+
end
|
206
|
+
|
207
|
+
context('with 2 matched key/value pairs') do
|
208
|
+
before {
|
209
|
+
driver.run(default_tag: 'test') {
|
210
|
+
driver.feed('foo@example.com' => 'staff', 'bar@example.com' => 'user', 'baz@baz.com' => 'staff')
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
it {
|
215
|
+
expect(driver.filtered[0][1].keys.length).to be == 2
|
216
|
+
}
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'fluent/test'
|
2
|
+
require 'fluent/test/driver/filter'
|
2
3
|
require 'fluent/plugin/out_conditional_filter'
|
4
|
+
require 'fluent/plugin/filter_conditional'
|
3
5
|
|
4
6
|
RSpec.configure do |config|
|
5
7
|
config.before(:all) do
|
@@ -24,4 +26,3 @@ unless ENV.has_key?('VERBOSE')
|
|
24
26
|
}
|
25
27
|
$log = nulllogger
|
26
28
|
end
|
27
|
-
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-conditional_filter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kentaro Kuribayashi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -16,14 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.14.0
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2'
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
27
|
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
29
|
+
version: 0.14.0
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: bundler
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,7 +100,10 @@ files:
|
|
94
100
|
- README.md
|
95
101
|
- Rakefile
|
96
102
|
- fluent-plugin-conditional_filter.gemspec
|
103
|
+
- lib/fluent/plugin/conditional_filter_rule.rb
|
104
|
+
- lib/fluent/plugin/filter_conditional.rb
|
97
105
|
- lib/fluent/plugin/out_conditional_filter.rb
|
106
|
+
- spec/lib/filter_conditional_spec.rb
|
98
107
|
- spec/lib/out_conditional_filter_spec.rb
|
99
108
|
- spec/spec_helper.rb
|
100
109
|
homepage: http://github.com/kentaro/fluent-plugin-conditional_filter
|
@@ -122,5 +131,6 @@ signing_key:
|
|
122
131
|
specification_version: 4
|
123
132
|
summary: A fluent plugin that provides conditional filters
|
124
133
|
test_files:
|
134
|
+
- spec/lib/filter_conditional_spec.rb
|
125
135
|
- spec/lib/out_conditional_filter_spec.rb
|
126
136
|
- spec/spec_helper.rb
|