fluentd 0.10.25 → 0.10.26

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,25 @@
1
1
 
2
+ Release 0.10.26 - 2012/09/26
3
+
4
+ * added in_debug_agent plugin and fluent-debug command which enable you to
5
+ gather internal information of running Fluentd process using interactive shell
6
+ * supervisor: --user commandline argument also inherits secondary groups (id -G)
7
+ * out_forward: supports 'expire_dns_cache' option to set DNS expire time or disable
8
+ caching. Default behavior is 'never expire' which is same as former versions
9
+ * out_forward: assumes successful data transfer via TCP as a successful
10
+ heartbeat.
11
+ * out_forward: lazier failure detection: default phi_threshold 8 -> 10
12
+ * in_forward: uses other nodes aggressively if it couldn't send data to the first
13
+ candidate to not stall during the wait time before detecting failure
14
+ * in_forward: fixed shutdown procedure
15
+ * in_tail: seeks to the saved position if detected log rotation actually
16
+ didn't rotate the file (meaning inode doesn't change). this change enables
17
+ cronolog to work with Fluentd.
18
+ * in_tail: fixed a problem that it couldn't recover from uncaught exceptions
19
+ caused by output plugins
20
+ * fluentd command supports '-q' option to decrease log level
21
+
22
+
2
23
  Release 0.10.25 - 2012/07/23
3
24
 
4
25
  * shutdown won't block
data/Rakefile CHANGED
@@ -24,7 +24,7 @@ begin
24
24
  gemspec.test_files = Dir["test/**/*.rb"]
25
25
  gemspec.files = Dir["bin/**/*", "lib/**/*", "test/**/*.rb"] +
26
26
  %w[fluent.conf VERSION AUTHORS Rakefile COPYING fluentd.gemspec Gemfile]
27
- gemspec.executables = ['fluentd', 'fluent-cat', 'fluent-gem']
27
+ gemspec.executables = ['fluentd', 'fluent-cat', 'fluent-gem', 'fluent-debug']
28
28
  gemspec.required_ruby_version = '~> 1.9.2'
29
29
  end
30
30
  Jeweler::GemcutterTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.25
1
+ 0.10.26
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require 'rubygems' unless defined?(gem)
4
+ here = File.dirname(__FILE__)
5
+ $LOAD_PATH << File.expand_path(File.join(here, '..', 'lib'))
6
+ require 'fluent/command/debug'
@@ -26,6 +26,12 @@
26
26
  # tag apache.access
27
27
  #</source>
28
28
 
29
+ # Listen DRb for debug
30
+ <source>
31
+ type debug_agent
32
+ port 24230
33
+ </source>
34
+
29
35
 
30
36
  ## match tag=apache.access and write to file
31
37
  #<match apache.access>
@@ -0,0 +1,82 @@
1
+ #
2
+ # Fluent
3
+ #
4
+ # Copyright (C) 2011 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'optparse'
20
+
21
+ op = OptionParser.new
22
+
23
+ host = '127.0.0.1'
24
+ port = 24230
25
+ unix = nil
26
+
27
+ op.on('-h', '--host HOST', "fluent host (default: #{host})") {|s|
28
+ host = s
29
+ }
30
+
31
+ op.on('-p', '--port PORT', "debug_agent tcp port (default: #{port})", Integer) {|i|
32
+ port = i
33
+ }
34
+
35
+ op.on('-u', '--unix PATH', "use unix socket instead of tcp") {|b|
36
+ unix = b
37
+ }
38
+
39
+ begin
40
+ op.parse!(ARGV)
41
+
42
+ if ARGV.length != 0
43
+ usage nil
44
+ end
45
+ rescue
46
+ usage $!.to_s
47
+ end
48
+
49
+ require 'drb/drb'
50
+
51
+ if unix
52
+ uri = "drbunix:#{unix}"
53
+ else
54
+ uri = "druby://#{host}:#{port}"
55
+ end
56
+
57
+ require 'fluent/load'
58
+
59
+ $log = Fluent::Log.new(STDERR, Fluent::Log::LEVEL_TRACE)
60
+ Fluent::Engine.init
61
+
62
+ remote_engine = DRb::DRbObject.new_with_uri(uri)
63
+
64
+ Fluent.module_eval do
65
+ remove_const(:Engine)
66
+ const_set(:Engine, remote_engine)
67
+ end
68
+
69
+ include Fluent
70
+
71
+ puts "Connected to #{uri}."
72
+ puts "Usage:"
73
+ puts " Engine.match('some.tag').output : get an output plugin instance"
74
+ puts " Engine.sources[i] : get input plugin instances"
75
+ puts " Plugin.load_plugin(type,name) : load plugin class (use this if you get DRb::DRbUnknown)"
76
+ puts ""
77
+
78
+ Encoding.default_internal = nil if Encoding.respond_to?(:default_internal)
79
+
80
+ require 'irb'
81
+ IRB.start
82
+
@@ -78,14 +78,15 @@ op.on('-i', '--inline-config CONFIG_STRING', "inline config which is appended to
78
78
  }
79
79
 
80
80
 
81
- op.on('-v', '--verbose', "increment verbose level (-v: debug, -vv: trace)", TrueClass) {|b|
81
+ op.on('-v', '--verbose', "increase verbose level (-v: debug, -vv: trace)", TrueClass) {|b|
82
82
  if b
83
- case opts[:log_level]
84
- when Fluent::Log::LEVEL_INFO
85
- opts[:log_level] = Fluent::Log::LEVEL_DEBUG
86
- when Fluent::Log::LEVEL_DEBUG
87
- opts[:log_level] = Fluent::Log::LEVEL_TRACE
88
- end
83
+ opts[:log_level] = [opts[:log_level] - 1, Fluent::Log::LEVEL_TRACE].max
84
+ end
85
+ }
86
+
87
+ op.on('-q', '--quiet', "decrease verbose level (-q: warn, -qq: error)", TrueClass) {|b|
88
+ if b
89
+ opts[:log_level] = [opts[:log_level] + 1, Fluent::Log::LEVEL_ERROR].min
89
90
  end
90
91
  }
91
92
 
@@ -27,6 +27,8 @@ class EngineClass
27
27
  @default_loop = nil
28
28
  end
29
29
 
30
+ attr_reader :matches, :sources
31
+
30
32
  def init
31
33
  BasicSocket.do_not_reverse_lookup = true
32
34
  Plugin.load_plugins
@@ -65,6 +65,10 @@ class PluginClass
65
65
  nil
66
66
  end
67
67
 
68
+ def load_plugin(type, name)
69
+ try_load_plugin(name, type)
70
+ end
71
+
68
72
  private
69
73
  def load_gem_plugins
70
74
  return unless defined? Gem
@@ -0,0 +1,57 @@
1
+ #
2
+ # Fluent
3
+ #
4
+ # Copyright (C) 2011 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ module Fluent
19
+
20
+
21
+ class DebugAgentInput < Input
22
+ Plugin.register_input('debug_agent', self)
23
+
24
+ def initialize
25
+ require 'drb/drb'
26
+ super
27
+ end
28
+
29
+ config_param :bind, :string, :default => '0.0.0.0'
30
+ config_param :port, :integer, :default => 24230
31
+ config_param :unix_path, :integer, :default => nil
32
+ #config_param :unix_mode # TODO
33
+ config_param :object, :string, :default => 'Engine'
34
+
35
+ def configure(conf)
36
+ super
37
+ end
38
+
39
+ def start
40
+ if @unix_path
41
+ require 'drb/unix'
42
+ uri = "drbunix:#{@unix_path}"
43
+ else
44
+ uri = "druby://#{@bind}:#{@port}"
45
+ end
46
+ $log.info "listening dRuby", :uri => uri, :object => @object
47
+ obj = eval(@object)
48
+ @server = DRb::DRbServer.new(uri, obj)
49
+ end
50
+
51
+ def shutdown
52
+ @server.stop_service if @server
53
+ end
54
+ end
55
+
56
+
57
+ end
@@ -51,7 +51,8 @@ class ForwardInput < Input
51
51
  @loop.watchers.each {|w| w.detach }
52
52
  @loop.stop
53
53
  @usock.close
54
- TCPSocket.open('127.0.0.1', @port) {|sock| } # FIXME @thread.join blocks without this line
54
+ listen_address = (@bind == '0.0.0.0' ? '127.0.0.1' : @bind)
55
+ TCPSocket.open(listen_address, @port) {|sock| } # FIXME @thread.join blocks without this line
55
56
  @thread.join
56
57
  @lsock.close
57
58
  end
@@ -200,7 +201,7 @@ class ForwardInput < Input
200
201
 
201
202
  def on_heartbeat_request(host, port, msg)
202
203
  #$log.trace "heartbeat request from #{host}:#{port}"
203
- @usock.send "", 0, host, port
204
+ @usock.send "\0", 0, host, port
204
205
  end
205
206
  end
206
207
 
@@ -92,7 +92,7 @@ class ObjectSpaceInput < Input
92
92
  map = {}
93
93
 
94
94
  ObjectSpace.each_object {|obj|
95
- klass = obj.class
95
+ klass = obj.class rescue Object
96
96
  if c = map[klass]
97
97
  c.incr!
98
98
  else
@@ -22,7 +22,7 @@ class SyslogInput < Input
22
22
  Plugin.register_input('syslog', self)
23
23
 
24
24
  SYSLOG_REGEXP = /^\<([0-9]+)\>(.*)/
25
- SYSLOG_ALL_REGEXP = /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* [^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?[^\:]*\: *(?<message>.*)$/
25
+ SYSLOG_ALL_REGEXP = /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?[^\:]*\: *(?<message>.*)$/
26
26
  TIME_FORMAT = "%b %d %H:%M:%S"
27
27
 
28
28
  FACILITY_MAP = {
@@ -155,7 +155,7 @@ class SyslogInput < Input
155
155
  when "pri"
156
156
  pri = value.to_i
157
157
  when "time"
158
- time = Time.strptime(value, TIME_FORMAT).to_i
158
+ time = Time.strptime(value.gsub(/ +/, ' '), TIME_FORMAT).to_i
159
159
  else
160
160
  record[name] = value
161
161
  end
@@ -189,7 +189,7 @@ class SyslogInput < Input
189
189
  end
190
190
 
191
191
  def on_readable
192
- msg, addr = @io.recvfrom_nonblock(1024)
192
+ msg, addr = @io.recvfrom_nonblock(2048)
193
193
  #host = addr[3]
194
194
  #port = addr[1]
195
195
  #@callback.call(host, port, msg)
@@ -61,7 +61,7 @@ class TailInput < Input
61
61
  def start
62
62
  @loop = Coolio::Loop.new
63
63
  @tails = @paths.map {|path|
64
- pe = @pf ? @pf[path] : NullPositionEntry.instance
64
+ pe = @pf ? @pf[path] : MemoryPositionEntry.new
65
65
  TailWatcher.new(path, @rotate_wait, pe, &method(:receive_lines))
66
66
  }
67
67
  @tails.each {|tail|
@@ -102,7 +102,11 @@ class TailInput < Input
102
102
  }
103
103
 
104
104
  unless es.empty?
105
- Engine.emit_stream(@tag, es)
105
+ begin
106
+ Engine.emit_stream(@tag, es)
107
+ rescue
108
+ # ignore errors. Engine shows logs and backtraces.
109
+ end
106
110
  end
107
111
  end
108
112
 
@@ -114,7 +118,7 @@ class TailInput < Input
114
118
  def initialize(path, rotate_wait, pe, &receive_lines)
115
119
  @path = path
116
120
  @rotate_wait = rotate_wait
117
- @pe = pe || NullPositionEntry.instance
121
+ @pe = pe || MemoryPositionEntry.new
118
122
  @receive_lines = receive_lines
119
123
 
120
124
  @rotate_queue = []
@@ -156,6 +160,19 @@ class TailInput < Input
156
160
 
157
161
  while @rotate_queue.first.ready?
158
162
  if io = @rotate_queue.first.io
163
+ stat = io.stat
164
+ inode = stat.ino
165
+ if inode == @pe.read_inode
166
+ # rotated file has the same inode number with the last file.
167
+ # assuming following situation:
168
+ # a) file was once renamed and backed, or
169
+ # b) symlink or hardlink to the same file is recreated
170
+ # in either case, seek to the saved position
171
+ pos = @pe.read_pos
172
+ else
173
+ pos = io.pos
174
+ end
175
+ @pe.update(inode, pos)
159
176
  io_handler = IOHandler.new(io, @pe, &@receive_lines)
160
177
  else
161
178
  io_handler = NullIOHandler.new
@@ -386,7 +403,7 @@ class TailInput < Input
386
403
  @file.write "0000000000000000\t00000000\n"
387
404
  @last_pos = @file.pos
388
405
 
389
- @map[path] = PositionEntry.new(@file, seek)
406
+ @map[path] = FilePositionEntry.new(@file, seek)
390
407
  end
391
408
 
392
409
  def self.parse(file)
@@ -399,7 +416,7 @@ class TailInput < Input
399
416
  pos = m[2].to_i(16)
400
417
  ino = m[3].to_i(16)
401
418
  seek = file.pos - line.bytesize + path.bytesize + 1
402
- map[path] = PositionEntry.new(file, seek)
419
+ map[path] = FilePositionEntry.new(file, seek)
403
420
  }
404
421
  new(file, map, file.pos)
405
422
  end
@@ -407,7 +424,7 @@ class TailInput < Input
407
424
 
408
425
  # pos inode
409
426
  # ffffffffffffffff\tffffffff\n
410
- class PositionEntry
427
+ class FilePositionEntry
411
428
  POS_SIZE = 16
412
429
  INO_OFFSET = 17
413
430
  INO_SIZE = 8
@@ -441,18 +458,27 @@ class TailInput < Input
441
458
  end
442
459
  end
443
460
 
444
- class NullPositionEntry
445
- require 'singleton'
446
- include Singleton
461
+ class MemoryPositionEntry
462
+ def initialize
463
+ @pos = 0
464
+ @inode = 0
465
+ end
466
+
447
467
  def update(ino, pos)
468
+ @inode = ino
469
+ @pos = pos
448
470
  end
471
+
449
472
  def update_pos(pos)
473
+ @pos = pos
450
474
  end
475
+
451
476
  def read_pos
452
- 0
477
+ @pos
453
478
  end
479
+
454
480
  def read_inode
455
- 0
481
+ @inode
456
482
  end
457
483
  end
458
484
  end
@@ -25,14 +25,15 @@ class ForwardOutput < ObjectBufferedOutput
25
25
  super
26
26
  require 'socket'
27
27
  require 'fileutils'
28
- @nodes = {} #=> {sockaddr => Node}
28
+ @nodes = [] #=> [Node]
29
29
  end
30
30
 
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
34
  config_param :hard_timeout, :time, :default => 60
35
- config_param :phi_threshold, :integer, :default => 8
35
+ config_param :expire_dns_cache, :time, :default => nil # 0 means disable cache
36
+ config_param :phi_threshold, :integer, :default => 16
36
37
  attr_reader :nodes
37
38
 
38
39
  # backward compatibility
@@ -72,10 +73,8 @@ class ForwardOutput < ObjectBufferedOutput
72
73
  end
73
74
 
74
75
  failure = FailureDetector.new(@heartbeat_interval, @hard_timeout, Time.now.to_i.to_f)
75
- sockaddr = Socket.pack_sockaddr_in(port, host)
76
- port, host = Socket.unpack_sockaddr_in(sockaddr)
77
- @nodes[sockaddr] = Node.new(name, host, port, weight, standby, failure,
78
- @phi_threshold, recover_sample_size)
76
+ @nodes << Node.new(name, host, port, weight, standby, failure,
77
+ @phi_threshold, recover_sample_size, @expire_dns_cache)
79
78
  $log.info "adding forwarding server '#{name}'", :host=>host, :port=>port, :weight=>weight
80
79
  }
81
80
  end
@@ -123,23 +122,34 @@ class ForwardOutput < ObjectBufferedOutput
123
122
  end
124
123
 
125
124
  def write_objects(tag, es)
125
+ error = nil
126
+
126
127
  wlen = @weight_array.length
127
128
  wlen.times do
128
129
  node = @weight_array[@rr]
129
130
  @rr = (@rr + 1) % wlen
130
131
 
131
132
  if node.available?
132
- send_data(node, tag, es)
133
- return
133
+ begin
134
+ send_data(node, tag, es)
135
+ return
136
+ rescue
137
+ # for load balancing during detecting crashed servers
138
+ error = $! # use the latest error
139
+ end
134
140
  end
135
141
  end
136
142
 
137
- raise "no nodes are available" # TODO message
143
+ if error
144
+ raise error
145
+ else
146
+ raise "no nodes are available" # TODO message
147
+ end
138
148
  end
139
149
 
140
150
  private
141
151
  def rebuild_weight_array
142
- standby_nodes, regular_nodes = @nodes.values.partition {|n|
152
+ standby_nodes, regular_nodes = @nodes.partition {|n|
143
153
  n.standby?
144
154
  }
145
155
 
@@ -170,6 +180,10 @@ class ForwardOutput < ObjectBufferedOutput
170
180
  }
171
181
  }
172
182
 
183
+ # for load balancing during detecting crashed servers
184
+ coe = (regular_nodes.size * 6) / weight_array.size
185
+ weight_array *= coe if coe > 1
186
+
173
187
  r = Random.new(@rand_seed)
174
188
  weight_array.sort_by! { r.rand }
175
189
 
@@ -209,6 +223,8 @@ class ForwardOutput < ObjectBufferedOutput
209
223
 
210
224
  # writeRawBody(packed_es)
211
225
  es.write_to(sock)
226
+
227
+ node.heartbeat(false)
212
228
  ensure
213
229
  sock.close
214
230
  end
@@ -216,7 +232,7 @@ class ForwardOutput < ObjectBufferedOutput
216
232
 
217
233
  def connect(node)
218
234
  # TODO unix socket?
219
- TCPSocket.new(node.host, node.port)
235
+ TCPSocket.new(node.resolved_host, node.port)
220
236
  end
221
237
 
222
238
  class HeartbeatRequestTimer < Coolio::TimerWatcher
@@ -234,16 +250,16 @@ class ForwardOutput < ObjectBufferedOutput
234
250
 
235
251
  def on_timer
236
252
  return if @finished
237
- @nodes.each_pair {|sockaddr,n|
253
+ @nodes.each {|n|
238
254
  if n.tick
239
255
  rebuild_weight_array
240
256
  end
241
257
  begin
242
258
  #$log.trace "sending heartbeat #{n.host}:#{n.port}"
243
- @usock.send "", 0, sockaddr
259
+ @usock.send "\0", 0, Socket.pack_sockaddr_in(n.port, n.resolved_host)
244
260
  rescue
245
261
  # TODO log
246
- $log.debug "failed to send heartbeat packet to #{Socket.unpack_sockaddr_in(sockaddr).reverse.join(':')}", :error=>$!.to_s
262
+ $log.debug "failed to send heartbeat packet to #{n.host}:#{n.port}", :error=>$!.to_s
247
263
  end
248
264
  }
249
265
  end
@@ -267,7 +283,8 @@ class ForwardOutput < ObjectBufferedOutput
267
283
  end
268
284
 
269
285
  def on_heartbeat(sockaddr, msg)
270
- if node = @nodes[sockaddr]
286
+ port, host = Socket.unpack_sockaddr_in(sockaddr)
287
+ if node = @nodes.find {|n| n.sockaddr == sockaddr }
271
288
  #$log.trace "heartbeat from '#{node.name}'", :host=>node.host, :port=>node.port
272
289
  if node.heartbeat
273
290
  rebuild_weight_array
@@ -277,7 +294,7 @@ class ForwardOutput < ObjectBufferedOutput
277
294
 
278
295
  class Node
279
296
  def initialize(name, host, port, weight, standby, failure,
280
- phi_threshold, recover_sample_size)
297
+ phi_threshold, recover_sample_size, expire_dns_cache)
281
298
  @name = name
282
299
  @host = host
283
300
  @port = port
@@ -286,11 +303,17 @@ class ForwardOutput < ObjectBufferedOutput
286
303
  @failure = failure
287
304
  @phi_threshold = phi_threshold
288
305
  @recover_sample_size = recover_sample_size
306
+ @expire_dns_cache = expire_dns_cache
289
307
  @available = true
308
+
309
+ @resolved_host = nil
310
+ @resolved_time = 0
311
+ resolved_host # check dns
290
312
  end
291
313
 
292
314
  attr_reader :name, :host, :port, :weight
293
315
  attr_writer :weight, :standby, :available
316
+ attr_reader :sockaddr # used by on_heartbeat
294
317
 
295
318
  def available?
296
319
  @available
@@ -300,6 +323,34 @@ class ForwardOutput < ObjectBufferedOutput
300
323
  @standby
301
324
  end
302
325
 
326
+ def resolved_host
327
+ case @expire_dns_cache
328
+ when 0
329
+ # cache is disabled
330
+ return resolve_dns!
331
+
332
+ when nil
333
+ # persistent cache
334
+ return @resolved_host ||= resolve_dns!
335
+
336
+ else
337
+ now = Engine.now
338
+ rh = @resolved_host
339
+ if !rh || now - @resolved_time >= @expire_dns_cache
340
+ rh = @resolved_host = resolve_dns!
341
+ @resolved_time = now
342
+ end
343
+ return rh
344
+ end
345
+ end
346
+
347
+ def resolve_dns!
348
+ @sockaddr = Socket.pack_sockaddr_in(@port, @host)
349
+ port, resolved_host = Socket.unpack_sockaddr_in(sockaddr)
350
+ return resolved_host
351
+ end
352
+ private :resolve_dns!
353
+
303
354
  def tick
304
355
  now = Time.now.to_f
305
356
  if !@available
@@ -312,6 +363,7 @@ class ForwardOutput < ObjectBufferedOutput
312
363
  if @failure.hard_timeout?(now)
313
364
  $log.info "detached forwarding server '#{@name}'", :host=>@host, :port=>@port, :hard_timeout=>true
314
365
  @available = false
366
+ @resolved_host = nil # expire cached host
315
367
  @failure.clear
316
368
  return true
317
369
  end
@@ -321,6 +373,7 @@ class ForwardOutput < ObjectBufferedOutput
321
373
  if phi > @phi_threshold
322
374
  $log.info "detached forwarding server '#{@name}'", :host=>@host, :port=>@port, :phi=>phi
323
375
  @available = false
376
+ @resolved_host = nil # expire cached host
324
377
  @failure.clear
325
378
  return true
326
379
  else
@@ -328,13 +381,13 @@ class ForwardOutput < ObjectBufferedOutput
328
381
  end
329
382
  end
330
383
 
331
- def heartbeat
384
+ def heartbeat(detect=true)
332
385
  now = Time.now.to_f
333
386
  @failure.add(now)
334
387
  #$log.trace "heartbeat from '#{@name}'", :host=>@host, :port=>@port, :available=>@available, :sample_size=>@failure.sample_size
335
- if !@available && @failure.sample_size > @recover_sample_size
336
- $log.info "recovered forwarding server '#{@name}'", :host=>@host, :port=>@port
388
+ if detect && !@available && @failure.sample_size > @recover_sample_size
337
389
  @available = true
390
+ $log.info "recovered forwarding server '#{@name}'", :host=>@host, :port=>@port
338
391
  return true
339
392
  else
340
393
  return nil
@@ -267,6 +267,13 @@ class Supervisor
267
267
  exit 1
268
268
  end
269
269
  end
270
+
271
+ user_groups = `id -G #{@chuser}`.split.map(&:to_i)
272
+ if $?.to_i != 0
273
+ exit 1
274
+ end
275
+
276
+ Process.groups = Process.groups | user_groups
270
277
  Process::UID.change_privilege(chuid)
271
278
  end
272
279
  end
@@ -39,7 +39,7 @@ class TestDriver
39
39
 
40
40
  def configure(str)
41
41
  if str.is_a?(Config)
42
- @config = @str
42
+ @config = str
43
43
  else
44
44
  @config = Config.parse(str, "(test)")
45
45
  end
@@ -1,5 +1,5 @@
1
1
  module Fluent
2
2
 
3
- VERSION = '0.10.25'
3
+ VERSION = '0.10.26'
4
4
 
5
5
  end
@@ -18,6 +18,7 @@ module MixinTest
18
18
  def teardown
19
19
  super
20
20
  Timecop.return
21
+ GC.start
21
22
  end
22
23
 
23
24
  module Checker
@@ -51,7 +52,7 @@ module MixinTest
51
52
  }
52
53
 
53
54
  Fluent::Test::BufferedOutputTestDriver.new(klass) {
54
- }.configure("tyep #{register_output_name}" + conf)
55
+ }.configure("type #{register_output_name}" + conf)
55
56
  end
56
57
  end
57
58
 
@@ -1,6 +1,12 @@
1
1
  require 'fluent/test'
2
2
 
3
3
  class ObjectSpaceInputTest < Test::Unit::TestCase
4
+ class FailObject
5
+ def self.class
6
+ raise "error"
7
+ end
8
+ end
9
+
4
10
  def setup
5
11
  Fluent::Test.setup
6
12
  end
@@ -0,0 +1,70 @@
1
+ require 'fluent/test'
2
+
3
+ class SyslogInputTest < Test::Unit::TestCase
4
+ def setup
5
+ Fluent::Test.setup
6
+ end
7
+
8
+ CONFIG = %[
9
+ port 9911
10
+ bind 127.0.0.1
11
+ tag syslog
12
+ ]
13
+
14
+ def create_driver(conf=CONFIG)
15
+ Fluent::Test::InputTestDriver.new(Fluent::SyslogInput).configure(conf)
16
+ end
17
+
18
+ def test_configure
19
+ d = create_driver
20
+ assert_equal 9911, d.instance.port
21
+ assert_equal '127.0.0.1', d.instance.bind
22
+ end
23
+
24
+ def test_time_format
25
+ d = create_driver
26
+
27
+ tests = [
28
+ {'msg' => '<6>Sep 11 00:00:00 localhost logger: foo', 'expected' => Time.strptime('Sep 11 00:00:00', '%b %d %H:%M:%S').to_i},
29
+ {'msg' => '<6>Sep 1 00:00:00 localhost logger: foo', 'expected' => Time.strptime('Sep 1 00:00:00', '%b %d %H:%M:%S').to_i},
30
+ ]
31
+
32
+ d.run do
33
+ u = UDPSocket.new
34
+ u.connect('127.0.0.1', 9911)
35
+ tests.each {|test|
36
+ u.send(test['msg'], 0)
37
+ }
38
+ sleep 1
39
+ end
40
+
41
+ emits = d.emits
42
+ emits.each_index {|i|
43
+ assert_equal(tests[i]['expected'], emits[i][1])
44
+ }
45
+ end
46
+
47
+ def test_msg_size
48
+ d = create_driver
49
+
50
+ tests = [
51
+ {'msg' => '<6>Sep 10 00:00:00 localhost logger: ' + 'x' * 100, 'expected' => 'x' * 100},
52
+ {'msg' => '<6>Sep 10 00:00:00 localhost logger: ' + 'x' * 1024, 'expected' => 'x' * 1024},
53
+ ]
54
+
55
+ d.run do
56
+ u = UDPSocket.new
57
+ u.connect('127.0.0.1', 9911)
58
+ tests.each {|test|
59
+ u.send(test['msg'], 0)
60
+ }
61
+ sleep 1
62
+ end
63
+
64
+ emits = d.emits
65
+ emits.each_index {|i|
66
+ assert_equal(tests[i]['expected'], emits[i][2]['message'])
67
+ }
68
+ end
69
+ end
70
+
@@ -27,7 +27,7 @@ class ForwardOutputTest < Test::Unit::TestCase
27
27
  nodes = d.instance.nodes
28
28
  assert_equal 51, d.instance.send_timeout
29
29
  assert_equal 1, nodes.length
30
- node = nodes.values.first
30
+ node = nodes.first
31
31
  assert_equal "test", node.name
32
32
  assert_equal '127.0.0.1', node.host
33
33
  assert_equal 13999, node.port
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.25
4
+ version: 0.10.26
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-23 00:00:00.000000000 Z
12
+ date: 2012-09-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: msgpack
@@ -161,6 +161,7 @@ executables:
161
161
  - fluentd
162
162
  - fluent-cat
163
163
  - fluent-gem
164
+ - fluent-debug
164
165
  extensions: []
165
166
  extra_rdoc_files:
166
167
  - ChangeLog
@@ -172,12 +173,14 @@ files:
172
173
  - Rakefile
173
174
  - VERSION
174
175
  - bin/fluent-cat
176
+ - bin/fluent-debug
175
177
  - bin/fluent-gem
176
178
  - bin/fluentd
177
179
  - fluent.conf
178
180
  - fluentd.gemspec
179
181
  - lib/fluent/buffer.rb
180
182
  - lib/fluent/command/cat.rb
183
+ - lib/fluent/command/debug.rb
181
184
  - lib/fluent/command/fluentd.rb
182
185
  - lib/fluent/config.rb
183
186
  - lib/fluent/engine.rb
@@ -196,6 +199,7 @@ files:
196
199
  - lib/fluent/plugin/buf_file.rb
197
200
  - lib/fluent/plugin/buf_memory.rb
198
201
  - lib/fluent/plugin/buf_zfile.rb
202
+ - lib/fluent/plugin/in_debug_agent.rb
199
203
  - lib/fluent/plugin/in_exec.rb
200
204
  - lib/fluent/plugin/in_forward.rb
201
205
  - lib/fluent/plugin/in_gc_stat.rb
@@ -232,6 +236,7 @@ files:
232
236
  - test/plugin/in_http.rb
233
237
  - test/plugin/in_object_space.rb
234
238
  - test/plugin/in_stream.rb
239
+ - test/plugin/in_syslog.rb
235
240
  - test/plugin/in_tail.rb
236
241
  - test/plugin/out_copy.rb
237
242
  - test/plugin/out_exec.rb
@@ -278,6 +283,7 @@ test_files:
278
283
  - test/plugin/in_http.rb
279
284
  - test/plugin/in_object_space.rb
280
285
  - test/plugin/in_stream.rb
286
+ - test/plugin/in_syslog.rb
281
287
  - test/plugin/in_tail.rb
282
288
  - test/plugin/out_copy.rb
283
289
  - test/plugin/out_exec.rb