fluentd 1.10.1-x86-mingw32 → 1.11.1-x86-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/CHANGELOG.md +112 -1
- data/CONTRIBUTING.md +1 -1
- data/lib/fluent/command/debug.rb +1 -0
- data/lib/fluent/command/fluentd.rb +12 -1
- data/lib/fluent/config.rb +1 -0
- data/lib/fluent/log.rb +45 -6
- data/lib/fluent/match.rb +1 -1
- data/lib/fluent/plugin/in_dummy.rb +2 -2
- data/lib/fluent/plugin/in_forward.rb +2 -2
- data/lib/fluent/plugin/in_gc_stat.rb +16 -0
- data/lib/fluent/plugin/in_http.rb +146 -75
- data/lib/fluent/plugin/in_monitor_agent.rb +1 -1
- data/lib/fluent/plugin/in_syslog.rb +4 -4
- data/lib/fluent/plugin/in_tail.rb +4 -4
- data/lib/fluent/plugin/in_unix.rb +77 -77
- data/lib/fluent/plugin/out_copy.rb +1 -1
- data/lib/fluent/plugin/out_file.rb +1 -1
- data/lib/fluent/plugin/out_forward.rb +23 -18
- data/lib/fluent/plugin/out_forward/load_balancer.rb +1 -1
- data/lib/fluent/plugin/out_http.rb +15 -2
- data/lib/fluent/plugin/parser_multiline.rb +1 -1
- data/lib/fluent/plugin/parser_syslog.rb +215 -54
- data/lib/fluent/plugin_helper/child_process.rb +3 -2
- data/lib/fluent/plugin_helper/record_accessor.rb +14 -0
- data/lib/fluent/plugin_helper/service_discovery.rb +7 -0
- data/lib/fluent/plugin_helper/service_discovery/manager.rb +8 -0
- data/lib/fluent/plugin_helper/socket.rb +20 -2
- data/lib/fluent/plugin_helper/socket_option.rb +2 -2
- data/lib/fluent/supervisor.rb +21 -9
- data/lib/fluent/system_config.rb +2 -1
- data/lib/fluent/test/filter_test.rb +2 -2
- data/lib/fluent/test/output_test.rb +3 -3
- data/lib/fluent/version.rb +1 -1
- data/test/command/test_fluentd.rb +57 -10
- data/test/config/test_system_config.rb +2 -0
- data/test/plugin/out_forward/test_load_balancer.rb +46 -0
- data/test/plugin/test_in_gc_stat.rb +24 -1
- data/test/plugin/test_in_http.rb +57 -0
- data/test/plugin/test_in_syslog.rb +1 -1
- data/test/plugin/test_in_tail.rb +20 -16
- data/test/plugin/test_in_unix.rb +128 -73
- data/test/plugin/test_out_forward.rb +11 -2
- data/test/plugin/test_out_http.rb +38 -0
- data/test/plugin/test_out_null.rb +1 -1
- data/test/plugin/test_output_as_buffered_retries.rb +12 -4
- data/test/plugin/test_parser_syslog.rb +66 -29
- data/test/plugin_helper/data/cert/cert_chains/ca-cert-key.pem +27 -0
- data/test/plugin_helper/data/cert/cert_chains/ca-cert.pem +20 -0
- data/test/plugin_helper/data/cert/cert_chains/cert-key.pem +27 -0
- data/test/plugin_helper/data/cert/cert_chains/cert.pem +40 -0
- data/test/plugin_helper/data/cert/generate_cert.rb +38 -0
- data/test/plugin_helper/http_server/test_app.rb +1 -1
- data/test/plugin_helper/http_server/test_route.rb +1 -1
- data/test/plugin_helper/test_child_process.rb +15 -0
- data/test/plugin_helper/test_http_server_helper.rb +2 -2
- data/test/plugin_helper/test_record_accessor.rb +41 -0
- data/test/plugin_helper/test_server.rb +1 -1
- data/test/plugin_helper/test_service_discovery.rb +37 -4
- data/test/plugin_helper/test_socket.rb +131 -0
- data/test/test_log.rb +44 -0
- metadata +12 -2
@@ -223,7 +223,7 @@ module Fluent::Plugin
|
|
223
223
|
opts = {with_config: false, with_retry: false}
|
224
224
|
timer_execute(:in_monitor_agent_emit, @emit_interval, repeat: true) {
|
225
225
|
es = Fluent::MultiEventStream.new
|
226
|
-
now = Fluent::
|
226
|
+
now = Fluent::EventTime.now
|
227
227
|
plugins_info_all(opts).each { |record|
|
228
228
|
es.add(now, record)
|
229
229
|
}
|
@@ -181,12 +181,12 @@ module Fluent::Plugin
|
|
181
181
|
if octet_count_frame
|
182
182
|
while idx = buffer.index(delimiter, pos)
|
183
183
|
num = Integer(buffer[pos..idx])
|
184
|
-
|
185
|
-
msg
|
186
|
-
if msg.size < num - 1
|
187
|
-
pos = pos - num - num.to_s.size
|
184
|
+
msg = buffer[idx + delimiter_size, num]
|
185
|
+
if msg.size != num
|
188
186
|
break
|
189
187
|
end
|
188
|
+
|
189
|
+
pos = idx + delimiter_size + num
|
190
190
|
message_handler(msg, conn)
|
191
191
|
end
|
192
192
|
else
|
@@ -136,7 +136,7 @@ module Fluent::Plugin
|
|
136
136
|
raise Fluent::ConfigError, "#{rc} are reserved words: #{@path_delimiter}"
|
137
137
|
end
|
138
138
|
|
139
|
-
@paths = @path.split(@path_delimiter).map(&:strip)
|
139
|
+
@paths = @path.split(@path_delimiter).map(&:strip).uniq
|
140
140
|
if @paths.empty?
|
141
141
|
raise Fluent::ConfigError, "tail: 'path' parameter is required on tail input"
|
142
142
|
end
|
@@ -271,9 +271,9 @@ module Fluent::Plugin
|
|
271
271
|
end
|
272
272
|
else
|
273
273
|
if is_file
|
274
|
-
unless @ignore_list.include?(
|
274
|
+
unless @ignore_list.include?(p)
|
275
275
|
log.warn "#{p} unreadable. It is excluded and would be examined next time."
|
276
|
-
@ignore_list <<
|
276
|
+
@ignore_list << p if @ignore_repeated_permission_error
|
277
277
|
end
|
278
278
|
end
|
279
279
|
false
|
@@ -296,7 +296,7 @@ module Fluent::Plugin
|
|
296
296
|
end
|
297
297
|
path.include?('*') ? Dir.glob(path) : path
|
298
298
|
}.flatten.uniq
|
299
|
-
paths - excluded
|
299
|
+
paths.uniq - excluded
|
300
300
|
end
|
301
301
|
|
302
302
|
# in_tail with '*' path doesn't check rotation file equality at refresh phase.
|
@@ -14,50 +14,68 @@
|
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
16
|
|
17
|
-
require '
|
18
|
-
require '
|
17
|
+
require 'fluent/env'
|
18
|
+
require 'fluent/plugin/input'
|
19
|
+
require 'fluent/msgpack_factory'
|
19
20
|
|
20
21
|
require 'cool.io'
|
21
22
|
require 'yajl'
|
23
|
+
require 'fileutils'
|
24
|
+
require 'socket'
|
25
|
+
|
26
|
+
module Fluent::Plugin
|
27
|
+
# TODO: This plugin will be 3rd party plugin
|
28
|
+
class UnixInput < Input
|
29
|
+
Fluent::Plugin.register_input('unix', self)
|
30
|
+
|
31
|
+
helpers :event_loop
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
super
|
22
35
|
|
23
|
-
|
24
|
-
|
36
|
+
@lsock = nil
|
37
|
+
end
|
25
38
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
config_param :
|
39
|
+
desc 'The path to your Unix Domain Socket.'
|
40
|
+
config_param :path, :string, default: Fluent::DEFAULT_SOCKET_PATH
|
41
|
+
desc 'The backlog of Unix Domain Socket.'
|
42
|
+
config_param :backlog, :integer, default: nil
|
43
|
+
desc "New tag instead of incoming tag"
|
44
|
+
config_param :tag, :string, default: nil
|
45
|
+
|
46
|
+
def configure(conf)
|
47
|
+
super
|
48
|
+
end
|
30
49
|
|
31
50
|
def start
|
32
51
|
super
|
33
52
|
|
34
|
-
@loop = Coolio::Loop.new
|
35
53
|
@lsock = listen
|
36
|
-
|
37
|
-
@thread = Thread.new(&method(:run))
|
54
|
+
event_loop_attach(@lsock)
|
38
55
|
end
|
39
56
|
|
40
57
|
def shutdown
|
41
|
-
@
|
42
|
-
|
43
|
-
|
44
|
-
|
58
|
+
if @lsock
|
59
|
+
event_loop_detach(@lsock)
|
60
|
+
@lsock.close
|
61
|
+
end
|
45
62
|
|
46
63
|
super
|
47
64
|
end
|
48
65
|
|
49
|
-
|
50
|
-
|
66
|
+
def listen
|
67
|
+
if File.exist?(@path)
|
68
|
+
log.warn "Found existing '#{@path}'. Remove this file for in_unix plugin"
|
69
|
+
File.unlink(@path)
|
70
|
+
end
|
71
|
+
FileUtils.mkdir_p(File.dirname(@path))
|
51
72
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
log.error_backtrace
|
73
|
+
log.info "listening fluent socket on #{@path}"
|
74
|
+
s = Coolio::UNIXServer.new(@path, Handler, log, method(:on_message))
|
75
|
+
s.listen(@backlog) unless @backlog.nil?
|
76
|
+
s
|
57
77
|
end
|
58
78
|
|
59
|
-
private
|
60
|
-
|
61
79
|
# message Entry {
|
62
80
|
# 1: long time
|
63
81
|
# 2: object record
|
@@ -79,23 +97,27 @@ module Fluent
|
|
79
97
|
# 3: object record
|
80
98
|
# }
|
81
99
|
def on_message(msg)
|
82
|
-
|
83
|
-
|
100
|
+
unless msg.is_a?(Array)
|
101
|
+
log.warn "incoming data is broken:", msg: msg
|
102
|
+
return
|
103
|
+
end
|
104
|
+
|
105
|
+
tag = @tag || (msg[0].to_s)
|
84
106
|
entries = msg[1]
|
85
107
|
|
86
|
-
|
108
|
+
case entries
|
109
|
+
when String
|
87
110
|
# PackedForward
|
88
|
-
es = MessagePackEventStream.new(entries)
|
111
|
+
es = Fluent::MessagePackEventStream.new(entries)
|
89
112
|
router.emit_stream(tag, es)
|
90
113
|
|
91
|
-
|
114
|
+
when Array
|
92
115
|
# Forward
|
93
|
-
es = MultiEventStream.new
|
116
|
+
es = Fluent::MultiEventStream.new
|
94
117
|
entries.each {|e|
|
95
118
|
record = e[1]
|
96
119
|
next if record.nil?
|
97
|
-
time = e[0]
|
98
|
-
time = (now ||= Engine.now) if time.to_i == 0
|
120
|
+
time = convert_time(e[0])
|
99
121
|
es.add(time, record)
|
100
122
|
}
|
101
123
|
router.emit_stream(tag, es)
|
@@ -105,25 +127,28 @@ module Fluent
|
|
105
127
|
record = msg[2]
|
106
128
|
return if record.nil?
|
107
129
|
|
108
|
-
time = msg[1]
|
109
|
-
time = Engine.now if time.to_i == 0
|
130
|
+
time = convert_time(msg[1])
|
110
131
|
router.emit(tag, time, record)
|
111
132
|
end
|
112
133
|
end
|
113
134
|
|
135
|
+
def convert_time(time)
|
136
|
+
case time
|
137
|
+
when nil, 0
|
138
|
+
Fluent::EventTime.now
|
139
|
+
when Fluent::EventTime
|
140
|
+
time
|
141
|
+
else
|
142
|
+
Fluent::EventTime.from_time(Time.at(time))
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
114
146
|
class Handler < Coolio::Socket
|
115
147
|
def initialize(io, log, on_message)
|
116
148
|
super(io)
|
117
|
-
|
118
|
-
opt = [1, @timeout.to_i].pack('I!I!') # { int l_onoff; int l_linger; }
|
119
|
-
io.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, opt)
|
120
|
-
end
|
149
|
+
|
121
150
|
@on_message = on_message
|
122
151
|
@log = log
|
123
|
-
@log.trace {
|
124
|
-
remote_port, remote_addr = *Socket.unpack_sockaddr_in(@_io.getpeername) rescue nil
|
125
|
-
"accepted fluent socket from '#{remote_addr}:#{remote_port}': object_id=#{self.object_id}"
|
126
|
-
}
|
127
152
|
end
|
128
153
|
|
129
154
|
def on_connect
|
@@ -131,13 +156,13 @@ module Fluent
|
|
131
156
|
|
132
157
|
def on_read(data)
|
133
158
|
first = data[0]
|
134
|
-
if first == '{' || first == '['
|
159
|
+
if first == '{'.freeze || first == '['.freeze
|
135
160
|
m = method(:on_read_json)
|
136
|
-
@
|
137
|
-
@
|
161
|
+
@parser = Yajl::Parser.new
|
162
|
+
@parser.on_parse_complete = @on_message
|
138
163
|
else
|
139
164
|
m = method(:on_read_msgpack)
|
140
|
-
@
|
165
|
+
@parser = Fluent::MessagePackFactory.msgpack_unpacker
|
141
166
|
end
|
142
167
|
|
143
168
|
singleton_class.module_eval do
|
@@ -147,17 +172,17 @@ module Fluent
|
|
147
172
|
end
|
148
173
|
|
149
174
|
def on_read_json(data)
|
150
|
-
@
|
151
|
-
rescue
|
152
|
-
@log.error "unexpected error", error:
|
175
|
+
@parser << data
|
176
|
+
rescue => e
|
177
|
+
@log.error "unexpected error in json payload", error: e.to_s
|
153
178
|
@log.error_backtrace
|
154
179
|
close
|
155
180
|
end
|
156
181
|
|
157
182
|
def on_read_msgpack(data)
|
158
|
-
@
|
159
|
-
rescue
|
160
|
-
@log.error "unexpected error", error:
|
183
|
+
@parser.feed_each(data, &@on_message)
|
184
|
+
rescue => e
|
185
|
+
@log.error "unexpected error in msgpack payload", error: e.to_s
|
161
186
|
@log.error_backtrace
|
162
187
|
close
|
163
188
|
end
|
@@ -167,29 +192,4 @@ module Fluent
|
|
167
192
|
end
|
168
193
|
end
|
169
194
|
end
|
170
|
-
|
171
|
-
class UnixInput < StreamInput
|
172
|
-
Plugin.register_input('unix', self)
|
173
|
-
|
174
|
-
desc 'The path to your Unix Domain Socket.'
|
175
|
-
config_param :path, :string, default: DEFAULT_SOCKET_PATH
|
176
|
-
desc 'The backlog of Unix Domain Socket.'
|
177
|
-
config_param :backlog, :integer, default: nil
|
178
|
-
|
179
|
-
def configure(conf)
|
180
|
-
super
|
181
|
-
#log.warn "'unix' input is obsoleted and will be removed. Use 'forward' instead."
|
182
|
-
end
|
183
|
-
|
184
|
-
def listen
|
185
|
-
if File.exist?(@path)
|
186
|
-
File.unlink(@path)
|
187
|
-
end
|
188
|
-
FileUtils.mkdir_p File.dirname(@path)
|
189
|
-
log.info "listening fluent socket on #{@path}"
|
190
|
-
s = Coolio::UNIXServer.new(@path, Handler, log, method(:on_message))
|
191
|
-
s.listen(@backlog) unless @backlog.nil?
|
192
|
-
s
|
193
|
-
end
|
194
|
-
end
|
195
195
|
end
|
@@ -61,7 +61,7 @@ module Fluent::Plugin
|
|
61
61
|
output.emit_events(tag, @copy_proc ? @copy_proc.call(es) : es)
|
62
62
|
rescue => e
|
63
63
|
if @ignore_errors[i]
|
64
|
-
log.error "ignore emit error", error: e
|
64
|
+
log.error "ignore emit error in #{output.plugin_id}", error: e
|
65
65
|
else
|
66
66
|
raise e
|
67
67
|
end
|
@@ -155,7 +155,7 @@ module Fluent::Plugin
|
|
155
155
|
dummy_record_keys = get_placeholders_keys(@path_template) || ['message']
|
156
156
|
dummy_record = Hash[dummy_record_keys.zip(['data'] * dummy_record_keys.size)]
|
157
157
|
|
158
|
-
test_chunk1 = chunk_for_test(dummy_tag, Fluent::
|
158
|
+
test_chunk1 = chunk_for_test(dummy_tag, Fluent::EventTime.now, dummy_record)
|
159
159
|
test_path = extract_placeholders(@path_template, test_chunk1)
|
160
160
|
unless ::Fluent::FileUtil.writable_p?(test_path)
|
161
161
|
raise Fluent::ConfigError, "out_file: `#{test_path}` is not writable"
|
@@ -324,7 +324,7 @@ module Fluent::Plugin
|
|
324
324
|
end
|
325
325
|
end
|
326
326
|
|
327
|
-
if @keepalive
|
327
|
+
if @keepalive
|
328
328
|
timer_execute(:out_forward_keep_alived_socket_watcher, @keep_alive_watcher_interval, &method(:on_purge_obsolete_socks))
|
329
329
|
end
|
330
330
|
end
|
@@ -382,7 +382,12 @@ module Fluent::Plugin
|
|
382
382
|
cert_logical_store_name: @tls_cert_logical_store_name,
|
383
383
|
cert_use_enterprise_store: @tls_cert_use_enterprise_store,
|
384
384
|
|
385
|
-
|
385
|
+
# Enabling SO_LINGER causes tcp port exhaustion on Windows.
|
386
|
+
# This is because dynamic ports are only 16384 (from 49152 to 65535) and
|
387
|
+
# expiring SO_LINGER enabled ports should wait 4 minutes
|
388
|
+
# where set by TcpTimeDelay. Its default value is 4 minutes.
|
389
|
+
# So, we should disable SO_LINGER on Windows to prevent flood of waiting ports.
|
390
|
+
linger_timeout: Fluent.windows? ? nil : @send_timeout,
|
386
391
|
send_timeout: @send_timeout,
|
387
392
|
recv_timeout: @ack_response_timeout,
|
388
393
|
connect_timeout: @connect_timeout,
|
@@ -578,12 +583,7 @@ module Fluent::Plugin
|
|
578
583
|
|
579
584
|
def verify_connection
|
580
585
|
connect do |sock, ri|
|
581
|
-
|
582
|
-
establish_connection(sock, ri)
|
583
|
-
if ri.state != :established
|
584
|
-
raise "Failed to establish connection to #{@host}:#{@port}"
|
585
|
-
end
|
586
|
-
end
|
586
|
+
ensure_established_connection(sock, ri)
|
587
587
|
end
|
588
588
|
end
|
589
589
|
|
@@ -652,14 +652,7 @@ module Fluent::Plugin
|
|
652
652
|
def send_data(tag, chunk)
|
653
653
|
ack = @ack_handler && @ack_handler.create_ack(chunk.unique_id, self)
|
654
654
|
connect(nil, ack: ack) do |sock, ri|
|
655
|
-
|
656
|
-
establish_connection(sock, ri)
|
657
|
-
|
658
|
-
if ri.state != :established
|
659
|
-
raise ConnectionClosedError, "failed to establish connection with node #{@name}"
|
660
|
-
end
|
661
|
-
end
|
662
|
-
|
655
|
+
ensure_established_connection(sock, ri)
|
663
656
|
send_data_actual(sock, tag, chunk)
|
664
657
|
end
|
665
658
|
|
@@ -684,7 +677,9 @@ module Fluent::Plugin
|
|
684
677
|
|
685
678
|
case @sender.heartbeat_type
|
686
679
|
when :transport
|
687
|
-
connect(dest_addr) do |
|
680
|
+
connect(dest_addr) do |sock, ri|
|
681
|
+
ensure_established_connection(sock, ri)
|
682
|
+
|
688
683
|
## don't send any data to not cause a compatibility problem
|
689
684
|
# sock.write FORWARD_TCP_HEARTBEAT_DATA
|
690
685
|
|
@@ -714,7 +709,7 @@ module Fluent::Plugin
|
|
714
709
|
@resolved_host ||= resolve_dns!
|
715
710
|
|
716
711
|
else
|
717
|
-
now = Fluent::
|
712
|
+
now = Fluent::EventTime.now
|
718
713
|
rh = @resolved_host
|
719
714
|
if !rh || now - @resolved_time >= @sender.expire_dns_cache
|
720
715
|
rh = @resolved_host = resolve_dns!
|
@@ -776,6 +771,16 @@ module Fluent::Plugin
|
|
776
771
|
|
777
772
|
private
|
778
773
|
|
774
|
+
def ensure_established_connection(sock, request_info)
|
775
|
+
if request_info.state != :established
|
776
|
+
establish_connection(sock, request_info)
|
777
|
+
|
778
|
+
if request_info.state != :established
|
779
|
+
raise ConnectionClosedError, "failed to establish connection with node #{@name}"
|
780
|
+
end
|
781
|
+
end
|
782
|
+
end
|
783
|
+
|
779
784
|
def connect(host = nil, ack: false, &block)
|
780
785
|
@connection_manager.connect(host: host || resolved_host, port: port, hostname: @hostname, ack: ack, &block)
|
781
786
|
end
|
@@ -37,6 +37,8 @@ module Fluent::Plugin
|
|
37
37
|
config_param :proxy, :string, default: ENV['HTTP_PROXY'] || ENV['http_proxy']
|
38
38
|
desc 'Content-Type for HTTP request'
|
39
39
|
config_param :content_type, :string, default: nil
|
40
|
+
desc 'JSON array data format for HTTP request body'
|
41
|
+
config_param :json_array, :bool, default: false
|
40
42
|
desc 'Additional headers for HTTP request'
|
41
43
|
config_param :headers, :hash, default: nil
|
42
44
|
|
@@ -100,6 +102,13 @@ module Fluent::Plugin
|
|
100
102
|
@proxy_uri = URI.parse(@proxy) if @proxy
|
101
103
|
@formatter = formatter_create
|
102
104
|
@content_type = setup_content_type unless @content_type
|
105
|
+
|
106
|
+
if @json_array
|
107
|
+
if @formatter_configs.first[:@type] != "json"
|
108
|
+
raise Fluent::ConfigError, "json_array option could be used with json formatter only"
|
109
|
+
end
|
110
|
+
define_singleton_method(:format, method(:format_json_array))
|
111
|
+
end
|
103
112
|
end
|
104
113
|
|
105
114
|
def multi_workers_ready?
|
@@ -114,6 +123,10 @@ module Fluent::Plugin
|
|
114
123
|
@formatter.format(tag, time, record)
|
115
124
|
end
|
116
125
|
|
126
|
+
def format_json_array(tag, time, record)
|
127
|
+
@formatter.format(tag, time, record) << ","
|
128
|
+
end
|
129
|
+
|
117
130
|
def write(chunk)
|
118
131
|
uri = parse_endpoint(chunk)
|
119
132
|
req = create_request(chunk, uri)
|
@@ -128,7 +141,7 @@ module Fluent::Plugin
|
|
128
141
|
def setup_content_type
|
129
142
|
case @formatter_configs.first[:@type]
|
130
143
|
when 'json'
|
131
|
-
'application/x-ndjson'
|
144
|
+
@json_array ? 'application/json' : 'application/x-ndjson'
|
132
145
|
when 'csv'
|
133
146
|
'text/csv'
|
134
147
|
when 'tsv', 'ltsv'
|
@@ -202,7 +215,7 @@ module Fluent::Plugin
|
|
202
215
|
req.basic_auth(@auth.username, @auth.password)
|
203
216
|
end
|
204
217
|
set_headers(req)
|
205
|
-
req.body = chunk.read
|
218
|
+
req.body = @json_array ? "[#{chunk.read.chop!}]" : chunk.read
|
206
219
|
req
|
207
220
|
end
|
208
221
|
|