fluent-plugin-route 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/fluent-plugin-route.gemspec +2 -2
- data/lib/fluent/plugin/out_route.rb +91 -113
- data/test/plugin/test_out_route.rb +40 -33
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a20d74801e0b2189c8de4e61be4123e131986800
|
4
|
+
data.tar.gz: 68d0a470e298074ce667651a6f4acccf79738d09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64ad0ac9468fb83c7c6c7e0a35c2e02b9325c5c26ccd7ddff6f86ef71e644e2657b0530003b82d0023b288ff1d51f0a36313544c3bddc3eeac3179389460160d
|
7
|
+
data.tar.gz: fb4e5e8fa31fdce80f2a4e577c392d734fe04c59d3e268600139044e991ef8456f33780760f4a858e1a9cbdf695f9be176bdb644e3c22df4e9aa930ef70447af
|
data/fluent-plugin-route.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
Gem::Specification.new do |gem|
|
3
3
|
gem.name = "fluent-plugin-route"
|
4
|
-
gem.version = "0.
|
4
|
+
gem.version = "1.0.0"
|
5
5
|
gem.authors = ["TAGOMORI Satoshi", "FURUHASHI Sadayuki"]
|
6
6
|
gem.email = ["tagomoris@gmail.com", "frsyuki@gmail.com"]
|
7
7
|
gem.summary = %q{Fluentd plugin to route messages in fluentd processes}
|
@@ -14,7 +14,7 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
|
17
|
-
gem.add_runtime_dependency "fluentd", "
|
17
|
+
gem.add_runtime_dependency "fluentd", ">= 0.14.0"
|
18
18
|
gem.add_development_dependency "rake"
|
19
19
|
gem.add_development_dependency "test-unit"
|
20
20
|
end
|
@@ -15,153 +15,131 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
|
-
require 'fluent/
|
18
|
+
require 'fluent/plugin/bare_output'
|
19
|
+
require 'fluent/match'
|
19
20
|
|
20
|
-
module Fluent
|
21
|
-
class RouteOutput <
|
22
|
-
Plugin.register_output('route', self)
|
21
|
+
module Fluent::Plugin
|
22
|
+
class RouteOutput < BareOutput
|
23
|
+
Fluent::Plugin.register_output('route', self)
|
23
24
|
|
24
|
-
|
25
|
-
include Configurable
|
25
|
+
helpers :event_emitter
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
config_section :route, param_name: :route_configs, multi: true, required: true do
|
28
|
+
config_argument :pattern, :string, default: '**'
|
29
|
+
config_param :@label, :string, default: nil
|
30
|
+
config_param :remove_tag_prefix, :string, default: nil
|
31
|
+
config_param :add_tag_prefix, :string, default: nil
|
32
|
+
config_param :copy, :bool, default: false
|
33
|
+
end
|
31
34
|
|
32
|
-
|
33
|
-
|
34
|
-
if !pattern || pattern.empty?
|
35
|
-
pattern = '**'
|
36
|
-
end
|
37
|
-
@router = router
|
38
|
-
@pattern = MatchPattern.create(pattern)
|
39
|
-
@tag_cache = {}
|
40
|
-
end
|
35
|
+
config_param :remove_tag_prefix, :string, default: nil
|
36
|
+
config_param :add_tag_prefix, :string, default: nil
|
41
37
|
|
42
|
-
|
43
|
-
|
44
|
-
end
|
38
|
+
config_param :match_cache_size, :integer, default: 256
|
39
|
+
config_param :tag_cache_size, :integer, default: 256
|
45
40
|
|
46
|
-
|
47
|
-
super
|
48
|
-
if conf['copy']
|
49
|
-
@copy = true
|
50
|
-
else
|
51
|
-
@copy = false
|
52
|
-
end
|
53
|
-
if label_name = conf['@label']
|
54
|
-
label = Fluent::Engine.root_agent.find_label(label_name)
|
55
|
-
@router = label.event_router
|
56
|
-
end
|
57
|
-
if @remove_tag_prefix
|
58
|
-
@prefix_match = /^#{Regexp.escape(@remove_tag_prefix)}\.?/
|
59
|
-
else
|
60
|
-
@prefix_match = //
|
61
|
-
end
|
62
|
-
if @add_tag_prefix
|
63
|
-
@tag_prefix = "#{@add_tag_prefix}."
|
64
|
-
else
|
65
|
-
@tag_prefix = ""
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def copy?
|
70
|
-
@copy
|
71
|
-
end
|
41
|
+
attr_reader :routes
|
72
42
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
43
|
+
def tag_modifier(remove_tag_prefix, add_tag_prefix)
|
44
|
+
tag_cache_size = @tag_cache_size
|
45
|
+
cache = {}
|
46
|
+
mutex = Mutex.new
|
47
|
+
removed_prefix = remove_tag_prefix ? remove_tag_prefix + "." : ""
|
48
|
+
added_prefix = add_tag_prefix ? add_tag_prefix + "." : ""
|
49
|
+
->(tag){
|
50
|
+
if cached = cache[tag]
|
51
|
+
cached
|
52
|
+
else
|
53
|
+
modified = tag.start_with?(removed_prefix) ? tag.sub(removed_prefix, added_prefix) : added_prefix + tag
|
54
|
+
mutex.synchronize do
|
55
|
+
if cache.size >= tag_cache_size
|
56
|
+
remove_keys = cache.keys[0...(tag_cache_size / 2)]
|
57
|
+
cache.delete_if{|key, _value| remove_keys.include?(key) }
|
58
|
+
end
|
59
|
+
cache[tag] = modified
|
79
60
|
end
|
61
|
+
modified
|
80
62
|
end
|
81
|
-
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def initialize
|
86
|
-
super
|
87
|
-
@routes = []
|
88
|
-
@tag_cache = {}
|
89
|
-
@match_cache = {}
|
63
|
+
}
|
90
64
|
end
|
91
65
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
attr_reader :routes
|
66
|
+
def configure(conf)
|
67
|
+
if conf.elements(name: 'store').size > 0
|
68
|
+
raise Fluent::ConfigError, "<store> section is not available in route plugin"
|
69
|
+
end
|
97
70
|
|
98
|
-
|
99
|
-
unless method_defined?(:log)
|
100
|
-
define_method("log") { $log }
|
101
|
-
end
|
71
|
+
super
|
102
72
|
|
103
|
-
|
104
|
-
|
105
|
-
|
73
|
+
@match_cache = {}
|
74
|
+
@routes = []
|
75
|
+
@route_configs.each do |rc|
|
76
|
+
route_router = event_emitter_router(rc['@label'])
|
77
|
+
modifier = tag_modifier(rc.remove_tag_prefix, rc.add_tag_prefix)
|
78
|
+
@routes << Route.new(rc.pattern, route_router, modifier, rc.copy)
|
79
|
+
end
|
80
|
+
@default_tag_modifier = (@remove_tag_prefix || @add_tag_prefix) ? tag_modifier(@remove_tag_prefix, @add_tag_prefix) : nil
|
81
|
+
@mutex = Mutex.new
|
106
82
|
end
|
107
83
|
|
108
|
-
|
109
|
-
|
84
|
+
class Route
|
85
|
+
def initialize(pattern, router, tag_modifier, copy)
|
86
|
+
@router = router
|
87
|
+
@pattern = Fluent::MatchPattern.create(pattern)
|
88
|
+
@tag_modifier = tag_modifier
|
89
|
+
@copy = copy
|
90
|
+
end
|
110
91
|
|
111
|
-
|
112
|
-
@
|
113
|
-
else
|
114
|
-
@prefix_match = //
|
92
|
+
def match?(tag)
|
93
|
+
@pattern.match(tag)
|
115
94
|
end
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
@tag_prefix = ""
|
95
|
+
|
96
|
+
def copy?
|
97
|
+
@copy
|
120
98
|
end
|
121
99
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
route.configure(e)
|
127
|
-
@routes << route
|
128
|
-
}
|
100
|
+
def emit(tag, es)
|
101
|
+
tag = @tag_modifier.call(tag)
|
102
|
+
@router.emit_stream(tag, es)
|
103
|
+
end
|
129
104
|
end
|
130
105
|
|
131
|
-
def
|
132
|
-
|
106
|
+
def process(tag, es)
|
107
|
+
modified_tag, targets = @match_cache[tag]
|
133
108
|
unless targets
|
134
|
-
|
109
|
+
modified_tag = @default_tag_modifier ? @default_tag_modifier.call(tag) : tag
|
135
110
|
targets = []
|
136
|
-
@routes.each
|
137
|
-
if r.match?(
|
111
|
+
@routes.each do |r|
|
112
|
+
if r.match?(modified_tag)
|
138
113
|
targets << r
|
139
114
|
break unless r.copy?
|
140
115
|
end
|
141
|
-
|
142
|
-
|
143
|
-
|
116
|
+
end
|
117
|
+
|
118
|
+
@mutex.synchronize do
|
119
|
+
if @match_cache.size >= @match_cache_size
|
120
|
+
remove_keys = @match_cache.keys[0...(@match_cache_size / 2)]
|
121
|
+
@match_cache.delete_if{|key, _value| remove_keys.include?(key) }
|
122
|
+
end
|
123
|
+
@match_cache[tag] = [modified_tag, targets]
|
144
124
|
end
|
145
125
|
end
|
146
126
|
|
147
127
|
case targets.size
|
148
128
|
when 0
|
149
|
-
|
129
|
+
# do nothing
|
150
130
|
when 1
|
151
|
-
targets.first.emit(
|
152
|
-
chain.next
|
131
|
+
targets.first.emit(modified_tag, es)
|
153
132
|
else
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
133
|
+
targets.each do |target|
|
134
|
+
dup_es = if es.respond_to?(:dup)
|
135
|
+
es.dup
|
136
|
+
else
|
137
|
+
m_es = MultiEventStream.new
|
138
|
+
es.each{|t,r| m_es.add(t, r) }
|
139
|
+
m_es
|
140
|
+
end
|
141
|
+
target.emit(modified_tag, dup_es)
|
160
142
|
end
|
161
|
-
targets.each {|t|
|
162
|
-
t.emit(ntag, es)
|
163
|
-
}
|
164
|
-
chain.next
|
165
143
|
end
|
166
144
|
end
|
167
145
|
end
|
@@ -1,6 +1,12 @@
|
|
1
|
-
require 'fluent/test'
|
2
1
|
require 'fluent/plugin/out_route'
|
3
2
|
|
3
|
+
require 'fluent/test'
|
4
|
+
require 'fluent/test/driver/multi_output'
|
5
|
+
require 'fluent/test/driver/event_feeder'
|
6
|
+
|
7
|
+
require 'fluent/test/helpers'
|
8
|
+
include Fluent::Test::Helpers
|
9
|
+
|
4
10
|
class RouteOutputTest < Test::Unit::TestCase
|
5
11
|
def setup
|
6
12
|
Fluent::Test.setup
|
@@ -25,14 +31,15 @@ class RouteOutputTest < Test::Unit::TestCase
|
|
25
31
|
</route>
|
26
32
|
]
|
27
33
|
|
28
|
-
def create_driver(conf
|
29
|
-
d = Fluent::Test::
|
34
|
+
def create_driver(conf)
|
35
|
+
d = Fluent::Test::Driver::BaseOwner.new(Fluent::Plugin::RouteOutput)
|
36
|
+
d.extend(Fluent::Test::Driver::EventFeeder)
|
30
37
|
Fluent::Engine.root_agent.define_singleton_method(:find_label) do |label_name|
|
31
38
|
obj = Object.new
|
32
39
|
obj.define_singleton_method(:event_router){ d.instance.router } # for test...
|
33
40
|
obj
|
34
41
|
end
|
35
|
-
d.configure(conf
|
42
|
+
d.configure(conf)
|
36
43
|
end
|
37
44
|
|
38
45
|
def test_configure
|
@@ -40,52 +47,52 @@ class RouteOutputTest < Test::Unit::TestCase
|
|
40
47
|
end
|
41
48
|
|
42
49
|
def test_emit_t1
|
43
|
-
d = create_driver(CONFIG
|
50
|
+
d = create_driver(CONFIG)
|
44
51
|
|
45
|
-
time =
|
46
|
-
d.run do
|
47
|
-
d.
|
48
|
-
d.
|
52
|
+
time = event_time("2011-11-11 11:11:11 UTC")
|
53
|
+
d.run(default_tag: "t.t1.test", expect_records: 2) do
|
54
|
+
d.feed(time, {"a" => 1})
|
55
|
+
d.feed(time, {"a" => 2})
|
49
56
|
end
|
50
57
|
|
51
|
-
|
52
|
-
assert_equal 2,
|
58
|
+
events = d.events
|
59
|
+
assert_equal 2, events.size
|
53
60
|
|
54
|
-
assert_equal ["yay.test", time, {"a" => 1}],
|
55
|
-
assert_equal ["yay.test", time, {"a" => 2}],
|
61
|
+
assert_equal ["yay.test", time, {"a" => 1}], events[0]
|
62
|
+
assert_equal ["yay.test", time, {"a" => 2}], events[1]
|
56
63
|
end
|
57
64
|
|
58
65
|
def test_emit_t2
|
59
|
-
d = create_driver(CONFIG
|
66
|
+
d = create_driver(CONFIG)
|
60
67
|
|
61
|
-
time =
|
62
|
-
d.run do
|
63
|
-
d.
|
64
|
-
d.
|
68
|
+
time = event_time("2011-11-11 11:11:11 UTC")
|
69
|
+
d.run(default_tag: "t.t2.test", expect_records: 2) do
|
70
|
+
d.feed(time, {"a" => 1})
|
71
|
+
d.feed(time, {"a" => 2})
|
65
72
|
end
|
66
73
|
|
67
|
-
|
68
|
-
assert_equal 2,
|
74
|
+
events = d.events
|
75
|
+
assert_equal 2, events.size
|
69
76
|
|
70
|
-
assert_equal ["foo.test", time, {"a" => 1}],
|
71
|
-
assert_equal ["foo.test", time, {"a" => 2}],
|
77
|
+
assert_equal ["foo.test", time, {"a" => 1}], events[0]
|
78
|
+
assert_equal ["foo.test", time, {"a" => 2}], events[1]
|
72
79
|
end
|
73
80
|
|
74
81
|
def test_emit_others
|
75
|
-
d = create_driver(CONFIG
|
82
|
+
d = create_driver(CONFIG)
|
76
83
|
|
77
|
-
time =
|
78
|
-
d.run do
|
79
|
-
d.
|
80
|
-
d.
|
84
|
+
time = event_time("2011-11-11 11:11:11 UTC")
|
85
|
+
d.run(default_tag: "t.t3.test", expect_records: 4) do
|
86
|
+
d.feed(time, {"a" => 1})
|
87
|
+
d.feed(time, {"a" => 2})
|
81
88
|
end
|
82
89
|
|
83
|
-
|
84
|
-
assert_equal 4,
|
90
|
+
events = d.events
|
91
|
+
assert_equal 4, events.size
|
85
92
|
|
86
|
-
assert_equal ["t3.test", time, {"a" => 1}],
|
87
|
-
assert_equal ["t3.test", time, {"a" => 1}],
|
88
|
-
assert_equal ["t3.test", time, {"a" => 2}],
|
89
|
-
assert_equal ["t3.test", time, {"a" => 2}],
|
93
|
+
assert_equal ["t3.test", time, {"a" => 1}], events[0]
|
94
|
+
assert_equal ["t3.test", time, {"a" => 1}], events[1]
|
95
|
+
assert_equal ["t3.test", time, {"a" => 2}], events[2]
|
96
|
+
assert_equal ["t3.test", time, {"a" => 2}], events[3]
|
90
97
|
end
|
91
98
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-route
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- TAGOMORI Satoshi
|
@@ -9,20 +9,20 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-01
|
12
|
+
date: 2017-02-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fluentd
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - "
|
18
|
+
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: 0.14.0
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - "
|
25
|
+
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: 0.14.0
|
28
28
|
- !ruby/object:Gem::Dependency
|