fluentd 1.7.4-x64-mingw32 → 1.8.0-x64-mingw32
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/.github/ISSUE_TEMPLATE/bug_report.md +0 -1
- data/.travis.yml +4 -0
- data/CHANGELOG.md +70 -0
- data/MAINTAINERS.md +1 -0
- data/example/out_forward_sd.conf +17 -0
- data/example/sd.yaml +8 -0
- data/fluentd.gemspec +1 -1
- data/lib/fluent/agent.rb +3 -1
- data/lib/fluent/command/cat.rb +1 -2
- data/lib/fluent/command/fluentd.rb +16 -8
- data/lib/fluent/compat/call_super_mixin.rb +9 -0
- data/lib/fluent/compat/exec_util.rb +1 -1
- data/lib/fluent/config/configure_proxy.rb +4 -4
- data/lib/fluent/config/element.rb +28 -15
- data/lib/fluent/config/error.rb +6 -0
- data/lib/fluent/config/literal_parser.rb +24 -2
- data/lib/fluent/config/section.rb +43 -6
- data/lib/fluent/config/types.rb +98 -26
- data/lib/fluent/configurable.rb +2 -2
- data/lib/fluent/counter/base_socket.rb +2 -4
- data/lib/fluent/engine.rb +41 -122
- data/lib/fluent/event.rb +5 -7
- data/lib/fluent/fluent_log_event_router.rb +141 -0
- data/lib/fluent/msgpack_factory.rb +19 -2
- data/lib/fluent/plugin.rb +10 -1
- data/lib/fluent/plugin/base.rb +2 -2
- data/lib/fluent/plugin/buf_file.rb +11 -7
- data/lib/fluent/plugin/buf_file_single.rb +8 -5
- data/lib/fluent/plugin/buffer/chunk.rb +1 -1
- data/lib/fluent/plugin/buffer/file_chunk.rb +4 -6
- data/lib/fluent/plugin/buffer/file_single_chunk.rb +3 -5
- data/lib/fluent/plugin/formatter_csv.rb +23 -1
- data/lib/fluent/plugin/formatter_stdout.rb +1 -1
- data/lib/fluent/plugin/in_forward.rb +1 -1
- data/lib/fluent/plugin/in_monitor_agent.rb +4 -2
- data/lib/fluent/plugin/in_tail.rb +6 -0
- data/lib/fluent/plugin/in_unix.rb +1 -1
- data/lib/fluent/plugin/out_forward.rb +77 -28
- data/lib/fluent/plugin/out_forward/ack_handler.rb +1 -1
- data/lib/fluent/plugin/out_forward/load_balancer.rb +5 -2
- data/lib/fluent/plugin/out_stream.rb +1 -1
- data/lib/fluent/plugin/output.rb +11 -3
- data/lib/fluent/plugin/parser.rb +1 -0
- data/lib/fluent/plugin/sd_file.rb +155 -0
- data/lib/fluent/plugin/sd_static.rb +58 -0
- data/lib/fluent/plugin/service_discovery.rb +80 -0
- data/lib/fluent/plugin_helper.rb +1 -0
- data/lib/fluent/plugin_helper/child_process.rb +3 -3
- data/lib/fluent/plugin_helper/compat_parameters.rb +11 -1
- data/lib/fluent/plugin_helper/extract.rb +1 -1
- data/lib/fluent/plugin_helper/inject.rb +1 -1
- data/lib/fluent/plugin_helper/record_accessor.rb +10 -19
- data/lib/fluent/plugin_helper/server.rb +8 -4
- data/lib/fluent/plugin_helper/service_discovery.rb +80 -0
- data/lib/fluent/plugin_helper/service_discovery/manager.rb +132 -0
- data/lib/fluent/plugin_helper/service_discovery/round_robin_balancer.rb +43 -0
- data/lib/fluent/plugin_id.rb +7 -0
- data/lib/fluent/root_agent.rb +7 -9
- data/lib/fluent/supervisor.rb +192 -211
- data/lib/fluent/system_config.rb +26 -52
- data/lib/fluent/test/driver/base_owned.rb +15 -2
- data/lib/fluent/time.rb +8 -6
- data/lib/fluent/version.rb +1 -1
- data/test/command/test_fluentd.rb +12 -7
- data/test/config/test_configurable.rb +154 -0
- data/test/config/test_element.rb +18 -0
- data/test/config/test_literal_parser.rb +4 -0
- data/test/config/test_system_config.rb +48 -91
- data/test/config/test_types.rb +293 -120
- data/test/counter/test_client.rb +8 -4
- data/test/plugin/data/sd_file/config +11 -0
- data/test/plugin/data/sd_file/config.json +17 -0
- data/test/plugin/data/sd_file/config.yaml +11 -0
- data/test/plugin/data/sd_file/config.yml +11 -0
- data/test/plugin/data/sd_file/invalid_config.yml +7 -0
- data/test/plugin/out_forward/test_handshake_protocol.rb +2 -2
- data/test/plugin/out_forward/test_load_balancer.rb +1 -1
- data/test/plugin/out_forward/test_socket_cache.rb +2 -2
- data/test/plugin/test_buf_file.rb +40 -0
- data/test/plugin/test_buf_file_single.rb +32 -0
- data/test/plugin/test_buffer_file_chunk.rb +0 -11
- data/test/plugin/test_buffer_file_single_chunk.rb +0 -10
- data/test/plugin/test_formatter_csv.rb +9 -0
- data/test/plugin/test_in_forward.rb +9 -9
- data/test/plugin/test_in_monitor_agent.rb +37 -10
- data/test/plugin/test_in_unix.rb +5 -5
- data/test/plugin/test_out_forward.rb +45 -1
- data/test/plugin/test_out_stdout.rb +36 -1
- data/test/plugin/test_out_stream.rb +3 -3
- data/test/plugin/test_output.rb +25 -1
- data/test/plugin/test_sd_file.rb +211 -0
- data/test/plugin_helper/service_discovery/test_manager.rb +93 -0
- data/test/plugin_helper/service_discovery/test_round_robin_balancer.rb +21 -0
- data/test/plugin_helper/test_server.rb +13 -0
- data/test/plugin_helper/test_service_discovery.rb +72 -0
- data/test/test_event.rb +15 -15
- data/test/test_fluent_log_event_router.rb +99 -0
- data/test/test_logger_initializer.rb +26 -0
- data/test/test_supervisor.rb +30 -59
- metadata +43 -6
@@ -28,7 +28,7 @@ module Fluent
|
|
28
28
|
def configure(conf)
|
29
29
|
super
|
30
30
|
|
31
|
-
@time_formatter = Strftime.new(TIME_FORMAT)
|
31
|
+
@time_formatter = Strftime.new(@time_format || TIME_FORMAT)
|
32
32
|
@sub_formatter = Plugin.new_formatter(@output_type, parent: self.owner)
|
33
33
|
@sub_formatter.configure(conf)
|
34
34
|
end
|
@@ -256,7 +256,7 @@ module Fluent::Plugin
|
|
256
256
|
serializer = :to_json.to_proc
|
257
257
|
feeder = ->(d){ parser << d }
|
258
258
|
else # msgpack
|
259
|
-
parser = Fluent::
|
259
|
+
parser = Fluent::MessagePackFactory.msgpack_unpacker
|
260
260
|
serializer = :to_msgpack.to_proc
|
261
261
|
feeder = ->(d){
|
262
262
|
parser.feed_each(d){|obj|
|
@@ -64,7 +64,8 @@ module Fluent::Plugin
|
|
64
64
|
def config_ltsv(_req)
|
65
65
|
obj = {
|
66
66
|
'pid' => Process.pid,
|
67
|
-
'ppid' => Process.ppid
|
67
|
+
'ppid' => Process.ppid,
|
68
|
+
'version' => Fluent::VERSION,
|
68
69
|
}.merge(@agent.fluentd_opts)
|
69
70
|
|
70
71
|
render_ltsv([obj])
|
@@ -73,7 +74,8 @@ module Fluent::Plugin
|
|
73
74
|
def config_json(req)
|
74
75
|
obj = {
|
75
76
|
'pid' => Process.pid,
|
76
|
-
'ppid' => Process.ppid
|
77
|
+
'ppid' => Process.ppid,
|
78
|
+
'version' => Fluent::VERSION,
|
77
79
|
}.merge(@agent.fluentd_opts)
|
78
80
|
opts = build_option(req)
|
79
81
|
|
@@ -204,6 +204,12 @@ module Fluent::Plugin
|
|
204
204
|
timer_execute(:in_tail_refresh_watchers, @refresh_interval, &method(:refresh_watchers))
|
205
205
|
end
|
206
206
|
|
207
|
+
def stop
|
208
|
+
@@pos_file_paths.delete(@pos_file)
|
209
|
+
|
210
|
+
super
|
211
|
+
end
|
212
|
+
|
207
213
|
def shutdown
|
208
214
|
# during shutdown phase, don't close io. It should be done in close after all threads are stopped. See close.
|
209
215
|
stop_watchers(@tails.keys, immediate: true, remove_watcher: false)
|
@@ -18,6 +18,7 @@ require 'fluent/output'
|
|
18
18
|
require 'fluent/config/error'
|
19
19
|
require 'fluent/clock'
|
20
20
|
require 'base64'
|
21
|
+
require 'forwardable'
|
21
22
|
|
22
23
|
require 'fluent/compat/socket_util'
|
23
24
|
require 'fluent/plugin/out_forward/handshake_protocol'
|
@@ -32,7 +33,7 @@ module Fluent::Plugin
|
|
32
33
|
class ForwardOutput < Output
|
33
34
|
Fluent::Plugin.register_output('forward', self)
|
34
35
|
|
35
|
-
helpers :socket, :server, :timer, :thread, :compat_parameters
|
36
|
+
helpers :socket, :server, :timer, :thread, :compat_parameters, :service_discovery
|
36
37
|
|
37
38
|
LISTEN_PORT = 24224
|
38
39
|
|
@@ -224,23 +225,41 @@ module Fluent::Plugin
|
|
224
225
|
socket_cache: socket_cache,
|
225
226
|
)
|
226
227
|
|
227
|
-
|
228
|
-
failure = FailureDetector.new(@heartbeat_interval, @hard_timeout, Time.now.to_i.to_f)
|
229
|
-
name = server.name || "#{server.host}:#{server.port}"
|
228
|
+
configs = []
|
230
229
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
230
|
+
# rewrite for using server as sd_static
|
231
|
+
conf.elements(name: 'server').each do |s|
|
232
|
+
s.name = 'service'
|
233
|
+
end
|
234
|
+
|
235
|
+
unless conf.elements(name: 'service').empty?
|
236
|
+
# To copy `services` element only
|
237
|
+
new_elem = Fluent::Config::Element.new('static_service_discovery', {}, {}, conf.elements(name: 'service'))
|
238
|
+
configs << { type: :static, conf: new_elem }
|
239
|
+
end
|
240
|
+
|
241
|
+
conf.elements(name: 'service_discovery').each_with_index do |c, i|
|
242
|
+
configs << { type: @service_discovery[i][:@type], conf: c }
|
243
|
+
end
|
244
|
+
|
245
|
+
service_discovery_create_manager(
|
246
|
+
:out_forward_service_discovery_watcher,
|
247
|
+
configurations: configs,
|
248
|
+
load_balancer: LoadBalancer.new(log),
|
249
|
+
custom_build_method: method(:build_node),
|
250
|
+
)
|
251
|
+
|
252
|
+
discovery_manager.services.each do |server|
|
253
|
+
# it's only for test
|
254
|
+
@nodes << server
|
255
|
+
unless @heartbeat_type == :none
|
236
256
|
begin
|
237
|
-
|
257
|
+
server.validate_host_resolution!
|
238
258
|
rescue => e
|
239
259
|
raise unless @ignore_network_errors_at_startup
|
240
260
|
log.warn "failed to resolve node name when configured", server: (server.name || server.host), error: e
|
241
|
-
|
261
|
+
server.disable!
|
242
262
|
end
|
243
|
-
@nodes << node
|
244
263
|
end
|
245
264
|
end
|
246
265
|
|
@@ -252,8 +271,8 @@ module Fluent::Plugin
|
|
252
271
|
end
|
253
272
|
end
|
254
273
|
|
255
|
-
if
|
256
|
-
raise Fluent::ConfigError, "forward output plugin requires at least one <server>
|
274
|
+
if discovery_manager.services.empty?
|
275
|
+
raise Fluent::ConfigError, "forward output plugin requires at least one node is required. Add <server> or <service_discovery>"
|
257
276
|
end
|
258
277
|
|
259
278
|
if !@keepalive && @keepalive_timeout
|
@@ -274,12 +293,9 @@ module Fluent::Plugin
|
|
274
293
|
def start
|
275
294
|
super
|
276
295
|
|
277
|
-
@load_balancer = LoadBalancer.new(log)
|
278
|
-
@load_balancer.rebuild_weight_array(@nodes)
|
279
|
-
|
280
296
|
unless @heartbeat_type == :none
|
281
297
|
if @heartbeat_type == :udp
|
282
|
-
@usock = socket_create_udp(
|
298
|
+
@usock = socket_create_udp(discovery_manager.services.first.host, discovery_manager.services.first.port, nonblock: true)
|
283
299
|
server_create_udp(:out_forward_heartbeat_receiver, 0, socket: @usock, max_bytes: @read_length, &method(:on_udp_heatbeat_response_recv))
|
284
300
|
end
|
285
301
|
timer_execute(:out_forward_heartbeat_request, @heartbeat_interval, &method(:on_heartbeat_timer))
|
@@ -297,7 +313,7 @@ module Fluent::Plugin
|
|
297
313
|
end
|
298
314
|
|
299
315
|
if @verify_connection_at_startup
|
300
|
-
|
316
|
+
discovery_manager.services.each do |node|
|
301
317
|
begin
|
302
318
|
node.verify_connection
|
303
319
|
rescue StandardError => e
|
@@ -333,7 +349,7 @@ module Fluent::Plugin
|
|
333
349
|
return if chunk.empty?
|
334
350
|
tag = chunk.metadata.tag
|
335
351
|
|
336
|
-
|
352
|
+
discovery_manager.select_service { |node| node.send_data(tag, chunk) }
|
337
353
|
end
|
338
354
|
|
339
355
|
def try_write(chunk)
|
@@ -343,7 +359,7 @@ module Fluent::Plugin
|
|
343
359
|
return
|
344
360
|
end
|
345
361
|
tag = chunk.metadata.tag
|
346
|
-
|
362
|
+
discovery_manager.select_service { |node| node.send_data(tag, chunk) }
|
347
363
|
end
|
348
364
|
|
349
365
|
def create_transfer_socket(host, port, hostname, &block)
|
@@ -387,6 +403,23 @@ module Fluent::Plugin
|
|
387
403
|
end
|
388
404
|
end
|
389
405
|
|
406
|
+
def statistics
|
407
|
+
stats = super
|
408
|
+
services = discovery_manager.services
|
409
|
+
healthy_nodes_count = 0
|
410
|
+
registed_nodes_count = services.size
|
411
|
+
services.each do |s|
|
412
|
+
if s.available?
|
413
|
+
healthy_nodes_count += 1
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
stats.merge(
|
418
|
+
'healthy_nodes_count' => healthy_nodes_count,
|
419
|
+
'registered_nodes_count' => registed_nodes_count,
|
420
|
+
)
|
421
|
+
end
|
422
|
+
|
390
423
|
# MessagePack FixArray length is 3
|
391
424
|
FORWARD_HEADER = [0x93].pack('C').freeze
|
392
425
|
def forward_header
|
@@ -395,9 +428,21 @@ module Fluent::Plugin
|
|
395
428
|
|
396
429
|
private
|
397
430
|
|
431
|
+
def build_node(server)
|
432
|
+
name = server.name || "#{server.host}:#{server.port}"
|
433
|
+
log.info "adding forwarding server '#{name}'", host: server.host, port: server.port, weight: server.weight, plugin_id: plugin_id
|
434
|
+
|
435
|
+
failure = FailureDetector.new(@heartbeat_interval, @hard_timeout, Time.now.to_i.to_f)
|
436
|
+
if @heartbeat_type == :none
|
437
|
+
NoneHeartbeatNode.new(self, server, failure: failure, connection_manager: @connection_manager, ack_handler: @ack_handler)
|
438
|
+
else
|
439
|
+
Node.new(self, server, failure: failure, connection_manager: @connection_manager, ack_handler: @ack_handler)
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
398
443
|
def on_heartbeat_timer
|
399
444
|
need_rebuild = false
|
400
|
-
|
445
|
+
discovery_manager.services.each do |n|
|
401
446
|
begin
|
402
447
|
log.trace "sending heartbeat", host: n.host, port: n.port, heartbeat_type: @heartbeat_type
|
403
448
|
n.usock = @usock if @usock
|
@@ -412,19 +457,19 @@ module Fluent::Plugin
|
|
412
457
|
end
|
413
458
|
|
414
459
|
if need_rebuild
|
415
|
-
|
460
|
+
discovery_manager.rebalance
|
416
461
|
end
|
417
462
|
end
|
418
463
|
|
419
464
|
def on_udp_heatbeat_response_recv(data, sock)
|
420
465
|
sockaddr = Socket.pack_sockaddr_in(sock.remote_port, sock.remote_host)
|
421
|
-
if node =
|
466
|
+
if node = discovery_manager.services.find { |n| n.sockaddr == sockaddr }
|
422
467
|
# log.trace "heartbeat arrived", name: node.name, host: node.host, port: node.port
|
423
468
|
if node.heartbeat
|
424
|
-
|
469
|
+
discovery_manager.rebalance
|
425
470
|
end
|
426
471
|
else
|
427
|
-
log.warn("Unknown heartbeat response received from #{sock.remote_host}:#{sock.remote_port}")
|
472
|
+
log.warn("Unknown heartbeat response received from #{sock.remote_host}:#{sock.remote_port}. It may service out")
|
428
473
|
end
|
429
474
|
end
|
430
475
|
|
@@ -463,12 +508,16 @@ module Fluent::Plugin
|
|
463
508
|
end
|
464
509
|
|
465
510
|
class Node
|
511
|
+
extend Forwardable
|
512
|
+
def_delegators :@server, :discovery_id, :host, :port, :name, :weight, :standby, :username, :password, :shared_key
|
513
|
+
|
466
514
|
# @param connection_manager [Fluent::Plugin::ForwardOutput::ConnectionManager]
|
467
515
|
# @param ack_handler [Fluent::Plugin::ForwardOutput::AckHandler]
|
468
516
|
def initialize(sender, server, failure:, connection_manager:, ack_handler:)
|
469
517
|
@sender = sender
|
470
518
|
@log = sender.log
|
471
519
|
@compress = sender.compress
|
520
|
+
@server = server
|
472
521
|
|
473
522
|
@name = server.name
|
474
523
|
@host = server.host
|
@@ -496,7 +545,7 @@ module Fluent::Plugin
|
|
496
545
|
username: server.username,
|
497
546
|
)
|
498
547
|
|
499
|
-
@unpacker = Fluent::
|
548
|
+
@unpacker = Fluent::MessagePackFactory.msgpack_unpacker
|
500
549
|
|
501
550
|
@resolved_host = nil
|
502
551
|
@resolved_time = 0
|
@@ -508,7 +557,7 @@ module Fluent::Plugin
|
|
508
557
|
|
509
558
|
attr_accessor :usock
|
510
559
|
|
511
|
-
attr_reader :
|
560
|
+
attr_reader :state
|
512
561
|
attr_reader :sockaddr # used by on_udp_heatbeat_response_recv
|
513
562
|
attr_reader :failure # for test
|
514
563
|
|
@@ -36,8 +36,8 @@ module Fluent::Plugin
|
|
36
36
|
wlen = @weight_array.size
|
37
37
|
wlen.times do
|
38
38
|
node = @mutex.synchronize do
|
39
|
-
r = @rr
|
40
|
-
@rr = (
|
39
|
+
r = @rr % @weight_array.size
|
40
|
+
@rr = (r + 1) % @weight_array.size
|
41
41
|
@weight_array[r]
|
42
42
|
end
|
43
43
|
next unless node.available?
|
@@ -106,6 +106,9 @@ module Fluent::Plugin
|
|
106
106
|
@weight_array = weight_array
|
107
107
|
end
|
108
108
|
end
|
109
|
+
|
110
|
+
alias select_service select_healthy_node
|
111
|
+
alias rebalance rebuild_weight_array
|
109
112
|
end
|
110
113
|
end
|
111
114
|
end
|
@@ -68,7 +68,7 @@ module Fluent
|
|
68
68
|
chain = NullOutputChain.instance
|
69
69
|
chunk.open {|io|
|
70
70
|
# TODO use MessagePackIoEventStream
|
71
|
-
u = Fluent::
|
71
|
+
u = Fluent::MessagePackFactory.msgpack_unpacker(io)
|
72
72
|
begin
|
73
73
|
u.each {|(tag,entries)|
|
74
74
|
es = MultiEventStream.new
|
data/lib/fluent/plugin/output.rb
CHANGED
@@ -40,7 +40,7 @@ module Fluent
|
|
40
40
|
helpers_internal :thread, :retry_state
|
41
41
|
|
42
42
|
CHUNK_KEY_PATTERN = /^[-_.@a-zA-Z0-9]+$/
|
43
|
-
CHUNK_KEY_PLACEHOLDER_PATTERN = /\$\{[-_.@$a-zA-Z0-9]
|
43
|
+
CHUNK_KEY_PLACEHOLDER_PATTERN = /\$\{([-_.@$a-zA-Z0-9]+)\}/
|
44
44
|
CHUNK_TAG_PLACEHOLDER_PATTERN = /\$\{(tag(?:\[-?\d+\])?)\}/
|
45
45
|
CHUNK_ID_PLACEHOLDER_PATTERN = /\$\{chunk_id\}/
|
46
46
|
|
@@ -707,7 +707,7 @@ module Fluent
|
|
707
707
|
end
|
708
708
|
|
709
709
|
def get_placeholders_keys(str)
|
710
|
-
str.scan(CHUNK_KEY_PLACEHOLDER_PATTERN).map
|
710
|
+
str.scan(CHUNK_KEY_PLACEHOLDER_PATTERN).map(&:first).reject{|s| (s == "tag") || (s == 'chunk_id') }.sort
|
711
711
|
end
|
712
712
|
|
713
713
|
# TODO: optimize this code
|
@@ -759,11 +759,19 @@ module Fluent
|
|
759
759
|
@chunk_keys.each do |key|
|
760
760
|
hash["${#{key}}"] = metadata.variables[key.to_sym]
|
761
761
|
end
|
762
|
-
|
762
|
+
|
763
|
+
rvalue = rvalue.gsub(CHUNK_KEY_PLACEHOLDER_PATTERN) do |matched|
|
764
|
+
hash.fetch(matched) do
|
765
|
+
log.warn "chunk key placeholder '#{matched[2..-2]}' not replaced. template:#{str}"
|
766
|
+
''
|
767
|
+
end
|
768
|
+
end
|
763
769
|
end
|
770
|
+
|
764
771
|
if rvalue =~ CHUNK_KEY_PLACEHOLDER_PATTERN
|
765
772
|
log.warn "chunk key placeholder '#{$1}' not replaced. template:#{str}"
|
766
773
|
end
|
774
|
+
|
767
775
|
rvalue.sub(CHUNK_ID_PLACEHOLDER_PATTERN) {
|
768
776
|
if chunk_passed
|
769
777
|
dump_unique_id_hex(chunk.unique_id)
|
data/lib/fluent/plugin/parser.rb
CHANGED
@@ -0,0 +1,155 @@
|
|
1
|
+
#
|
2
|
+
# Fluentd
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require 'cool.io'
|
18
|
+
|
19
|
+
require 'fluent/plugin_helper'
|
20
|
+
require 'fluent/plugin/service_discovery'
|
21
|
+
|
22
|
+
module Fluent
|
23
|
+
module Plugin
|
24
|
+
class FileServiceDiscovery < ServiceDiscovery
|
25
|
+
include PluginHelper::Mixin
|
26
|
+
|
27
|
+
Plugin.register_sd('file', self)
|
28
|
+
|
29
|
+
DEFAULT_FILE_TYPE = :yaml
|
30
|
+
DEFAUT_WEIGHT = 60
|
31
|
+
DEFAULT_SD_FILE_PATH = ENV['DEFAULT_SD_FILE_PATH'] || '/etc/fluent/sd.yaml'
|
32
|
+
|
33
|
+
helpers :event_loop
|
34
|
+
|
35
|
+
config_param :path, :string, default: DEFAULT_SD_FILE_PATH
|
36
|
+
config_param :conf_encoding, :string, default: 'utf-8'
|
37
|
+
|
38
|
+
def initialize
|
39
|
+
super
|
40
|
+
|
41
|
+
@file_type = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def configure(conf)
|
45
|
+
super
|
46
|
+
|
47
|
+
unless File.exist?(@path)
|
48
|
+
raise Fluent::ConfigError, "sd_file: path=#{@path} not found"
|
49
|
+
end
|
50
|
+
|
51
|
+
@file_type = File.basename(@path).split('.', 2).last.to_sym
|
52
|
+
unless %i[yaml yml json].include?(@file_type)
|
53
|
+
@file_type = DEFAULT_FILE_TYPE
|
54
|
+
end
|
55
|
+
|
56
|
+
@services = fetch_server_info
|
57
|
+
end
|
58
|
+
|
59
|
+
def start(queue)
|
60
|
+
watcher = StatWatcher.new(@path, @log) do |_prev, _cur|
|
61
|
+
refresh_file(queue)
|
62
|
+
end
|
63
|
+
event_loop_attach(watcher)
|
64
|
+
|
65
|
+
super()
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def parser
|
71
|
+
@parser ||=
|
72
|
+
case @file_type
|
73
|
+
when :yaml, :yml
|
74
|
+
require 'yaml'
|
75
|
+
-> (v) { YAML.safe_load(v).map }
|
76
|
+
when :json
|
77
|
+
require 'json'
|
78
|
+
-> (v) { JSON.parse(v) }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def refresh_file(queue)
|
83
|
+
s =
|
84
|
+
begin
|
85
|
+
fetch_server_info
|
86
|
+
rescue => e
|
87
|
+
@log.error("sd_file: #{e}")
|
88
|
+
end
|
89
|
+
|
90
|
+
if s.nil?
|
91
|
+
# if any error occurs, skip this turn
|
92
|
+
return
|
93
|
+
end
|
94
|
+
|
95
|
+
diff = []
|
96
|
+
join = s - @services
|
97
|
+
# Need service_in first to guarantee that server exist at least one all time.
|
98
|
+
join.each do |j|
|
99
|
+
diff << ServiceDiscovery.service_in_msg(j)
|
100
|
+
end
|
101
|
+
|
102
|
+
drain = @services - s
|
103
|
+
drain.each do |d|
|
104
|
+
diff << ServiceDiscovery.service_out_msg(d)
|
105
|
+
end
|
106
|
+
|
107
|
+
@services = s
|
108
|
+
|
109
|
+
diff.each do |a|
|
110
|
+
queue.push(a)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def fetch_server_info
|
115
|
+
config_data =
|
116
|
+
begin
|
117
|
+
File.open(@path, "r:#{@conf_encoding}:utf-8", &:read)
|
118
|
+
rescue => e
|
119
|
+
raise Fluent::ConfigError, "sd_file: path=#{@path} couldn't open #{e}"
|
120
|
+
end
|
121
|
+
|
122
|
+
parser.call(config_data).map do |s|
|
123
|
+
Service.new(
|
124
|
+
:file,
|
125
|
+
s.fetch('host'),
|
126
|
+
s.fetch('port'),
|
127
|
+
s['name'],
|
128
|
+
s.fetch('weight', DEFAUT_WEIGHT),
|
129
|
+
s['standby'],
|
130
|
+
s['username'],
|
131
|
+
s['password'],
|
132
|
+
s['shared_key'],
|
133
|
+
)
|
134
|
+
end
|
135
|
+
rescue KeyError => e
|
136
|
+
raise Fluent::ConfigError, "#{e}. Service must have `host` and `port`"
|
137
|
+
end
|
138
|
+
|
139
|
+
class StatWatcher < Coolio::StatWatcher
|
140
|
+
def initialize(path, log, &callback)
|
141
|
+
@path = path
|
142
|
+
@log = log
|
143
|
+
@callback = callback
|
144
|
+
super(@path)
|
145
|
+
end
|
146
|
+
|
147
|
+
def on_change(prev_stat, cur_stat)
|
148
|
+
@callback.call(prev_stat, cur_stat)
|
149
|
+
rescue => e
|
150
|
+
@log.error(e)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|