fluent-plugin-route 0.2.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/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
|