fluentd 0.10.49 → 0.10.50
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 +4 -4
- data/ChangeLog +11 -0
- data/fluentd.gemspec +1 -1
- data/lib/fluent/config/v1_parser.rb +4 -4
- data/lib/fluent/engine.rb +22 -6
- data/lib/fluent/formatter.rb +4 -1
- data/lib/fluent/mixin.rb +0 -14
- data/lib/fluent/parser.rb +70 -17
- data/lib/fluent/plugin/buf_memory.rb +1 -1
- data/lib/fluent/plugin/in_http.rb +0 -7
- data/lib/fluent/plugin/in_syslog.rb +7 -7
- data/lib/fluent/plugin/in_tail.rb +56 -40
- data/lib/fluent/test/input_test.rb +3 -4
- data/lib/fluent/version.rb +1 -1
- data/spec/config/config_parser_spec.rb +30 -30
- data/spec/config/configurable_spec.rb +2 -2
- data/spec/config/configure_proxy_spec.rb +20 -20
- data/spec/config/dsl_spec.rb +1 -1
- data/spec/config/helper.rb +3 -3
- data/spec/config/literal_parser_spec.rb +136 -136
- data/spec/config/section_spec.rb +5 -5
- data/test/plugin/test_in_tail.rb +129 -14
- data/test/plugin/test_out_file.rb +24 -0
- data/test/test_formatter.rb +9 -2
- data/test/test_parser.rb +209 -119
- 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: dcc68a7c0e54890fee8388d37e9801edac3fb77f
|
4
|
+
data.tar.gz: 992e8adb5d7c043f91f58e095aaf1d6cb5c7b363
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84b5ed1c244b405de5ed3d637fbad708cbb361a42a7efd13793c2992f7aad66c9c9d49256b105545e65e2627d5e3de64838e0df05d9e0d6bd82e6c47d7f56230
|
7
|
+
data.tar.gz: ad3c062f06ec7b472f7efb72acc693c9b71e83fc4eaf1df4c6c23ca5820543cb72bfea59778f3f5cb42f1510927f1f52c9f674a8bee3debdb3f86c4cc75e5950
|
data/ChangeLog
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
Release 0.10.50 - 2014/06/17
|
2
|
+
|
3
|
+
* in_tail: Fix race condition at shutdown
|
4
|
+
* in_tail: read_from_head now works without pos_file
|
5
|
+
* in_tail: Fix multiline format parsing without format_firstline
|
6
|
+
* formatter: Add add_newline option to SingleValueFormatter
|
7
|
+
* parser: Add block based API to support multi-events parsing
|
8
|
+
* config: Fix encoding mismatch when @include used in v1
|
9
|
+
* engine: Serialize shutdown order. Now shutdown input plugins first
|
10
|
+
* Update rspec to 3.x
|
11
|
+
|
1
12
|
Release 0.10.49 - 2014/06/05
|
2
13
|
|
3
14
|
* in_http: Add format option to support various input data format
|
data/fluentd.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |gem|
|
|
28
28
|
gem.add_development_dependency("rake", [">= 0.9.2"])
|
29
29
|
gem.add_development_dependency("flexmock")
|
30
30
|
gem.add_development_dependency("parallel_tests", [">= 0.15.3"])
|
31
|
-
gem.add_development_dependency("rspec", ["~>
|
31
|
+
gem.add_development_dependency("rspec", ["~> 3.0.0"])
|
32
32
|
gem.add_development_dependency("simplecov", ["~> 0.6.4"])
|
33
33
|
gem.add_development_dependency("rr", [">= 1.0.0"])
|
34
34
|
gem.add_development_dependency("timecop", [">= 0.3.0"])
|
@@ -142,16 +142,16 @@ module Fluent
|
|
142
142
|
basepath = File.dirname(path)
|
143
143
|
fname = File.basename(path)
|
144
144
|
data = File.read(path)
|
145
|
+
data.force_encoding('UTF-8')
|
145
146
|
ss = StringScanner.new(data)
|
146
147
|
V1Parser.new(ss, basepath, fname, @eval_context).parse_element(true, nil, attrs, elems)
|
147
148
|
}
|
148
|
-
|
149
149
|
else
|
150
|
+
require 'open-uri'
|
150
151
|
basepath = '/'
|
151
152
|
fname = path
|
152
|
-
|
153
|
-
data
|
154
|
-
open(uri) { |f| data = f.read }
|
153
|
+
data = open(uri) { |f| f.read }
|
154
|
+
data.force_encoding('UTF-8')
|
155
155
|
ss = StringScanner.new(data)
|
156
156
|
V1Parser.new(ss, basepath, fname, @eval_context).parse_element(true, nil, attrs, elems)
|
157
157
|
end
|
data/lib/fluent/engine.rb
CHANGED
@@ -22,7 +22,8 @@ module Fluent
|
|
22
22
|
@sources = []
|
23
23
|
@match_cache = {}
|
24
24
|
@match_cache_keys = []
|
25
|
-
@
|
25
|
+
@started_sources = []
|
26
|
+
@started_matches = []
|
26
27
|
@default_loop = nil
|
27
28
|
@engine_stopped = false
|
28
29
|
|
@@ -254,25 +255,40 @@ module Fluent
|
|
254
255
|
def start
|
255
256
|
@matches.each {|m|
|
256
257
|
m.start
|
257
|
-
@
|
258
|
+
@started_matches << m
|
258
259
|
}
|
259
260
|
@sources.each {|s|
|
260
261
|
s.start
|
261
|
-
@
|
262
|
+
@started_sources << s
|
262
263
|
}
|
263
264
|
end
|
264
265
|
|
265
266
|
def shutdown
|
266
|
-
|
267
|
+
# Shutdown Input plugin first to prevent emitting to terminated Output plugin
|
268
|
+
@started_sources.map { |s|
|
267
269
|
Thread.new do
|
268
270
|
begin
|
269
271
|
s.shutdown
|
270
272
|
rescue => e
|
271
|
-
$log.warn "unexpected error while shutting down", :error_class=>e.class, :error=>e
|
273
|
+
$log.warn "unexpected error while shutting down", :plugin => s.class, :plugin_id => s.plugin_id, :error_class => e.class, :error => e
|
272
274
|
$log.warn_backtrace
|
273
275
|
end
|
274
276
|
end
|
275
|
-
}.each {|t|
|
277
|
+
}.each { |t|
|
278
|
+
t.join
|
279
|
+
}
|
280
|
+
# Output plugin as filter emits records at shutdown so emit problem still exist.
|
281
|
+
# This problem will be resolved after actual filter mechanizm.
|
282
|
+
@started_matches.map { |m|
|
283
|
+
Thread.new do
|
284
|
+
begin
|
285
|
+
m.shutdown
|
286
|
+
rescue => e
|
287
|
+
$log.warn "unexpected error while shutting down", :plugin => m.output.class, :plugin_id => m.output.plugin_id, :error_class => e.class, :error => e
|
288
|
+
$log.warn_backtrace
|
289
|
+
end
|
290
|
+
end
|
291
|
+
}.each { |t|
|
276
292
|
t.join
|
277
293
|
}
|
278
294
|
end
|
data/lib/fluent/formatter.rb
CHANGED
@@ -126,9 +126,12 @@ module Fluent
|
|
126
126
|
include Configurable
|
127
127
|
|
128
128
|
config_param :message_key, :string, :default => 'message'
|
129
|
+
config_param :add_newline, :bool, :default => true
|
129
130
|
|
130
131
|
def format(tag, time, record)
|
131
|
-
record[@message_key]
|
132
|
+
text = record[@message_key].to_s
|
133
|
+
text << "\n" if @add_newline
|
134
|
+
text
|
132
135
|
end
|
133
136
|
end
|
134
137
|
|
data/lib/fluent/mixin.rb
CHANGED
@@ -67,20 +67,6 @@ module Fluent
|
|
67
67
|
def format_nocache(time)
|
68
68
|
# will be overridden in initialize
|
69
69
|
end
|
70
|
-
|
71
|
-
def self.configure(conf)
|
72
|
-
if time_format = conf['time_format']
|
73
|
-
@time_format = time_format
|
74
|
-
end
|
75
|
-
|
76
|
-
if localtime = conf['localtime']
|
77
|
-
@localtime = true
|
78
|
-
elsif utc = conf['utc']
|
79
|
-
@localtime = false
|
80
|
-
end
|
81
|
-
|
82
|
-
@timef = new(@time_format, @localtime)
|
83
|
-
end
|
84
70
|
end
|
85
71
|
|
86
72
|
|
data/lib/fluent/parser.rb
CHANGED
@@ -147,7 +147,12 @@ module Fluent
|
|
147
147
|
def call(text)
|
148
148
|
m = @regexp.match(text)
|
149
149
|
unless m
|
150
|
-
|
150
|
+
if block_given?
|
151
|
+
yield nil, nil
|
152
|
+
return
|
153
|
+
else
|
154
|
+
return nil, nil
|
155
|
+
end
|
151
156
|
end
|
152
157
|
|
153
158
|
time = nil
|
@@ -170,7 +175,11 @@ module Fluent
|
|
170
175
|
|
171
176
|
time ||= Engine.now
|
172
177
|
|
173
|
-
|
178
|
+
if block_given?
|
179
|
+
yield time, record
|
180
|
+
else # keep backward compatibility. will be removed at v1
|
181
|
+
return time, record
|
182
|
+
end
|
174
183
|
end
|
175
184
|
end
|
176
185
|
|
@@ -202,9 +211,17 @@ module Fluent
|
|
202
211
|
time = Engine.now
|
203
212
|
end
|
204
213
|
|
205
|
-
|
214
|
+
if block_given?
|
215
|
+
yield time, record
|
216
|
+
else
|
217
|
+
return time, record
|
218
|
+
end
|
206
219
|
rescue Yajl::ParseError
|
207
|
-
|
220
|
+
if block_given?
|
221
|
+
yield nil, nil
|
222
|
+
else
|
223
|
+
return nil, nil
|
224
|
+
end
|
208
225
|
end
|
209
226
|
end
|
210
227
|
|
@@ -267,7 +284,11 @@ module Fluent
|
|
267
284
|
config_param :delimiter, :string, :default => "\t"
|
268
285
|
|
269
286
|
def call(text)
|
270
|
-
|
287
|
+
if block_given?
|
288
|
+
yield values_map(text.split(@delimiter))
|
289
|
+
else
|
290
|
+
return values_map(text.split(@delimiter))
|
291
|
+
end
|
271
292
|
end
|
272
293
|
end
|
273
294
|
|
@@ -291,7 +312,11 @@ module Fluent
|
|
291
312
|
values.push(value)
|
292
313
|
end
|
293
314
|
|
294
|
-
|
315
|
+
if block_given?
|
316
|
+
yield values_map(values)
|
317
|
+
else
|
318
|
+
return values_map(values)
|
319
|
+
end
|
295
320
|
end
|
296
321
|
end
|
297
322
|
|
@@ -302,7 +327,11 @@ module Fluent
|
|
302
327
|
end
|
303
328
|
|
304
329
|
def call(text)
|
305
|
-
|
330
|
+
if block_given?
|
331
|
+
yield values_map(CSV.parse_line(text))
|
332
|
+
else
|
333
|
+
return values_map(CSV.parse_line(text))
|
334
|
+
end
|
306
335
|
end
|
307
336
|
end
|
308
337
|
|
@@ -314,7 +343,11 @@ module Fluent
|
|
314
343
|
def call(text)
|
315
344
|
record = {}
|
316
345
|
record[@message_key] = text
|
317
|
-
|
346
|
+
if block_given?
|
347
|
+
yield Engine.now, record
|
348
|
+
else
|
349
|
+
return Engine.now, record
|
350
|
+
end
|
318
351
|
end
|
319
352
|
end
|
320
353
|
|
@@ -331,7 +364,12 @@ module Fluent
|
|
331
364
|
def call(text)
|
332
365
|
m = REGEXP.match(text)
|
333
366
|
unless m
|
334
|
-
|
367
|
+
if block_given?
|
368
|
+
yield nil, nil
|
369
|
+
return
|
370
|
+
else
|
371
|
+
return nil, nil
|
372
|
+
end
|
335
373
|
end
|
336
374
|
|
337
375
|
host = m['host']
|
@@ -369,7 +407,11 @@ module Fluent
|
|
369
407
|
"agent" => agent,
|
370
408
|
}
|
371
409
|
|
372
|
-
|
410
|
+
if block_given?
|
411
|
+
yield time, record
|
412
|
+
else
|
413
|
+
return time, record
|
414
|
+
end
|
373
415
|
end
|
374
416
|
end
|
375
417
|
|
@@ -396,16 +438,24 @@ module Fluent
|
|
396
438
|
|
397
439
|
if @format_firstline
|
398
440
|
check_format_regexp(@format_firstline, 'format_firstline')
|
399
|
-
@
|
441
|
+
@firstline_regex = Regexp.new(@format_firstline[1..-2])
|
400
442
|
end
|
401
443
|
end
|
402
444
|
|
403
|
-
def call(text)
|
404
|
-
|
445
|
+
def call(text, &block)
|
446
|
+
if block
|
447
|
+
@parser.call(text, &block)
|
448
|
+
else
|
449
|
+
@parser.call(text)
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
def has_firstline?
|
454
|
+
!!@format_firstline
|
405
455
|
end
|
406
456
|
|
407
457
|
def firstline?(text)
|
408
|
-
@
|
458
|
+
@firstline_regex.match(text)
|
409
459
|
end
|
410
460
|
|
411
461
|
private
|
@@ -506,7 +556,6 @@ module Fluent
|
|
506
556
|
end
|
507
557
|
|
508
558
|
@parser = RegexpParser.new(regexp, conf)
|
509
|
-
|
510
559
|
else
|
511
560
|
# built-in template
|
512
561
|
begin
|
@@ -524,8 +573,12 @@ module Fluent
|
|
524
573
|
return true
|
525
574
|
end
|
526
575
|
|
527
|
-
def parse(text)
|
528
|
-
|
576
|
+
def parse(text, &block)
|
577
|
+
if block
|
578
|
+
@parser.call(text, &block)
|
579
|
+
else # keep backward compatibility. Will be removed at v1
|
580
|
+
return @parser.call(text)
|
581
|
+
end
|
529
582
|
end
|
530
583
|
end
|
531
584
|
end
|
@@ -22,7 +22,7 @@ module Fluent
|
|
22
22
|
@data.force_encoding('ASCII-8BIT')
|
23
23
|
now = Time.now.utc
|
24
24
|
u1 = ((now.to_i*1000*1000+now.usec) << 12 | rand(0xfff))
|
25
|
-
@unique_id = [u1 >> 32, u1 &
|
25
|
+
@unique_id = [u1 >> 32, u1 & 0xffffffff, rand(0xffffffff), rand(0xffffffff)].pack('NNNN')
|
26
26
|
super(key)
|
27
27
|
end
|
28
28
|
|
@@ -131,14 +131,14 @@ module Fluent
|
|
131
131
|
pri = m[1].to_i
|
132
132
|
text = m[2]
|
133
133
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
emit(pri, time, record)
|
134
|
+
@parser.parse(text) { |time, record|
|
135
|
+
unless time && record
|
136
|
+
log.warn "pattern not match: #{text.inspect}"
|
137
|
+
return
|
138
|
+
end
|
141
139
|
|
140
|
+
emit(pri, time, record)
|
141
|
+
}
|
142
142
|
rescue
|
143
143
|
log.warn data.dump, :error=>$!.to_s
|
144
144
|
log.debug_backtrace
|
@@ -129,7 +129,7 @@ module Fluent
|
|
129
129
|
end
|
130
130
|
|
131
131
|
def setup_watcher(path, pe)
|
132
|
-
tw = TailWatcher.new(path, @rotate_wait, pe, log, method(:update_watcher), &method(:receive_lines))
|
132
|
+
tw = TailWatcher.new(path, @rotate_wait, pe, log, @read_from_head, method(:update_watcher), &method(:receive_lines))
|
133
133
|
tw.attach(@loop)
|
134
134
|
tw
|
135
135
|
end
|
@@ -158,7 +158,7 @@ module Fluent
|
|
158
158
|
if tw
|
159
159
|
tw.unwatched = unwatched
|
160
160
|
if immediate
|
161
|
-
close_watcher(tw)
|
161
|
+
close_watcher(tw, false)
|
162
162
|
else
|
163
163
|
close_watcher_after_rotate_wait(tw)
|
164
164
|
end
|
@@ -173,8 +173,12 @@ module Fluent
|
|
173
173
|
close_watcher_after_rotate_wait(rotated_tw) if rotated_tw
|
174
174
|
end
|
175
175
|
|
176
|
-
|
177
|
-
|
176
|
+
# TailWatcher#close is called by another thread at shutdown phase.
|
177
|
+
# It causes 'can't modify string; temporarily locked' error in IOHandler
|
178
|
+
# so adding close_io argument to avoid this problem.
|
179
|
+
# At shutdown, IOHandler's io will be released automatically after detached the event loop
|
180
|
+
def close_watcher(tw, close_io = true)
|
181
|
+
tw.close(close_io)
|
178
182
|
flush_buffer(tw)
|
179
183
|
if tw.unwatched && @pf
|
180
184
|
@pf[tw.path].update_pos(PositionFile::UNWATCHED_POSITION)
|
@@ -189,17 +193,18 @@ module Fluent
|
|
189
193
|
def flush_buffer(tw)
|
190
194
|
if lb = tw.line_buffer
|
191
195
|
lb.chomp!
|
192
|
-
time, record
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
196
|
+
@parser.parse(lb) { |time, record|
|
197
|
+
if time && record
|
198
|
+
tag = if @tag_prefix || @tag_suffix
|
199
|
+
@tag_prefix + tw.tag + @tag_suffix
|
200
|
+
else
|
201
|
+
@tag
|
202
|
+
end
|
203
|
+
Engine.emit(tag, time, record)
|
204
|
+
else
|
205
|
+
log.warn "got incomplete line at shutdown from #{tw.path}: #{lb.inspect}"
|
206
|
+
end
|
207
|
+
}
|
203
208
|
end
|
204
209
|
end
|
205
210
|
|
@@ -226,19 +231,16 @@ module Fluent
|
|
226
231
|
end
|
227
232
|
end
|
228
233
|
|
229
|
-
def parse_line(line)
|
230
|
-
return @parser.parse(line)
|
231
|
-
end
|
232
|
-
|
233
234
|
def convert_line_to_event(line, es)
|
234
235
|
begin
|
235
236
|
line.chomp! # remove \n
|
236
|
-
time, record
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
237
|
+
@parser.parse(line) { |time, record|
|
238
|
+
if time && record
|
239
|
+
es.add(time, record)
|
240
|
+
else
|
241
|
+
log.warn "pattern not match: #{line.inspect}"
|
242
|
+
end
|
243
|
+
}
|
242
244
|
rescue => e
|
243
245
|
log.warn line.dump, :error => e.to_s
|
244
246
|
log.debug_backtrace(e.backtrace)
|
@@ -256,29 +258,43 @@ module Fluent
|
|
256
258
|
def parse_multilines(lines, tail_watcher)
|
257
259
|
lb = tail_watcher.line_buffer
|
258
260
|
es = MultiEventStream.new
|
259
|
-
|
260
|
-
|
261
|
-
if
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
if lb.nil?
|
267
|
-
log.warn "got incomplete line before first line from #{tail_watcher.path}: #{lb.inspect}"
|
261
|
+
if @parser.parser.has_firstline?
|
262
|
+
lines.each { |line|
|
263
|
+
if @parser.parser.firstline?(line)
|
264
|
+
if lb
|
265
|
+
convert_line_to_event(lb, es)
|
266
|
+
end
|
267
|
+
lb = line
|
268
268
|
else
|
269
|
-
lb
|
269
|
+
if lb.nil?
|
270
|
+
log.warn "got incomplete line before first line from #{tail_watcher.path}: #{lb.inspect}"
|
271
|
+
else
|
272
|
+
lb << line
|
273
|
+
end
|
270
274
|
end
|
275
|
+
}
|
276
|
+
else
|
277
|
+
lb ||= ''
|
278
|
+
lines.each do |line|
|
279
|
+
lb << line
|
280
|
+
@parser.parse(lb) { |time, record|
|
281
|
+
if time && record
|
282
|
+
convert_line_to_event(lb, es)
|
283
|
+
lb = ''
|
284
|
+
end
|
285
|
+
}
|
271
286
|
end
|
272
|
-
|
287
|
+
end
|
273
288
|
tail_watcher.line_buffer = lb
|
274
289
|
es
|
275
290
|
end
|
276
291
|
|
277
292
|
class TailWatcher
|
278
|
-
def initialize(path, rotate_wait, pe, log, update_watcher, &receive_lines)
|
293
|
+
def initialize(path, rotate_wait, pe, log, read_from_head, update_watcher, &receive_lines)
|
279
294
|
@path = path
|
280
295
|
@rotate_wait = rotate_wait
|
281
296
|
@pe = pe || MemoryPositionEntry.new
|
297
|
+
@read_from_head = read_from_head
|
282
298
|
@receive_lines = receive_lines
|
283
299
|
@update_watcher = update_watcher
|
284
300
|
|
@@ -313,8 +329,8 @@ module Fluent
|
|
313
329
|
@stat_trigger.detach if @stat_trigger.attached?
|
314
330
|
end
|
315
331
|
|
316
|
-
def close
|
317
|
-
if @io_handler
|
332
|
+
def close(close_io = true)
|
333
|
+
if close_io && @io_handler
|
318
334
|
@io_handler.on_notify
|
319
335
|
@io_handler.close
|
320
336
|
end
|
@@ -354,7 +370,7 @@ module Fluent
|
|
354
370
|
# seek to the end of the any files.
|
355
371
|
# logs may duplicate without this seek because it's not sure the file is
|
356
372
|
# existent file or rotated new file.
|
357
|
-
pos = fsize
|
373
|
+
pos = @read_from_head ? 0 : fsize
|
358
374
|
@pe.update(inode, pos)
|
359
375
|
end
|
360
376
|
io.seek(pos)
|