fluentd 0.10.11 → 0.10.12
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.
- data/ChangeLog +8 -0
- data/README.rdoc +1 -0
- data/VERSION +1 -1
- data/lib/fluent/engine.rb +18 -1
- data/lib/fluent/plugin/in_exec.rb +1 -1
- data/lib/fluent/plugin/in_tail.rb +231 -87
- data/lib/fluent/plugin/out_exec_filter.rb +2 -2
- data/lib/fluent/plugin/out_forward.rb +2 -4
- data/lib/fluent/version.rb +1 -1
- metadata +14 -14
data/ChangeLog
CHANGED
@@ -1,4 +1,12 @@
|
|
1
1
|
|
2
|
+
Release 0.10.12 - 2012/02/13
|
3
|
+
|
4
|
+
* Engine shows warnings when emitted record doesn't match any outputs
|
5
|
+
* in_tail is rewritten to follow symbolic links correctly
|
6
|
+
* out_forward uses independent default value as 'hard_timeout' parameter
|
7
|
+
*
|
8
|
+
|
9
|
+
|
2
10
|
Release 0.10.11 - 2012/02/10
|
3
11
|
|
4
12
|
* out_forward supports 'standby' parameter
|
data/README.rdoc
CHANGED
@@ -71,6 +71,7 @@ Patches contributed by:
|
|
71
71
|
* {Hiro Yoshikawa}[https://github.com/hiroyoshikawa]
|
72
72
|
* {Masahiro Nakagawa}[https://github.com/repeatedly]
|
73
73
|
* {Nathan Parry}[https://github.com/nparry]
|
74
|
+
* {Nobuyuki Kubota}[https://github.com/nobu-k]
|
74
75
|
* {Sakuro Ozawa}[https://github.com/sakuro]
|
75
76
|
* {Satoshi Tagomori}[https://github.com/tagomoris]
|
76
77
|
* {Takashi Nagayasu}[https://github.com/sumipan]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.10.
|
1
|
+
0.10.12
|
data/lib/fluent/engine.rb
CHANGED
@@ -203,8 +203,25 @@ class EngineClass
|
|
203
203
|
end
|
204
204
|
|
205
205
|
class NoMatchMatch
|
206
|
+
def initialize
|
207
|
+
@count = 0
|
208
|
+
end
|
209
|
+
|
206
210
|
def emit(tag, es)
|
207
|
-
|
211
|
+
# TODO use time instead of num of records
|
212
|
+
c = (@count += 1)
|
213
|
+
if c < 512
|
214
|
+
if Math.log(c) / Math.log(2) % 1.0 == 0
|
215
|
+
$log.warn "no patterns matched", :tag=>tag
|
216
|
+
return
|
217
|
+
end
|
218
|
+
else
|
219
|
+
if c % 512 == 0
|
220
|
+
$log.warn "no patterns matched", :tag=>tag
|
221
|
+
return
|
222
|
+
end
|
223
|
+
end
|
224
|
+
$log.on_trace { $log.trace "no patterns matched", :tag=>tag }
|
208
225
|
end
|
209
226
|
|
210
227
|
def start
|
@@ -122,7 +122,7 @@ class ExecInput < Input
|
|
122
122
|
Engine.emit(tag, time, record)
|
123
123
|
end
|
124
124
|
rescue
|
125
|
-
$log.error "exec failed to emit", :error
|
125
|
+
$log.error "exec failed to emit", :error=>$!.to_s, :line=>line
|
126
126
|
$log.warn_backtrace $!.backtrace
|
127
127
|
end
|
128
128
|
end
|
@@ -28,6 +28,7 @@ class TailInput < Input
|
|
28
28
|
|
29
29
|
config_param :path, :string
|
30
30
|
config_param :tag, :string
|
31
|
+
config_param :rotate_wait, :time, :default => 5
|
31
32
|
config_param :pos_file, :string, :default => nil
|
32
33
|
|
33
34
|
def configure(conf)
|
@@ -57,14 +58,9 @@ class TailInput < Input
|
|
57
58
|
|
58
59
|
def start
|
59
60
|
@loop = Coolio::Loop.new
|
60
|
-
|
61
|
-
$log.debug "following tail of #{path}"
|
61
|
+
@tailers = @paths.map {|path|
|
62
62
|
pe = @pf ? @pf[path] : NullPositionEntry.instance
|
63
|
-
|
64
|
-
@loop.attach h
|
65
|
-
}
|
66
|
-
handlers.each {|h|
|
67
|
-
h.on_change(nil, nil) # initialize call # TODO prev, cur
|
63
|
+
Tailer.new(@loop, path, @rotate_wait, pe, method(:receive_lines))
|
68
64
|
}
|
69
65
|
@thread = Thread.new(&method(:run))
|
70
66
|
end
|
@@ -107,114 +103,226 @@ class TailInput < Input
|
|
107
103
|
return @parser.parse(line)
|
108
104
|
end
|
109
105
|
|
110
|
-
class
|
111
|
-
def initialize(path, pe,
|
112
|
-
|
106
|
+
class Tailer
|
107
|
+
def initialize(loop, path, rotate_wait, pe, receive_lines)
|
108
|
+
@loop = loop
|
109
|
+
@path = path
|
110
|
+
@rotate_wait = rotate_wait
|
113
111
|
@pe = pe
|
114
|
-
@
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
112
|
+
@receive_lines = receive_lines
|
113
|
+
|
114
|
+
@rotate_queue = []
|
115
|
+
@rotate_timer = nil
|
116
|
+
@io_handler = nil
|
117
|
+
|
118
|
+
@rh = RotateHandler.new(path, method(:rotate))
|
119
|
+
@rh.check # invoke rotate
|
120
|
+
@rh.on_rotate = method(:on_rotate)
|
121
|
+
@rh.attach(@loop)
|
122
|
+
end
|
123
|
+
|
124
|
+
def on_rotate(io)
|
125
|
+
return if @rotate_queue.include?(io)
|
126
|
+
$log.info "detected rotation of #{@path}; waiting #{@rotate_wait} seconds"
|
127
|
+
@rotate_queue.push(io)
|
128
|
+
|
129
|
+
# start rotate_timer
|
130
|
+
unless @rotate_timer
|
131
|
+
@rotate_timer = RotateTimer.new(@rotate_wait, method(:on_rotate_timer))
|
132
|
+
@rotate_timer.attach(@loop)
|
123
133
|
end
|
124
|
-
@buffer = ''
|
125
|
-
@callback = callback
|
126
|
-
super(path)
|
127
134
|
end
|
128
135
|
|
129
|
-
def
|
130
|
-
|
131
|
-
|
136
|
+
def on_rotate_timer
|
137
|
+
io = @rotate_queue.first
|
138
|
+
rotate(io, 0)
|
139
|
+
end
|
140
|
+
|
141
|
+
def rotate(io, start_pos=nil)
|
142
|
+
# start_pos is nil if first
|
143
|
+
io_handler = IOHandler.new(io, start_pos, @pe, @receive_lines)
|
144
|
+
|
145
|
+
if @io_handler
|
146
|
+
@io_handler.close
|
147
|
+
@io_handler = nil
|
148
|
+
end
|
149
|
+
io_handler.attach(@loop)
|
150
|
+
@io_handler = io_handler
|
151
|
+
@rotate_queue.shift
|
152
|
+
|
153
|
+
if @rotate_queue.empty?
|
154
|
+
@rotate_timer.detach if @rotate_timer
|
155
|
+
@rotate_timer = nil
|
156
|
+
end
|
157
|
+
end
|
132
158
|
|
133
|
-
|
134
|
-
|
159
|
+
def shutdown
|
160
|
+
@rotate_queue.reject! {|io|
|
161
|
+
io.close
|
162
|
+
true
|
163
|
+
}
|
164
|
+
if @io_handler
|
165
|
+
@io_handler.close
|
166
|
+
@io_handler = nil
|
167
|
+
end
|
168
|
+
if @rotate_timer
|
169
|
+
@rotate_timer.detach
|
170
|
+
@rotate_timer = nil
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
class RotateHandler
|
176
|
+
def initialize(path, on_rotate)
|
177
|
+
@path = path
|
178
|
+
@inode = nil
|
179
|
+
@fsize = 0
|
180
|
+
@on_rotate = on_rotate
|
181
|
+
@path = path
|
182
|
+
@stat_watcher = Stat.new(self, @path)
|
183
|
+
@timer_watcher = Timer.new(self, 1)
|
184
|
+
end
|
185
|
+
|
186
|
+
attr_accessor :on_rotate
|
187
|
+
|
188
|
+
def check
|
189
|
+
begin
|
190
|
+
io = File.open(@path)
|
191
|
+
rescue Errno::ENOENT
|
192
|
+
# moved or deleted
|
193
|
+
@inode = nil
|
194
|
+
@fsize = 0
|
195
|
+
return
|
196
|
+
end
|
197
|
+
|
198
|
+
begin
|
199
|
+
stat = io.stat
|
135
200
|
inode = stat.ino
|
201
|
+
fsize = stat.size
|
136
202
|
|
137
|
-
if @inode != inode ||
|
138
|
-
#
|
139
|
-
@
|
140
|
-
|
141
|
-
f.seek(@pos)
|
203
|
+
if @inode != inode || fsize < @fsize
|
204
|
+
# rotated or truncated
|
205
|
+
@on_rotate.call(io)
|
206
|
+
io = nil
|
142
207
|
end
|
143
208
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
209
|
+
@inode = inode
|
210
|
+
@fsize = fsize
|
211
|
+
ensure
|
212
|
+
io.close if io
|
213
|
+
end
|
148
214
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
end
|
215
|
+
rescue
|
216
|
+
$log.error $!.to_s
|
217
|
+
$log.error_backtrace
|
218
|
+
end
|
154
219
|
|
155
|
-
|
156
|
-
|
220
|
+
def attach(loop)
|
221
|
+
@stat_watcher.attach(loop)
|
222
|
+
@timer_watcher.attach(loop)
|
223
|
+
end
|
157
224
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
end
|
163
|
-
lines << line
|
164
|
-
end
|
225
|
+
def detach
|
226
|
+
@stat_watcher.detach
|
227
|
+
@timer_watcher.detach
|
228
|
+
end
|
165
229
|
|
166
|
-
|
167
|
-
|
230
|
+
def attached?
|
231
|
+
@stat_watcher.attached?
|
232
|
+
end
|
168
233
|
|
169
|
-
|
170
|
-
|
171
|
-
@
|
172
|
-
|
173
|
-
@pe.update_pos(@pos)
|
234
|
+
class Stat < Coolio::StatWatcher
|
235
|
+
def initialize(h, path)
|
236
|
+
@h = h
|
237
|
+
super(path)
|
174
238
|
end
|
175
239
|
|
176
|
-
|
240
|
+
def on_change(prev, cur)
|
241
|
+
@h.check
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
class Timer < Coolio::TimerWatcher
|
246
|
+
def initialize(h, interval)
|
247
|
+
@h = h
|
248
|
+
super(interval, true)
|
249
|
+
end
|
177
250
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
# TODO rescue
|
251
|
+
def on_timer
|
252
|
+
@h.check
|
253
|
+
end
|
182
254
|
end
|
183
255
|
end
|
184
256
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
INO_OFFSET = 17
|
190
|
-
INO_SIZE = 8
|
191
|
-
LN_OFFSET = 25
|
192
|
-
SIZE = 26
|
193
|
-
|
194
|
-
def initialize(file, seek)
|
195
|
-
@file = file
|
196
|
-
@seek = seek
|
257
|
+
class RotateTimer < Coolio::TimerWatcher
|
258
|
+
def initialize(interval, callback)
|
259
|
+
super(interval, true)
|
260
|
+
@callback = callback
|
197
261
|
end
|
198
262
|
|
199
|
-
def
|
200
|
-
@
|
201
|
-
|
202
|
-
|
263
|
+
def on_timer
|
264
|
+
@callback.call
|
265
|
+
rescue
|
266
|
+
# TODO log?
|
203
267
|
end
|
268
|
+
end
|
204
269
|
|
205
|
-
|
206
|
-
|
207
|
-
|
270
|
+
class IOHandler < Coolio::IOWatcher
|
271
|
+
def initialize(io, start_pos, pe, receive_lines)
|
272
|
+
$log.info "following tail of #{io.path}"
|
273
|
+
@io = io
|
274
|
+
@pe = pe
|
275
|
+
@receive_lines = receive_lines
|
276
|
+
|
277
|
+
if start_pos
|
278
|
+
# rotated
|
279
|
+
@pos = start_pos
|
280
|
+
|
281
|
+
else
|
282
|
+
# first time
|
283
|
+
stat = io.stat
|
284
|
+
fsize = stat.size
|
285
|
+
inode = stat.ino
|
286
|
+
if inode == @pe.read_inode
|
287
|
+
# seek to the saved position
|
288
|
+
@pos = @pe.read_pos
|
289
|
+
else
|
290
|
+
# seek to the end of the file.
|
291
|
+
# logs never duplicate but may be lost if fluentd is down.
|
292
|
+
@pos = fsize
|
293
|
+
@pe.update(inode, @pos)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
io.seek(@pos)
|
298
|
+
|
299
|
+
@buffer = ''
|
300
|
+
super(io)
|
208
301
|
end
|
209
302
|
|
210
|
-
def
|
211
|
-
|
212
|
-
|
303
|
+
def on_readable
|
304
|
+
lines = []
|
305
|
+
|
306
|
+
while line = @io.gets
|
307
|
+
@buffer << line
|
308
|
+
@pos = @io.pos
|
309
|
+
unless @buffer[@buffer.length-1] == ?\n
|
310
|
+
break
|
311
|
+
end
|
312
|
+
lines << line
|
313
|
+
end
|
314
|
+
|
315
|
+
@pe.update_pos(@pos)
|
316
|
+
@receive_lines.call(lines) unless lines.empty?
|
317
|
+
rescue
|
318
|
+
$log.error $!.to_s
|
319
|
+
$log.error_backtrace
|
320
|
+
close
|
213
321
|
end
|
214
322
|
|
215
|
-
def
|
216
|
-
|
217
|
-
@
|
323
|
+
def close
|
324
|
+
detach if attached?
|
325
|
+
@io.close unless @io.closed?
|
218
326
|
end
|
219
327
|
end
|
220
328
|
|
@@ -256,6 +364,42 @@ class TailInput < Input
|
|
256
364
|
end
|
257
365
|
end
|
258
366
|
|
367
|
+
# pos inode
|
368
|
+
# ffffffffffffffff\tffffffff\n
|
369
|
+
class PositionEntry
|
370
|
+
POS_SIZE = 16
|
371
|
+
INO_OFFSET = 17
|
372
|
+
INO_SIZE = 8
|
373
|
+
LN_OFFSET = 25
|
374
|
+
SIZE = 26
|
375
|
+
|
376
|
+
def initialize(file, seek)
|
377
|
+
@file = file
|
378
|
+
@seek = seek
|
379
|
+
end
|
380
|
+
|
381
|
+
def update(ino, pos)
|
382
|
+
@file.pos = @seek
|
383
|
+
@file.write "%016x\t%08x" % [pos, ino]
|
384
|
+
@inode = ino
|
385
|
+
end
|
386
|
+
|
387
|
+
def update_pos(pos)
|
388
|
+
@file.pos = @seek
|
389
|
+
@file.write "%016x" % pos
|
390
|
+
end
|
391
|
+
|
392
|
+
def read_inode
|
393
|
+
@file.pos = @seek + INO_OFFSET
|
394
|
+
@file.read(8).to_i(16)
|
395
|
+
end
|
396
|
+
|
397
|
+
def read_pos
|
398
|
+
@file.pos = @seek
|
399
|
+
@file.read(16).to_i(16)
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
259
403
|
class NullPositionEntry
|
260
404
|
require 'singleton'
|
261
405
|
include Singleton
|
@@ -167,7 +167,7 @@ class ExecFilterOutput < BufferedOutput
|
|
167
167
|
Engine.emit(tag, time, record)
|
168
168
|
end
|
169
169
|
rescue
|
170
|
-
$log.error "exec_filter failed to emit", :error
|
170
|
+
$log.error "exec_filter failed to emit", :error=>$!.to_s, :line=>line
|
171
171
|
$log.warn_backtrace $!.backtrace
|
172
172
|
end
|
173
173
|
|
@@ -217,7 +217,7 @@ class ExecFilterOutput < BufferedOutput
|
|
217
217
|
def run
|
218
218
|
@io.each_line(&@each_line)
|
219
219
|
rescue
|
220
|
-
$log.error "exec_filter process exited", :error
|
220
|
+
$log.error "exec_filter process exited", :error=>$!.to_s
|
221
221
|
$log.warn_backtrace $!.backtrace
|
222
222
|
ensure
|
223
223
|
Process.waitpid(@pid)
|
@@ -31,7 +31,7 @@ class ForwardOutput < ObjectBufferedOutput
|
|
31
31
|
config_param :send_timeout, :time, :default => 60
|
32
32
|
config_param :heartbeat_interval, :time, :default => 1
|
33
33
|
config_param :recover_wait, :time, :default => 10
|
34
|
-
config_param :hard_timeout, :time, :default =>
|
34
|
+
config_param :hard_timeout, :time, :default => 60
|
35
35
|
config_param :phi_threshold, :integer, :default => 8
|
36
36
|
attr_reader :nodes
|
37
37
|
|
@@ -52,8 +52,6 @@ class ForwardOutput < ObjectBufferedOutput
|
|
52
52
|
e['port'] = port.to_s
|
53
53
|
end
|
54
54
|
|
55
|
-
@hard_timeout ||= @send_timeout
|
56
|
-
|
57
55
|
recover_sample_size = @recover_wait / @heartbeat_interval
|
58
56
|
|
59
57
|
conf.elements.each {|e|
|
@@ -245,7 +243,7 @@ class ForwardOutput < ObjectBufferedOutput
|
|
245
243
|
@usock.send "", 0, sockaddr
|
246
244
|
rescue
|
247
245
|
# TODO log
|
248
|
-
$log.debug "failed to send heartbeat packet to #{Socket.unpack_sockaddr_in(sockaddr).reverse.join(':')}", :error
|
246
|
+
$log.debug "failed to send heartbeat packet to #{Socket.unpack_sockaddr_in(sockaddr).reverse.join(':')}", :error=>$!.to_s
|
249
247
|
end
|
250
248
|
}
|
251
249
|
end
|
data/lib/fluent/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluentd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.12
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-14 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: msgpack
|
16
|
-
requirement: &
|
16
|
+
requirement: &70256836669480 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.4.4
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70256836669480
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: json
|
27
|
-
requirement: &
|
27
|
+
requirement: &70256836648880 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.4.3
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70256836648880
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: yajl-ruby
|
38
|
-
requirement: &
|
38
|
+
requirement: &70256836646880 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 1.0.0
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70256836646880
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: cool.io
|
49
|
-
requirement: &
|
49
|
+
requirement: &70256836645660 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.1.0
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70256836645660
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: http_parser.rb
|
60
|
-
requirement: &
|
60
|
+
requirement: &70256836644620 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 0.5.1
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70256836644620
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
|
-
requirement: &
|
71
|
+
requirement: &70256836643580 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: 0.9.2
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70256836643580
|
80
80
|
description:
|
81
81
|
email: frsyuki@gmail.com
|
82
82
|
executables:
|