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.
- checksums.yaml +7 -0
- data/.travis.yml +2 -2
- data/ChangeLog +8 -0
- data/lib/fluent/config.rb +285 -289
- data/lib/fluent/config_dsl.rb +74 -0
- data/lib/fluent/engine.rb +250 -247
- data/lib/fluent/env.rb +5 -5
- data/lib/fluent/event.rb +120 -124
- data/lib/fluent/input.rb +13 -17
- data/lib/fluent/load.rb +1 -0
- data/lib/fluent/log.rb +238 -242
- data/lib/fluent/match.rb +132 -137
- data/lib/fluent/mixin.rb +151 -155
- data/lib/fluent/parser.rb +201 -205
- data/lib/fluent/plugin.rb +117 -121
- data/lib/fluent/plugin/buf_file.rb +8 -0
- data/lib/fluent/plugin/exec_util.rb +49 -0
- data/lib/fluent/plugin/in_exec.rb +44 -30
- data/lib/fluent/plugin/in_forward.rb +4 -2
- data/lib/fluent/plugin/in_http.rb +5 -0
- data/lib/fluent/plugin/in_stream.rb +5 -2
- data/lib/fluent/plugin/out_exec_filter.rb +4 -47
- data/lib/fluent/plugin/out_stdout.rb +21 -1
- data/lib/fluent/process.rb +358 -362
- data/lib/fluent/status.rb +25 -30
- data/lib/fluent/supervisor.rb +277 -281
- data/lib/fluent/test/base.rb +35 -39
- data/lib/fluent/test/input_test.rb +68 -63
- data/lib/fluent/test/output_test.rb +98 -101
- data/lib/fluent/version.rb +1 -1
- data/test/configdsl.rb +77 -0
- data/test/plugin/in_exec.rb +73 -13
- data/test/plugin/in_gc_stat.rb +1 -1
- data/test/plugin/in_object_space.rb +2 -2
- data/test/plugin/out_stdout.rb +45 -2
- data/test/scripts/exec_script.rb +26 -0
- metadata +31 -46
data/lib/fluent/plugin.rb
CHANGED
@@ -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
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
34
|
+
def register_buffer(type, klass)
|
35
|
+
register_impl('buffer', @buffer, type, klass)
|
36
|
+
end
|
51
37
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
load_gem_plugins
|
56
|
-
end
|
38
|
+
def new_input(type)
|
39
|
+
new_impl('input', @input, type)
|
40
|
+
end
|
57
41
|
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
46
|
+
def new_buffer(type)
|
47
|
+
new_impl('buffer', @buffer, type)
|
48
|
+
end
|
71
49
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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
|
-
|
94
|
-
|
95
|
-
return klass.new
|
66
|
+
def load_plugin(type, name)
|
67
|
+
try_load_plugin(name, type)
|
96
68
|
end
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
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
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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 :
|
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
|
-
@
|
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
|
-
|
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
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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
|