fluentd 0.10.36 → 0.10.37

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fluentd might be problematic. Click here for more details.

@@ -16,149 +16,145 @@
16
16
  # limitations under the License.
17
17
  #
18
18
  module Fluent
19
+ class PluginClass
20
+ def initialize
21
+ @input = {}
22
+ @output = {}
23
+ @buffer = {}
24
+ end
19
25
 
26
+ def register_input(type, klass)
27
+ register_impl('input', @input, type, klass)
28
+ end
20
29
 
21
- class PluginClass
22
- def initialize
23
- @input = {}
24
- @output = {}
25
- @buffer = {}
26
- end
27
-
28
- def register_input(type, klass)
29
- register_impl('input', @input, type, klass)
30
- end
31
-
32
- def register_output(type, klass)
33
- register_impl('output', @output, type, klass)
34
- end
35
-
36
- def register_buffer(type, klass)
37
- register_impl('buffer', @buffer, type, klass)
38
- end
39
-
40
- def new_input(type)
41
- new_impl('input', @input, type)
42
- end
43
-
44
- def new_output(type)
45
- new_impl('output', @output, type)
46
- end
30
+ def register_output(type, klass)
31
+ register_impl('output', @output, type, klass)
32
+ end
47
33
 
48
- def new_buffer(type)
49
- new_impl('buffer', @buffer, type)
50
- end
34
+ def register_buffer(type, klass)
35
+ register_impl('buffer', @buffer, type, klass)
36
+ end
51
37
 
52
- def load_plugins
53
- dir = File.join(File.dirname(__FILE__), "plugin")
54
- load_plugin_dir(dir)
55
- load_gem_plugins
56
- end
38
+ def new_input(type)
39
+ new_impl('input', @input, type)
40
+ end
57
41
 
58
- def load_plugin_dir(dir)
59
- dir = File.expand_path(dir)
60
- Dir.entries(dir).sort.each {|fname|
61
- if fname =~ /\.rb$/
62
- require File.join(dir, fname)
63
- end
64
- }
65
- nil
66
- end
42
+ def new_output(type)
43
+ new_impl('output', @output, type)
44
+ end
67
45
 
68
- def load_plugin(type, name)
69
- try_load_plugin(name, type)
70
- end
46
+ def new_buffer(type)
47
+ new_impl('buffer', @buffer, type)
48
+ end
71
49
 
72
- private
73
- def load_gem_plugins
74
- return unless defined? Gem
75
- plugins = Gem.find_files('fluent_plugin')
76
-
77
- plugins.each {|plugin|
78
- begin
79
- load plugin
80
- rescue ::Exception => e
81
- msg = "#{plugin.inspect}: #{e.message} (#{e.class})"
82
- $log.warn "Error loading Fluent plugin #{msg}"
83
- end
84
- }
85
- end
50
+ def load_plugins
51
+ dir = File.join(File.dirname(__FILE__), "plugin")
52
+ load_plugin_dir(dir)
53
+ load_gem_plugins
54
+ end
86
55
 
87
- def register_impl(name, map, type, klass)
88
- map[type] = klass
89
- $log.trace { "registered #{name} plugin '#{type}'" }
90
- nil
91
- end
56
+ def load_plugin_dir(dir)
57
+ dir = File.expand_path(dir)
58
+ Dir.entries(dir).sort.each {|fname|
59
+ if fname =~ /\.rb$/
60
+ require File.join(dir, fname)
61
+ end
62
+ }
63
+ nil
64
+ end
92
65
 
93
- def new_impl(name, map, type)
94
- if klass = map[type]
95
- return klass.new
66
+ def load_plugin(type, name)
67
+ try_load_plugin(name, type)
96
68
  end
97
- try_load_plugin(name, type)
98
- if klass = map[type]
99
- return klass.new
69
+
70
+ private
71
+ def load_gem_plugins
72
+ return unless defined? Gem
73
+ plugins = Gem.find_files('fluent_plugin')
74
+
75
+ plugins.each {|plugin|
76
+ begin
77
+ load plugin
78
+ rescue ::Exception => e
79
+ msg = "#{plugin.inspect}: #{e.message} (#{e.class})"
80
+ $log.warn "Error loading Fluent plugin #{msg}"
81
+ end
82
+ }
100
83
  end
101
- raise ConfigError, "Unknown #{name} plugin '#{type}'. Run 'gem search -rd fluent-plugin' to find plugins"
102
- end
103
84
 
104
- def try_load_plugin(name, type)
105
- case name
106
- when 'input'
107
- path = "fluent/plugin/in_#{type}"
108
- when 'output'
109
- path = "fluent/plugin/out_#{type}"
110
- when 'buffer'
111
- path = "fluent/plugin/buf_#{type}"
112
- else
113
- return
85
+ def register_impl(name, map, type, klass)
86
+ map[type] = klass
87
+ $log.trace { "registered #{name} plugin '#{type}'" }
88
+ nil
114
89
  end
115
90
 
116
- # prefer LOAD_PATH than gems
117
- files = $LOAD_PATH.map {|lp|
118
- lpath = File.join(lp, "#{path}.rb")
119
- File.exist?(lpath) ? lpath : nil
120
- }.compact
121
- unless files.empty?
122
- # prefer newer version
123
- require File.expand_path(files.sort.last)
124
- return
91
+ def new_impl(name, map, type)
92
+ if klass = map[type]
93
+ return klass.new
94
+ end
95
+ try_load_plugin(name, type)
96
+ if klass = map[type]
97
+ return klass.new
98
+ end
99
+ raise ConfigError, "Unknown #{name} plugin '#{type}'. Run 'gem search -rd fluent-plugin' to find plugins"
125
100
  end
126
101
 
127
- # search gems
128
- if defined?(::Gem::Specification) && ::Gem::Specification.respond_to?(:find_all)
129
- specs = Gem::Specification.find_all {|spec|
130
- spec.contains_requirable_file? path
131
- }
102
+ def try_load_plugin(name, type)
103
+ case name
104
+ when 'input'
105
+ path = "fluent/plugin/in_#{type}"
106
+ when 'output'
107
+ path = "fluent/plugin/out_#{type}"
108
+ when 'buffer'
109
+ path = "fluent/plugin/buf_#{type}"
110
+ else
111
+ return
112
+ end
132
113
 
133
- # prefer newer version
134
- specs = specs.sort_by {|spec| spec.version }
135
- if spec = specs.last
136
- spec.require_paths.each {|lib|
137
- file = "#{spec.full_gem_path}/#{lib}/#{path}"
138
- require file
139
- }
114
+ # prefer LOAD_PATH than gems
115
+ files = $LOAD_PATH.map {|lp|
116
+ lpath = File.join(lp, "#{path}.rb")
117
+ File.exist?(lpath) ? lpath : nil
118
+ }.compact
119
+ unless files.empty?
120
+ # prefer newer version
121
+ require File.expand_path(files.sort.last)
122
+ return
140
123
  end
141
124
 
142
- # backward compatibility for rubygems < 1.8
143
- elsif defined?(::Gem) && ::Gem.respond_to?(:searcher)
144
- #files = Gem.find_files(path).sort
145
- specs = Gem.searcher.find_all(path)
146
-
147
- # prefer newer version
148
- specs = specs.sort_by {|spec| spec.version }
149
- specs.reverse_each {|spec|
150
- files = Gem.searcher.matching_files(spec, path)
151
- unless files.empty?
152
- require files.first
153
- break
125
+ # search gems
126
+ if defined?(::Gem::Specification) && ::Gem::Specification.respond_to?(:find_all)
127
+ specs = Gem::Specification.find_all {|spec|
128
+ spec.contains_requirable_file? path
129
+ }
130
+
131
+ # prefer newer version
132
+ specs = specs.sort_by {|spec| spec.version }
133
+ if spec = specs.last
134
+ spec.require_paths.each {|lib|
135
+ file = "#{spec.full_gem_path}/#{lib}/#{path}"
136
+ require file
137
+ }
154
138
  end
155
- }
139
+
140
+ # backward compatibility for rubygems < 1.8
141
+ elsif defined?(::Gem) && ::Gem.respond_to?(:searcher)
142
+ #files = Gem.find_files(path).sort
143
+ specs = Gem.searcher.find_all(path)
144
+
145
+ # prefer newer version
146
+ specs = specs.sort_by {|spec| spec.version }
147
+ specs.reverse_each {|spec|
148
+ files = Gem.searcher.matching_files(spec, path)
149
+ unless files.empty?
150
+ require files.first
151
+ break
152
+ end
153
+ }
154
+ end
156
155
  end
157
156
  end
158
- end
159
-
160
- Plugin = PluginClass.new
161
-
162
157
 
158
+ Plugin = PluginClass.new
163
159
  end
164
160
 
@@ -75,6 +75,8 @@ module Fluent
75
75
  class FileBuffer < BasicBuffer
76
76
  Plugin.register_buffer('file', self)
77
77
 
78
+ @@buffer_paths = {}
79
+
78
80
  def initialize
79
81
  require 'uri'
80
82
  super
@@ -85,6 +87,12 @@ module Fluent
85
87
  def configure(conf)
86
88
  super
87
89
 
90
+ if @@buffer_paths.has_key?(@buffer_path)
91
+ raise ConfigError, "Other '#{@@buffer_paths[@buffer_path]}' plugin already use same buffer_path: type = #{conf['type']}, buffer_path = #{@buffer_path}"
92
+ else
93
+ @@buffer_paths[@buffer_path] = conf['type']
94
+ end
95
+
88
96
  if pos = @buffer_path.index('*')
89
97
  @buffer_path_prefix = @buffer_path[0,pos]
90
98
  @buffer_path_suffix = @buffer_path[pos+1..-1]
@@ -0,0 +1,49 @@
1
+ module Fluent
2
+ module ExecUtil
3
+ class Parser
4
+ def initialize(on_message)
5
+ @on_message = on_message
6
+ end
7
+ end
8
+
9
+ class TSVParser < Parser
10
+ def initialize(keys, on_message)
11
+ @keys = keys
12
+ super(on_message)
13
+ end
14
+
15
+ def call(io)
16
+ io.each_line(&method(:each_line))
17
+ end
18
+
19
+ def each_line(line)
20
+ line.chomp!
21
+ vals = line.split("\t")
22
+
23
+ record = Hash[@keys.zip(vals)]
24
+
25
+ @on_message.call(record)
26
+ end
27
+ end
28
+
29
+ class JSONParser < Parser
30
+ def call(io)
31
+ y = Yajl::Parser.new
32
+ y.on_parse_complete = @on_message
33
+ y.parse(io)
34
+ end
35
+ end
36
+
37
+ class MessagePackParser < Parser
38
+ def call(io)
39
+ @u = MessagePack::Unpacker.new(io)
40
+ begin
41
+ @u.each(&@on_message)
42
+ rescue EOFError
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+
@@ -21,10 +21,24 @@ module Fluent
21
21
 
22
22
  def initialize
23
23
  super
24
+ require 'fluent/plugin/exec_util'
24
25
  end
25
26
 
27
+ SUPPORTED_FORMAT = {
28
+ 'tsv' => :tsv,
29
+ 'json' => :json,
30
+ 'msgpack' => :msgpack,
31
+ }
32
+
26
33
  config_param :command, :string
27
- config_param :keys, :string
34
+ config_param :format, :default => :tsv do |val|
35
+ f = SUPPORTED_FORMAT[val]
36
+ raise ConfigError, "Unsupported format '#{val}'" unless f
37
+ f
38
+ end
39
+ config_param :keys, :default => [] do |val|
40
+ val.split(',')
41
+ end
28
42
  config_param :tag, :string, :default => nil
29
43
  config_param :tag_key, :string, :default => nil
30
44
  config_param :time_key, :string, :default => nil
@@ -44,8 +58,6 @@ module Fluent
44
58
  raise ConfigError, "'tag' or 'tag_key' option is required on exec input"
45
59
  end
46
60
 
47
- @keys = @keys.split(',')
48
-
49
61
  if @time_key
50
62
  if @time_format
51
63
  f = @time_format
@@ -54,6 +66,18 @@ module Fluent
54
66
  @time_parse_proc = Proc.new {|str| str.to_i }
55
67
  end
56
68
  end
69
+
70
+ case @format
71
+ when :tsv
72
+ if @keys.empty?
73
+ raise ConfigError, "keys option is required on exec input for tsv format"
74
+ end
75
+ @parser = ExecUtil::TSVParser.new(@keys, method(:on_message))
76
+ when :json
77
+ @parser = ExecUtil::JSONParser.new(method(:on_message))
78
+ when :msgpack
79
+ @parser = ExecUtil::MessagePackParser.new(method(:on_message))
80
+ end
57
81
  end
58
82
 
59
83
  def start
@@ -82,47 +106,37 @@ module Fluent
82
106
  end
83
107
 
84
108
  def run
85
- @io.each_line(&method(:each_line))
109
+ @parser.call(@io)
86
110
  end
87
111
 
88
112
  def run_periodic
89
113
  until @finished
90
114
  sleep @run_interval
91
115
  io = IO.popen(@command, "r")
92
- io.each_line(&method(:each_line))
116
+ @parser.call(io)
93
117
  Process.waitpid(io.pid)
94
118
  end
95
119
  end
96
120
 
97
121
  private
98
- def each_line(line)
99
- begin
100
- line.chomp!
101
- vals = line.split("\t")
102
122
 
103
- tag = @tag
104
- time = nil
105
- record = {}
106
- for i in 0..@keys.length-1
107
- key = @keys[i]
108
- val = vals[i]
109
- if key == @time_key
110
- time = @time_parse_proc.call(val)
111
- elsif key == @tag_key
112
- tag = val
113
- else
114
- record[key] = val
115
- end
116
- end
123
+ def on_message(record)
124
+ if val = record.delete(@time_key)
125
+ time = @time_parse_proc.call(val)
126
+ else
127
+ time = Engine.now
128
+ end
117
129
 
118
- if tag
119
- time ||= Engine.now
120
- Engine.emit(tag, time, record)
121
- end
122
- rescue
123
- $log.error "exec failed to emit", :error=>$!.to_s, :line=>line
124
- $log.warn_backtrace $!.backtrace
130
+ if val = record.delete(@tag_key)
131
+ tag = val
132
+ else
133
+ tag = @tag
125
134
  end
135
+
136
+ Engine.emit(tag, time, record)
137
+ rescue
138
+ $log.error "exec failed to emit", :error => $!.to_s, :error_class => $!.class.to_s, :record => Yajl.dump(record)
139
+ $log.warn_backtrace $!.backtrace
126
140
  end
127
141
  end
128
142
  end