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
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'fluent/config'
|
2
|
+
|
3
|
+
module Fluent
|
4
|
+
module Config
|
5
|
+
module DSL
|
6
|
+
module DSLParser
|
7
|
+
def self.read(path)
|
8
|
+
path = File.expand_path(path)
|
9
|
+
data = File.read(path)
|
10
|
+
parse(data, path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.parse(source, source_path="config.rb")
|
14
|
+
DSLElement.new('ROOT', nil).__eval(source, source_path).__to_config_element
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class DSLElement < BasicObject
|
19
|
+
def initialize(name, arg)
|
20
|
+
@name = name
|
21
|
+
@arg = arg || ''
|
22
|
+
@attrs = {}
|
23
|
+
@elements = []
|
24
|
+
end
|
25
|
+
|
26
|
+
def __eval(source, source_path)
|
27
|
+
instance_eval(source, source_path)
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def __to_config_element
|
32
|
+
Config::Element.new(@name, @arg, @attrs, @elements)
|
33
|
+
end
|
34
|
+
|
35
|
+
def method_missing(name, *args, &block)
|
36
|
+
raise ArgumentError, "Configuration DSL Syntax Error: only one argument allowed" if args.size > 1
|
37
|
+
value = args.first
|
38
|
+
if block
|
39
|
+
element = DSLElement.new(name.to_s, value)
|
40
|
+
element.instance_exec(&block)
|
41
|
+
@elements.push(element.__to_config_element)
|
42
|
+
else
|
43
|
+
# @attrs[name.to_s] = value.is_a?(::Symbol) ? value.to_s : value
|
44
|
+
@attrs[name.to_s] = value.to_s
|
45
|
+
end
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def source(&block)
|
50
|
+
__element('source', nil, block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def match(*args, &block)
|
54
|
+
__need_arg('match', args); __element('match', args.first, block)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def __element(name, arg, block)
|
60
|
+
raise ArgumentError, "#{name} block must be specified" if block.nil?
|
61
|
+
element = DSLElement.new(name.to_s, arg)
|
62
|
+
element.instance_exec(&block)
|
63
|
+
@elements.push(element.__to_config_element)
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def __need_arg(name, args)
|
68
|
+
raise ArgumentError, "#{name} block requires arguments for match pattern" if args.nil? || args.size != 1
|
69
|
+
true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/fluent/engine.rb
CHANGED
@@ -16,318 +16,321 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
module Fluent
|
19
|
+
class EngineClass
|
20
|
+
def initialize
|
21
|
+
@matches = []
|
22
|
+
@sources = []
|
23
|
+
@match_cache = {}
|
24
|
+
@match_cache_keys = []
|
25
|
+
@started = []
|
26
|
+
@default_loop = nil
|
19
27
|
|
28
|
+
@log_emit_thread = nil
|
29
|
+
@log_event_loop_stop = false
|
30
|
+
@log_event_queue = []
|
20
31
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
@sources = []
|
25
|
-
@match_cache = {}
|
26
|
-
@match_cache_keys = []
|
27
|
-
@started = []
|
28
|
-
@default_loop = nil
|
29
|
-
|
30
|
-
@log_emit_thread = nil
|
31
|
-
@log_event_loop_stop = false
|
32
|
-
@log_event_queue = []
|
33
|
-
|
34
|
-
@suppress_emit_error_log_interval = 0
|
35
|
-
@next_emit_error_log_time = nil
|
36
|
-
end
|
32
|
+
@suppress_emit_error_log_interval = 0
|
33
|
+
@next_emit_error_log_time = nil
|
34
|
+
end
|
37
35
|
|
38
|
-
|
36
|
+
MATCH_CACHE_SIZE = 1024
|
39
37
|
|
40
|
-
|
38
|
+
LOG_EMIT_INTERVAL = 0.1
|
41
39
|
|
42
|
-
|
40
|
+
attr_reader :matches, :sources
|
43
41
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
42
|
+
def init
|
43
|
+
BasicSocket.do_not_reverse_lookup = true
|
44
|
+
Plugin.load_plugins
|
45
|
+
if defined?(Encoding)
|
46
|
+
Encoding.default_internal = 'ASCII-8BIT' if Encoding.respond_to?(:default_internal)
|
47
|
+
Encoding.default_external = 'ASCII-8BIT' if Encoding.respond_to?(:default_external)
|
48
|
+
end
|
49
|
+
self
|
50
50
|
end
|
51
|
-
self
|
52
|
-
end
|
53
51
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
52
|
+
def suppress_interval(interval_time)
|
53
|
+
@suppress_emit_error_log_interval = interval_time
|
54
|
+
@next_emit_error_log_time = Time.now.to_i
|
55
|
+
end
|
58
56
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
57
|
+
def read_config(path)
|
58
|
+
$log.info "reading config file", :path=>path
|
59
|
+
File.open(path) {|io|
|
60
|
+
parse_config(io, File.basename(path), File.dirname(path))
|
61
|
+
}
|
62
|
+
end
|
65
63
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
64
|
+
def parse_config(io, fname, basepath=Dir.pwd)
|
65
|
+
conf = if fname =~ /\.rb$/
|
66
|
+
Config::DSL::DSLParser.parse(io, fname)
|
67
|
+
else
|
68
|
+
Config.parse(io, fname, basepath)
|
69
|
+
end
|
70
|
+
configure(conf)
|
71
|
+
conf.check_not_fetched {|key,e|
|
72
|
+
$log.warn "parameter '#{key}' in #{e.to_s.strip} is not used."
|
73
|
+
}
|
74
|
+
end
|
73
75
|
|
74
|
-
|
75
|
-
|
76
|
+
def configure(conf)
|
77
|
+
$log.info "using configuration file: #{conf.to_s.rstrip}"
|
76
78
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
79
|
+
conf.elements.select {|e|
|
80
|
+
e.name == 'source'
|
81
|
+
}.each {|e|
|
82
|
+
type = e['type']
|
83
|
+
unless type
|
84
|
+
raise ConfigError, "Missing 'type' parameter on <source> directive"
|
85
|
+
end
|
86
|
+
$log.info "adding source type=#{type.dump}"
|
85
87
|
|
86
|
-
|
87
|
-
|
88
|
+
input = Plugin.new_input(type)
|
89
|
+
input.configure(e)
|
88
90
|
|
89
|
-
|
90
|
-
|
91
|
+
@sources << input
|
92
|
+
}
|
91
93
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
94
|
+
conf.elements.select {|e|
|
95
|
+
e.name == 'match'
|
96
|
+
}.each {|e|
|
97
|
+
type = e['type']
|
98
|
+
pattern = e.arg
|
99
|
+
unless type
|
100
|
+
raise ConfigError, "Missing 'type' parameter on <match #{e.arg}> directive"
|
101
|
+
end
|
102
|
+
$log.info "adding match", :pattern=>pattern, :type=>type
|
101
103
|
|
102
|
-
|
103
|
-
|
104
|
+
output = Plugin.new_output(type)
|
105
|
+
output.configure(e)
|
104
106
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
107
|
+
match = Match.new(pattern, output)
|
108
|
+
@matches << match
|
109
|
+
}
|
110
|
+
end
|
109
111
|
|
110
|
-
|
111
|
-
|
112
|
-
|
112
|
+
def load_plugin_dir(dir)
|
113
|
+
Plugin.load_plugin_dir(dir)
|
114
|
+
end
|
113
115
|
|
114
|
-
|
115
|
-
|
116
|
-
|
116
|
+
def emit(tag, time, record)
|
117
|
+
unless record.nil?
|
118
|
+
emit_stream tag, OneEventStream.new(time, record)
|
119
|
+
end
|
120
|
+
end
|
117
121
|
|
118
|
-
|
119
|
-
|
120
|
-
|
122
|
+
def emit_array(tag, array)
|
123
|
+
emit_stream tag, ArrayEventStream.new(array)
|
124
|
+
end
|
121
125
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
126
|
+
def emit_stream(tag, es)
|
127
|
+
target = @match_cache[tag]
|
128
|
+
unless target
|
129
|
+
target = match(tag) || NoMatchMatch.new
|
130
|
+
# this is not thread-safe but inconsistency doesn't
|
131
|
+
# cause serious problems while locking causes.
|
132
|
+
if @match_cache_keys.size >= MATCH_CACHE_SIZE
|
133
|
+
@match_cache_keys.delete @match_cache_keys.shift
|
134
|
+
end
|
135
|
+
@match_cache[tag] = target
|
136
|
+
@match_cache_keys << tag
|
130
137
|
end
|
131
|
-
|
132
|
-
|
138
|
+
target.emit(tag, es)
|
139
|
+
rescue => e
|
140
|
+
if @suppress_emit_error_log_interval == 0 || now > @next_emit_error_log_time
|
141
|
+
$log.warn "emit transaction failed ", :error_class=>e.class, :error=>e
|
142
|
+
$log.warn_backtrace
|
143
|
+
# $log.debug "current next_emit_error_log_time: #{Time.at(@next_emit_error_log_time)}"
|
144
|
+
@next_emit_error_log_time = Time.now.to_i + @suppress_emit_error_log_interval
|
145
|
+
# $log.debug "next emit failure log suppressed"
|
146
|
+
# $log.debug "next logged time is #{Time.at(@next_emit_error_log_time)}"
|
147
|
+
end
|
148
|
+
raise
|
133
149
|
end
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
$log.warn "emit transaction failed ", :error_class=>e.class, :error=>e
|
138
|
-
$log.warn_backtrace
|
139
|
-
# $log.debug "current next_emit_error_log_time: #{Time.at(@next_emit_error_log_time)}"
|
140
|
-
@next_emit_error_log_time = Time.now.to_i + @suppress_emit_error_log_interval
|
141
|
-
# $log.debug "next emit failure log suppressed"
|
142
|
-
# $log.debug "next logged time is #{Time.at(@next_emit_error_log_time)}"
|
150
|
+
|
151
|
+
def match(tag)
|
152
|
+
@matches.find {|m| m.match(tag) }
|
143
153
|
end
|
144
|
-
raise
|
145
|
-
end
|
146
154
|
|
147
|
-
|
148
|
-
|
149
|
-
|
155
|
+
def match?(tag)
|
156
|
+
!!match(tag)
|
157
|
+
end
|
150
158
|
|
151
|
-
|
152
|
-
|
153
|
-
|
159
|
+
def flush!
|
160
|
+
flush_recursive(@matches)
|
161
|
+
end
|
154
162
|
|
155
|
-
|
156
|
-
|
157
|
-
|
163
|
+
def now
|
164
|
+
# TODO thread update
|
165
|
+
Time.now.to_i
|
166
|
+
end
|
158
167
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
168
|
+
def log_event_loop
|
169
|
+
$log.disable_events(Thread.current)
|
170
|
+
|
171
|
+
while sleep(LOG_EMIT_INTERVAL)
|
172
|
+
break if @log_event_loop_stop
|
173
|
+
next if @log_event_queue.empty?
|
163
174
|
|
164
|
-
|
165
|
-
|
175
|
+
# NOTE: thead-safe of slice! depends on GVL
|
176
|
+
events = @log_event_queue.slice!(0..-1)
|
177
|
+
next if events.empty?
|
166
178
|
|
167
|
-
|
168
|
-
|
169
|
-
|
179
|
+
events.each {|tag,time,record|
|
180
|
+
begin
|
181
|
+
Engine.emit(tag, time, record)
|
182
|
+
rescue => e
|
183
|
+
$log.error "failed to emit fluentd's log event", :tag => tag, :event => record, :error_class => e.class, :error => e
|
184
|
+
end
|
185
|
+
}
|
186
|
+
end
|
187
|
+
end
|
170
188
|
|
171
|
-
|
172
|
-
|
173
|
-
|
189
|
+
def run
|
190
|
+
begin
|
191
|
+
start
|
174
192
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
rescue => e
|
179
|
-
$log.error "failed to emit fluentd's log event", :tag => tag, :event => record, :error_class => e.class, :error => e
|
193
|
+
if match?($log.tag)
|
194
|
+
$log.enable_event
|
195
|
+
@log_emit_thread = Thread.new(&method(:log_event_loop))
|
180
196
|
end
|
181
|
-
}
|
182
|
-
end
|
183
|
-
end
|
184
197
|
|
185
|
-
|
186
|
-
|
187
|
-
|
198
|
+
# for empty loop
|
199
|
+
@default_loop = Coolio::Loop.default
|
200
|
+
@default_loop.attach Coolio::TimerWatcher.new(1, true)
|
201
|
+
# TODO attach async watch for thread pool
|
202
|
+
@default_loop.run
|
188
203
|
|
189
|
-
|
190
|
-
$log.
|
191
|
-
|
204
|
+
rescue => e
|
205
|
+
$log.error "unexpected error", :error_class=>e.class, :error=>e
|
206
|
+
$log.error_backtrace
|
207
|
+
ensure
|
208
|
+
$log.info "shutting down fluentd"
|
209
|
+
shutdown
|
210
|
+
if @log_emit_thread
|
211
|
+
@log_event_loop_stop = true
|
212
|
+
@log_emit_thread.join
|
213
|
+
end
|
192
214
|
end
|
215
|
+
end
|
193
216
|
|
194
|
-
|
195
|
-
@default_loop
|
196
|
-
|
197
|
-
|
198
|
-
@default_loop.run
|
199
|
-
|
200
|
-
rescue => e
|
201
|
-
$log.error "unexpected error", :error_class=>e.class, :error=>e
|
202
|
-
$log.error_backtrace
|
203
|
-
ensure
|
204
|
-
$log.info "shutting down fluentd"
|
205
|
-
shutdown
|
206
|
-
if @log_emit_thread
|
207
|
-
@log_event_loop_stop = true
|
208
|
-
@log_emit_thread.join
|
217
|
+
def stop
|
218
|
+
if @default_loop
|
219
|
+
@default_loop.stop
|
220
|
+
@default_loop = nil
|
209
221
|
end
|
222
|
+
nil
|
210
223
|
end
|
211
|
-
end
|
212
224
|
|
213
|
-
|
214
|
-
|
215
|
-
@
|
216
|
-
@default_loop = nil
|
225
|
+
def push_log_event(tag, time, record)
|
226
|
+
return if @log_emit_thread.nil?
|
227
|
+
@log_event_queue.push([tag, time, record])
|
217
228
|
end
|
218
|
-
nil
|
219
|
-
end
|
220
229
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
230
|
+
private
|
231
|
+
def start
|
232
|
+
@matches.each {|m|
|
233
|
+
m.start
|
234
|
+
@started << m
|
235
|
+
}
|
236
|
+
@sources.each {|s|
|
237
|
+
s.start
|
238
|
+
@started << s
|
239
|
+
}
|
240
|
+
end
|
225
241
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
242
|
+
def shutdown
|
243
|
+
@started.map {|s|
|
244
|
+
Thread.new do
|
245
|
+
begin
|
246
|
+
s.shutdown
|
247
|
+
rescue => e
|
248
|
+
$log.warn "unexpected error while shutting down", :error_class=>e.class, :error=>e
|
249
|
+
$log.warn_backtrace
|
250
|
+
end
|
251
|
+
end
|
252
|
+
}.each {|t|
|
253
|
+
t.join
|
254
|
+
}
|
255
|
+
end
|
237
256
|
|
238
|
-
|
239
|
-
|
240
|
-
Thread.new do
|
257
|
+
def flush_recursive(array)
|
258
|
+
array.each {|m|
|
241
259
|
begin
|
242
|
-
|
260
|
+
if m.is_a?(Match)
|
261
|
+
m = m.output
|
262
|
+
end
|
263
|
+
if m.is_a?(BufferedOutput)
|
264
|
+
m.force_flush
|
265
|
+
elsif m.is_a?(MultiOutput)
|
266
|
+
flush_recursive(m.outputs)
|
267
|
+
end
|
243
268
|
rescue => e
|
244
|
-
$log.
|
245
|
-
$log.
|
269
|
+
$log.debug "error while force flushing", :error_class=>e.class, :error=>e
|
270
|
+
$log.debug_backtrace
|
246
271
|
end
|
247
|
-
|
248
|
-
|
249
|
-
t.join
|
250
|
-
}
|
251
|
-
end
|
272
|
+
}
|
273
|
+
end
|
252
274
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
if m.is_a?(Match)
|
257
|
-
m = m.output
|
258
|
-
end
|
259
|
-
if m.is_a?(BufferedOutput)
|
260
|
-
m.force_flush
|
261
|
-
elsif m.is_a?(MultiOutput)
|
262
|
-
flush_recursive(m.outputs)
|
263
|
-
end
|
264
|
-
rescue => e
|
265
|
-
$log.debug "error while force flushing", :error_class=>e.class, :error=>e
|
266
|
-
$log.debug_backtrace
|
275
|
+
class NoMatchMatch
|
276
|
+
def initialize
|
277
|
+
@count = 0
|
267
278
|
end
|
268
|
-
}
|
269
|
-
end
|
270
|
-
|
271
|
-
class NoMatchMatch
|
272
|
-
def initialize
|
273
|
-
@count = 0
|
274
|
-
end
|
275
279
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
280
|
+
def emit(tag, es)
|
281
|
+
# TODO use time instead of num of records
|
282
|
+
c = (@count += 1)
|
283
|
+
if c < 512
|
284
|
+
if Math.log(c) / Math.log(2) % 1.0 == 0
|
285
|
+
$log.warn "no patterns matched", :tag=>tag
|
286
|
+
return
|
287
|
+
end
|
288
|
+
else
|
289
|
+
if c % 512 == 0
|
290
|
+
$log.warn "no patterns matched", :tag=>tag
|
291
|
+
return
|
292
|
+
end
|
288
293
|
end
|
294
|
+
$log.on_trace { $log.trace "no patterns matched", :tag=>tag }
|
289
295
|
end
|
290
|
-
$log.on_trace { $log.trace "no patterns matched", :tag=>tag }
|
291
|
-
end
|
292
296
|
|
293
|
-
|
294
|
-
|
297
|
+
def start
|
298
|
+
end
|
295
299
|
|
296
|
-
|
297
|
-
|
300
|
+
def shutdown
|
301
|
+
end
|
298
302
|
|
299
|
-
|
300
|
-
|
303
|
+
def match(tag)
|
304
|
+
false
|
305
|
+
end
|
301
306
|
end
|
302
307
|
end
|
303
|
-
end
|
304
308
|
|
305
|
-
Engine = EngineClass.new
|
309
|
+
Engine = EngineClass.new
|
306
310
|
|
307
311
|
|
308
|
-
module Test
|
309
|
-
|
312
|
+
module Test
|
313
|
+
@@test = false
|
310
314
|
|
311
|
-
|
312
|
-
|
313
|
-
|
315
|
+
def test?
|
316
|
+
@@test
|
317
|
+
end
|
314
318
|
|
315
|
-
|
316
|
-
|
319
|
+
def self.setup
|
320
|
+
@@test = true
|
317
321
|
|
318
|
-
|
319
|
-
|
322
|
+
Fluent.__send__(:remove_const, :Engine)
|
323
|
+
engine = Fluent.const_set(:Engine, EngineClass.new).init
|
320
324
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
325
|
+
engine.define_singleton_method(:now=) {|n|
|
326
|
+
@now = n.to_i
|
327
|
+
}
|
328
|
+
engine.define_singleton_method(:now) {
|
329
|
+
@now || super()
|
330
|
+
}
|
327
331
|
|
328
|
-
|
332
|
+
nil
|
333
|
+
end
|
329
334
|
end
|
330
335
|
end
|
331
336
|
|
332
|
-
end
|
333
|
-
|