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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7740164b77dfc4121d2abb21a984958cc4578cc8
4
- data.tar.gz: 22a5547cf3d120b4e939b232b858f9482935f2f0
3
+ metadata.gz: a20d74801e0b2189c8de4e61be4123e131986800
4
+ data.tar.gz: 68d0a470e298074ce667651a6f4acccf79738d09
5
5
  SHA512:
6
- metadata.gz: 990730d0d8956c835ccb2e9b7e1e88e9d7ad0df1feb88f1736db30279d371ad42908eb9b349ddd64f0e019d7a3242dedc4120091daa0b03aacc20302378c6c93
7
- data.tar.gz: f840ec3d77b45fe782871621793ef2ff4401c3dddcbce08107072aa808f2537e5c9b207745ac28e0ef8ad240c293e33a0fb08fd3dec2545bd6dae105366d54be
6
+ metadata.gz: 64ad0ac9468fb83c7c6c7e0a35c2e02b9325c5c26ccd7ddff6f86ef71e644e2657b0530003b82d0023b288ff1d51f0a36313544c3bddc3eeac3179389460160d
7
+ data.tar.gz: fb4e5e8fa31fdce80f2a4e577c392d734fe04c59d3e268600139044e991ef8456f33780760f4a858e1a9cbdf695f9be176bdb644e3c22df4e9aa930ef70447af
@@ -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.2.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", "< 0.14.0"
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/output'
18
+ require 'fluent/plugin/bare_output'
19
+ require 'fluent/match'
19
20
 
20
- module Fluent
21
- class RouteOutput < MultiOutput
22
- Plugin.register_output('route', self)
21
+ module Fluent::Plugin
22
+ class RouteOutput < BareOutput
23
+ Fluent::Plugin.register_output('route', self)
23
24
 
24
- class Route
25
- include Configurable
25
+ helpers :event_emitter
26
26
 
27
- config_param :remove_tag_prefix, :string, :default => nil
28
- config_param :add_tag_prefix, :string, :default => nil
29
- # TODO tag_transform regexp
30
- attr_accessor :copy
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
- def initialize(pattern, router)
33
- super()
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
- def match?(tag)
43
- @pattern.match(tag)
44
- end
38
+ config_param :match_cache_size, :integer, default: 256
39
+ config_param :tag_cache_size, :integer, default: 256
45
40
 
46
- def configure(conf)
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
- def emit(tag, es)
74
- ntag = @tag_cache[tag]
75
- unless ntag
76
- ntag = tag.sub(@prefix_match, @tag_prefix)
77
- if @tag_cache.size < 1024 # TODO size limit
78
- @tag_cache[tag] = ntag
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
- @router.emit_stream(ntag, es)
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
- config_param :remove_tag_prefix, :string, :default => nil
93
- config_param :add_tag_prefix, :string, :default => nil
94
- # TODO tag_transform regexp
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
- # Define `log` method for v0.10.42 or earlier
99
- unless method_defined?(:log)
100
- define_method("log") { $log }
101
- end
71
+ super
102
72
 
103
- # Define `router` method of v0.12 to support v0.10 or earlier
104
- unless method_defined?(:router)
105
- define_method("router") { ::Fluent::Engine }
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
- def configure(conf)
109
- super
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
- if @remove_tag_prefix
112
- @prefix_match = /^#{Regexp.escape(@remove_tag_prefix)}\.?/
113
- else
114
- @prefix_match = //
92
+ def match?(tag)
93
+ @pattern.match(tag)
115
94
  end
116
- if @add_tag_prefix
117
- @tag_prefix = "#{@add_tag_prefix}."
118
- else
119
- @tag_prefix = ""
95
+
96
+ def copy?
97
+ @copy
120
98
  end
121
99
 
122
- conf.elements.select {|e|
123
- e.name == 'route'
124
- }.each {|e|
125
- route = Route.new(e.arg, router)
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 emit(tag, es, chain)
132
- ntag, targets = @match_cache[tag]
106
+ def process(tag, es)
107
+ modified_tag, targets = @match_cache[tag]
133
108
  unless targets
134
- ntag = tag.sub(@prefix_match, @tag_prefix)
109
+ modified_tag = @default_tag_modifier ? @default_tag_modifier.call(tag) : tag
135
110
  targets = []
136
- @routes.each {|r|
137
- if r.match?(ntag)
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
- if @match_cache.size < 1024 # TODO size limit
143
- @match_cache[tag] = [ntag, targets]
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
- return
129
+ # do nothing
150
130
  when 1
151
- targets.first.emit(ntag, es)
152
- chain.next
131
+ targets.first.emit(modified_tag, es)
153
132
  else
154
- unless es.repeatable?
155
- m = MultiEventStream.new
156
- es.each {|time,record|
157
- m.add(time, record)
158
- }
159
- es = m
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, tag)
29
- d = Fluent::Test::OutputTestDriver.new(Fluent::RouteOutput, tag)
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, true)
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, "t.t1.test")
50
+ d = create_driver(CONFIG)
44
51
 
45
- time = Time.parse("2011-11-11 11:11:11 UTC").to_i
46
- d.run do
47
- d.emit({"a" => 1}, time)
48
- d.emit({"a" => 2}, time)
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
- emits = d.emits
52
- assert_equal 2, emits.size
58
+ events = d.events
59
+ assert_equal 2, events.size
53
60
 
54
- assert_equal ["yay.test", time, {"a" => 1}], emits[0]
55
- assert_equal ["yay.test", time, {"a" => 2}], emits[1]
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, "t.t2.test")
66
+ d = create_driver(CONFIG)
60
67
 
61
- time = Time.parse("2011-11-11 11:11:11 UTC").to_i
62
- d.run do
63
- d.emit({"a" => 1}, time)
64
- d.emit({"a" => 2}, time)
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
- emits = d.emits
68
- assert_equal 2, emits.size
74
+ events = d.events
75
+ assert_equal 2, events.size
69
76
 
70
- assert_equal ["foo.test", time, {"a" => 1}], emits[0]
71
- assert_equal ["foo.test", time, {"a" => 2}], emits[1]
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, "t.t3.test")
82
+ d = create_driver(CONFIG)
76
83
 
77
- time = Time.parse("2011-11-11 11:11:11 UTC").to_i
78
- d.run do
79
- d.emit({"a" => 1}, time)
80
- d.emit({"a" => 2}, time)
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
- emits = d.emits
84
- assert_equal 4, emits.size
90
+ events = d.events
91
+ assert_equal 4, events.size
85
92
 
86
- assert_equal ["t3.test", time, {"a" => 1}], emits[0]
87
- assert_equal ["t3.test", time, {"a" => 1}], emits[1]
88
- assert_equal ["t3.test", time, {"a" => 2}], emits[2]
89
- assert_equal ["t3.test", time, {"a" => 2}], emits[3]
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.2.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-31 00:00:00.000000000 Z
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