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 +21 -0
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/bin/fluent-debug +6 -0
- data/fluent.conf +6 -0
- data/lib/fluent/command/debug.rb +82 -0
- data/lib/fluent/command/fluentd.rb +8 -7
- data/lib/fluent/engine.rb +2 -0
- data/lib/fluent/plugin.rb +4 -0
- data/lib/fluent/plugin/in_debug_agent.rb +57 -0
- data/lib/fluent/plugin/in_forward.rb +3 -2
- data/lib/fluent/plugin/in_object_space.rb +1 -1
- data/lib/fluent/plugin/in_syslog.rb +3 -3
- data/lib/fluent/plugin/in_tail.rb +37 -11
- data/lib/fluent/plugin/out_forward.rb +72 -19
- data/lib/fluent/supervisor.rb +7 -0
- data/lib/fluent/test/base.rb +1 -1
- data/lib/fluent/version.rb +1 -1
- data/test/mixin.rb +2 -1
- data/test/plugin/in_object_space.rb +6 -0
- data/test/plugin/in_syslog.rb +70 -0
- data/test/plugin/out_forward.rb +1 -1
- metadata +8 -2
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.
|
1
|
+
0.10.26
|
data/bin/fluent-debug
ADDED
data/fluent.conf
CHANGED
@@ -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', "
|
81
|
+
op.on('-v', '--verbose', "increase verbose level (-v: debug, -vv: trace)", TrueClass) {|b|
|
82
82
|
if b
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
|
data/lib/fluent/engine.rb
CHANGED
data/lib/fluent/plugin.rb
CHANGED
@@ -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
|
-
|
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
|
|
@@ -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(
|
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] :
|
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
|
-
|
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 ||
|
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] =
|
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] =
|
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
|
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
|
445
|
-
|
446
|
-
|
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
|
-
|
477
|
+
@pos
|
453
478
|
end
|
479
|
+
|
454
480
|
def read_inode
|
455
|
-
|
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 =
|
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 :
|
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
|
-
|
76
|
-
|
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
|
-
|
133
|
-
|
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
|
-
|
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.
|
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.
|
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.
|
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,
|
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 #{
|
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
|
-
|
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
|
data/lib/fluent/supervisor.rb
CHANGED
@@ -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
|
data/lib/fluent/test/base.rb
CHANGED
data/lib/fluent/version.rb
CHANGED
data/test/mixin.rb
CHANGED
@@ -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("
|
55
|
+
}.configure("type #{register_output_name}" + conf)
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
@@ -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
|
+
|
data/test/plugin/out_forward.rb
CHANGED
@@ -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.
|
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.
|
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-
|
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
|