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 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
@@ -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.11
1
+ 0.10.12
@@ -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
- $log.on_trace { $log.trace "no pattern matched", :tag=>tag }
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=>$!, :line=>line
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
- handlers = @paths.map {|path|
61
- $log.debug "following tail of #{path}"
61
+ @tailers = @paths.map {|path|
62
62
  pe = @pf ? @pf[path] : NullPositionEntry.instance
63
- h = Handler.new(path, pe, method(:receive_lines))
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 Handler < Coolio::StatWatcher
111
- def initialize(path, pe, callback)
112
- stat = File.stat(path)
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
- @inode = stat.ino
115
- if @inode == @pe.read_inode
116
- # seek to the saved position
117
- @pos = @pe.read_pos
118
- else
119
- # seek to the end of file first.
120
- # logs never duplicate but may be lost if fluent is down.
121
- @pos = stat.size
122
- @pe.update(@inode, @pos)
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 on_change(prev, cur)
130
- lines = []
131
- inode = nil
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
- File.open(path) {|f|
134
- stat = f.stat
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 || stat.size < @pos
138
- # moved or deleted
139
- @pos = 0
140
- else
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
- line = f.gets
145
- unless line
146
- break
147
- end
209
+ @inode = inode
210
+ @fsize = fsize
211
+ ensure
212
+ io.close if io
213
+ end
148
214
 
149
- @buffer << line
150
- unless line[line.length-1] == ?\n
151
- @pos = f.pos
152
- break
153
- end
215
+ rescue
216
+ $log.error $!.to_s
217
+ $log.error_backtrace
218
+ end
154
219
 
155
- lines << @buffer
156
- @buffer = ''
220
+ def attach(loop)
221
+ @stat_watcher.attach(loop)
222
+ @timer_watcher.attach(loop)
223
+ end
157
224
 
158
- while line = f.gets
159
- unless line[line.length-1] == ?\n
160
- @buffer = line
161
- break
162
- end
163
- lines << line
164
- end
225
+ def detach
226
+ @stat_watcher.detach
227
+ @timer_watcher.detach
228
+ end
165
229
 
166
- @pos = f.pos
167
- }
230
+ def attached?
231
+ @stat_watcher.attached?
232
+ end
168
233
 
169
- if @inode != inode
170
- @pe.update(inode, @pos)
171
- @inode = inode
172
- else
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
- @callback.call(lines) unless lines.empty?
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
- rescue Errno::ENOENT
179
- # moved or deleted
180
- @pos = 0
181
- # TODO rescue
251
+ def on_timer
252
+ @h.check
253
+ end
182
254
  end
183
255
  end
184
256
 
185
- # pos inode
186
- # ffffffffffffffff\tffffffff\n
187
- class PositionEntry
188
- POS_SIZE = 16
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 update(ino, pos)
200
- @file.pos = @seek
201
- @file.write "%016x\t%08x" % [pos, ino]
202
- @inode = ino
263
+ def on_timer
264
+ @callback.call
265
+ rescue
266
+ # TODO log?
203
267
  end
268
+ end
204
269
 
205
- def update_pos(pos)
206
- @file.pos = @seek
207
- @file.write "%016x" % pos
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 read_inode
211
- @file.pos = @seek + INO_OFFSET
212
- @file.read(8).to_i(16)
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 read_pos
216
- @file.pos = @seek
217
- @file.read(16).to_i(16)
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=>$!, :line=>line
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 => nil
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
@@ -1,5 +1,5 @@
1
1
  module Fluent
2
2
 
3
- VERSION = '0.10.11'
3
+ VERSION = '0.10.12'
4
4
 
5
5
  end
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.11
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-10 00:00:00.000000000Z
12
+ date: 2012-02-14 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: msgpack
16
- requirement: &70203141220220 !ruby/object:Gem::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: *70203141220220
24
+ version_requirements: *70256836669480
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: json
27
- requirement: &70203141219740 !ruby/object:Gem::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: *70203141219740
35
+ version_requirements: *70256836648880
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: yajl-ruby
38
- requirement: &70203141219240 !ruby/object:Gem::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: *70203141219240
46
+ version_requirements: *70256836646880
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: cool.io
49
- requirement: &70203141218740 !ruby/object:Gem::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: *70203141218740
57
+ version_requirements: *70256836645660
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: http_parser.rb
60
- requirement: &70203141218220 !ruby/object:Gem::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: *70203141218220
68
+ version_requirements: *70256836644620
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
- requirement: &70203141217440 !ruby/object:Gem::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: *70203141217440
79
+ version_requirements: *70256836643580
80
80
  description:
81
81
  email: frsyuki@gmail.com
82
82
  executables: