fluentd 0.14.11 → 0.14.12
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of fluentd might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +1 -5
- data/ChangeLog +54 -2
- data/example/in_dummy_blocks.conf +17 -0
- data/example/in_forward_tls.conf +14 -0
- data/example/in_forward_workers.conf +21 -0
- data/example/logevents.conf +25 -0
- data/example/out_forward_heartbeat_none.conf +16 -0
- data/example/out_forward_tls.conf +18 -0
- data/example/suppress_config_dump.conf +7 -0
- data/lib/fluent/agent.rb +3 -32
- data/lib/fluent/clock.rb +62 -0
- data/lib/fluent/command/fluentd.rb +12 -0
- data/lib/fluent/compat/input.rb +10 -1
- data/lib/fluent/compat/output.rb +40 -1
- data/lib/fluent/config/configure_proxy.rb +30 -7
- data/lib/fluent/config/section.rb +4 -0
- data/lib/fluent/config/types.rb +2 -2
- data/lib/fluent/configurable.rb +31 -5
- data/lib/fluent/engine.rb +61 -12
- data/lib/fluent/event_router.rb +6 -0
- data/lib/fluent/load.rb +0 -1
- data/lib/fluent/log.rb +118 -42
- data/lib/fluent/match.rb +37 -0
- data/lib/fluent/plugin.rb +25 -3
- data/lib/fluent/plugin/base.rb +4 -0
- data/lib/fluent/plugin/buf_file.rb +38 -14
- data/lib/fluent/plugin/buffer.rb +20 -20
- data/lib/fluent/plugin/buffer/file_chunk.rb +2 -2
- data/lib/fluent/plugin/compressable.rb +1 -0
- data/lib/fluent/plugin/filter_record_transformer.rb +3 -6
- data/lib/fluent/plugin/formatter_csv.rb +4 -1
- data/lib/fluent/plugin/formatter_hash.rb +5 -1
- data/lib/fluent/plugin/formatter_json.rb +10 -0
- data/lib/fluent/plugin/formatter_ltsv.rb +2 -1
- data/lib/fluent/plugin/in_dummy.rb +4 -0
- data/lib/fluent/plugin/in_exec.rb +4 -0
- data/lib/fluent/plugin/in_forward.rb +11 -3
- data/lib/fluent/plugin/in_gc_stat.rb +4 -0
- data/lib/fluent/plugin/in_http.rb +4 -0
- data/lib/fluent/plugin/in_monitor_agent.rb +29 -2
- data/lib/fluent/plugin/in_object_space.rb +4 -1
- data/lib/fluent/plugin/in_syslog.rb +4 -0
- data/lib/fluent/plugin/in_tail.rb +193 -116
- data/lib/fluent/plugin/in_tcp.rb +5 -1
- data/lib/fluent/plugin/in_udp.rb +4 -0
- data/lib/fluent/plugin/input.rb +4 -0
- data/lib/fluent/plugin/out_copy.rb +4 -0
- data/lib/fluent/plugin/out_exec.rb +4 -0
- data/lib/fluent/plugin/out_exec_filter.rb +4 -0
- data/lib/fluent/plugin/out_file.rb +70 -30
- data/lib/fluent/plugin/out_forward.rb +132 -28
- data/lib/fluent/plugin/out_null.rb +10 -0
- data/lib/fluent/plugin/out_relabel.rb +4 -0
- data/lib/fluent/plugin/out_roundrobin.rb +4 -0
- data/lib/fluent/plugin/out_secondary_file.rb +5 -0
- data/lib/fluent/plugin/out_stdout.rb +5 -0
- data/lib/fluent/plugin/output.rb +18 -9
- data/lib/fluent/plugin/storage_local.rb +25 -2
- data/lib/fluent/plugin_helper/cert_option.rb +159 -0
- data/lib/fluent/plugin_helper/child_process.rb +6 -6
- data/lib/fluent/plugin_helper/compat_parameters.rb +1 -1
- data/lib/fluent/plugin_helper/event_loop.rb +29 -4
- data/lib/fluent/plugin_helper/inject.rb +14 -1
- data/lib/fluent/plugin_helper/server.rb +275 -31
- data/lib/fluent/plugin_helper/socket.rb +144 -4
- data/lib/fluent/plugin_helper/socket_option.rb +2 -17
- data/lib/fluent/plugin_helper/storage.rb +7 -1
- data/lib/fluent/plugin_helper/thread.rb +16 -4
- data/lib/fluent/registry.rb +26 -9
- data/lib/fluent/root_agent.rb +7 -3
- data/lib/fluent/supervisor.rb +37 -15
- data/lib/fluent/system_config.rb +37 -10
- data/lib/fluent/test.rb +2 -0
- data/lib/fluent/test/driver/base.rb +24 -26
- data/lib/fluent/test/helpers.rb +21 -0
- data/lib/fluent/version.rb +1 -1
- data/test/command/test_fluentd.rb +274 -4
- data/test/config/test_configurable.rb +154 -0
- data/test/config/test_configure_proxy.rb +180 -1
- data/test/config/test_system_config.rb +10 -0
- data/test/config/test_types.rb +1 -0
- data/test/plugin/test_base.rb +4 -0
- data/test/plugin/test_buf_file.rb +241 -9
- data/test/plugin/test_buffer.rb +11 -11
- data/test/plugin/test_buffer_file_chunk.rb +6 -6
- data/test/plugin/test_compressable.rb +3 -0
- data/test/plugin/test_filter.rb +4 -0
- data/test/plugin/test_filter_record_transformer.rb +20 -0
- data/test/plugin/test_formatter_csv.rb +9 -0
- data/test/plugin/test_formatter_hash.rb +35 -0
- data/test/plugin/test_formatter_json.rb +8 -0
- data/test/plugin/test_formatter_ltsv.rb +7 -0
- data/test/plugin/test_in_dummy.rb +7 -3
- data/test/plugin/test_in_monitor_agent.rb +43 -5
- data/test/plugin/test_in_tail.rb +97 -4
- data/test/plugin/test_input.rb +4 -0
- data/test/plugin/test_out_file.rb +46 -7
- data/test/plugin/test_out_forward.rb +59 -7
- data/test/plugin/test_output.rb +10 -4
- data/test/plugin/test_output_as_buffered.rb +37 -25
- data/test/plugin/test_output_as_buffered_compress.rb +1 -1
- data/test/plugin/test_output_as_buffered_retries.rb +6 -6
- data/test/plugin/test_output_as_buffered_secondary.rb +91 -31
- data/test/plugin/test_storage_local.rb +40 -1
- data/test/plugin_helper/test_child_process.rb +29 -28
- data/test/plugin_helper/test_compat_parameters.rb +1 -1
- data/test/plugin_helper/test_inject.rb +27 -9
- data/test/plugin_helper/test_server.rb +822 -50
- data/test/plugin_helper/test_storage.rb +11 -0
- data/test/plugin_helper/test_timer.rb +1 -0
- data/test/test_clock.rb +164 -0
- data/test/test_log.rb +146 -15
- data/test/test_plugin.rb +251 -0
- data/test/test_supervisor.rb +65 -57
- data/test/test_test_drivers.rb +2 -2
- metadata +18 -7
- data/lib/fluent/process.rb +0 -504
- data/test/test_process.rb +0 -48
@@ -16,6 +16,7 @@
|
|
16
16
|
|
17
17
|
require 'socket'
|
18
18
|
require 'ipaddr'
|
19
|
+
require 'openssl'
|
19
20
|
|
20
21
|
require_relative 'socket_option'
|
21
22
|
|
@@ -29,6 +30,12 @@ module Fluent
|
|
29
30
|
|
30
31
|
include Fluent::PluginHelper::SocketOption
|
31
32
|
|
33
|
+
TLS_DEFAULT_VERSION = :'TLSv1_2'
|
34
|
+
TLS_SUPPORTED_VERSIONS = [:'TLSv1_1', :'TLSv1_2']
|
35
|
+
### follow httpclient configuration by nahi
|
36
|
+
# OpenSSL 0.9.8 default: "ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH"
|
37
|
+
CIPHERS_DEFAULT = "ALL:!aNULL:!eNULL:!SSLv2" # OpenSSL >1.0.0 default
|
38
|
+
|
32
39
|
attr_reader :_sockets # for tests
|
33
40
|
|
34
41
|
# TODO: implement connection pool for specified host
|
@@ -49,7 +56,7 @@ module Fluent
|
|
49
56
|
end
|
50
57
|
|
51
58
|
def socket_create_tcp(host, port, resolve_name: false, **kwargs, &block)
|
52
|
-
sock =
|
59
|
+
sock = WrappedSocket::TCP.new(host, port)
|
53
60
|
socket_option_set(sock, resolve_name: resolve_name, **kwargs)
|
54
61
|
if block
|
55
62
|
begin
|
@@ -65,7 +72,7 @@ module Fluent
|
|
65
72
|
|
66
73
|
def socket_create_udp(host, port, resolve_name: false, connect: false, **kwargs, &block)
|
67
74
|
family = IPAddr.new(IPSocket.getaddress(host)).ipv4? ? ::Socket::AF_INET : ::Socket::AF_INET6
|
68
|
-
sock =
|
75
|
+
sock = WrappedSocket::UDP.new(family)
|
69
76
|
socket_option_set(sock, resolve_name: resolve_name, **kwargs)
|
70
77
|
sock.connect(host, port) if connect
|
71
78
|
if block
|
@@ -79,12 +86,145 @@ module Fluent
|
|
79
86
|
end
|
80
87
|
end
|
81
88
|
|
82
|
-
def socket_create_tls(
|
83
|
-
|
89
|
+
def socket_create_tls(
|
90
|
+
host, port,
|
91
|
+
version: TLS_DEFAULT_VERSION, ciphers: CIPHERS_DEFAULT, insecure: false, verify_fqdn: true, fqdn: nil,
|
92
|
+
enable_system_cert_store: true, allow_self_signed_cert: false, cert_paths: nil, **kwargs, &block)
|
93
|
+
|
94
|
+
host_is_ipaddress = IPAddr.new(host) rescue false
|
95
|
+
fqdn ||= host unless host_is_ipaddress
|
96
|
+
|
97
|
+
context = OpenSSL::SSL::SSLContext.new(version)
|
98
|
+
|
99
|
+
if insecure
|
100
|
+
log.trace "setting TLS verify_mode NONE"
|
101
|
+
context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
102
|
+
else
|
103
|
+
cert_store = OpenSSL::X509::Store.new
|
104
|
+
if allow_self_signed_cert && OpenSSL::X509.const_defined?('V_FLAG_CHECK_SS_SIGNATURE')
|
105
|
+
cert_store.flags = OpenSSL::X509::V_FLAG_CHECK_SS_SIGNATURE
|
106
|
+
end
|
107
|
+
begin
|
108
|
+
if enable_system_cert_store
|
109
|
+
log.trace "loading system default certificate store"
|
110
|
+
cert_store.set_default_paths
|
111
|
+
end
|
112
|
+
rescue OpenSSL::X509::StoreError
|
113
|
+
log.warn "failed to load system default certificate store", error: e
|
114
|
+
end
|
115
|
+
if cert_paths
|
116
|
+
if cert_paths.respond_to?(:each)
|
117
|
+
cert_paths.each do |cert_path|
|
118
|
+
log.trace "adding CA cert", path: cert_path
|
119
|
+
cert_store.add_file(cert_path)
|
120
|
+
end
|
121
|
+
else
|
122
|
+
cert_path = cert_paths
|
123
|
+
log.trace "adding CA cert", path: cert_path
|
124
|
+
cert_store.add_file(cert_path)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
log.trace "setting TLS context", mode: "peer", ciphers: ciphers
|
129
|
+
context.set_params({})
|
130
|
+
context.ciphers = ciphers
|
131
|
+
context.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
132
|
+
context.cert_store = cert_store
|
133
|
+
context.verify_hostname = true if verify_fqdn && fqdn && context.respond_to?(:verify_hostname=)
|
134
|
+
end
|
135
|
+
|
136
|
+
tcpsock = socket_create_tcp(host, port, **kwargs)
|
137
|
+
sock = WrappedSocket::TLS.new(tcpsock, context)
|
138
|
+
sock.sync_close = true
|
139
|
+
sock.hostname = fqdn if verify_fqdn && fqdn && sock.respond_to?(:hostname=)
|
140
|
+
|
141
|
+
log.trace "entering TLS handshake"
|
142
|
+
sock.connect
|
143
|
+
|
144
|
+
begin
|
145
|
+
if verify_fqdn
|
146
|
+
log.trace "checking peer's certificate", subject: sock.peer_cert.subject
|
147
|
+
sock.post_connection_check(fqdn)
|
148
|
+
verify = sock.verify_result
|
149
|
+
if verify != OpenSSL::X509::V_OK
|
150
|
+
err_name = Socket.tls_verify_result_name(verify)
|
151
|
+
log.warn "BUG: failed to verify certification while connecting (but not raised, why?)", host: host, fqdn: fqdn, error: err_name
|
152
|
+
raise RuntimeError, "BUG: failed to verify certification and to handle it correctly while connecting host #{host} as #{fqdn}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
rescue OpenSSL::SSL::SSLError => e
|
156
|
+
log.warn "failed to verify certification while connecting tls session", host: host, fqdn: fqdn, error: e
|
157
|
+
raise
|
158
|
+
end
|
159
|
+
|
160
|
+
if block
|
161
|
+
begin
|
162
|
+
block.call(sock)
|
163
|
+
ensure
|
164
|
+
sock.close rescue nil
|
165
|
+
end
|
166
|
+
else
|
167
|
+
sock
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.tls_verify_result_name(code)
|
172
|
+
case code
|
173
|
+
when OpenSSL::X509::V_OK then 'V_OK'
|
174
|
+
when OpenSSL::X509::V_ERR_AKID_SKID_MISMATCH then 'V_ERR_AKID_SKID_MISMATCH'
|
175
|
+
when OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION then 'V_ERR_APPLICATION_VERIFICATION'
|
176
|
+
when OpenSSL::X509::V_ERR_CERT_CHAIN_TOO_LONG then 'V_ERR_CERT_CHAIN_TOO_LONG'
|
177
|
+
when OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED then 'V_ERR_CERT_HAS_EXPIRED'
|
178
|
+
when OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID then 'V_ERR_CERT_NOT_YET_VALID'
|
179
|
+
when OpenSSL::X509::V_ERR_CERT_REJECTED then 'V_ERR_CERT_REJECTED'
|
180
|
+
when OpenSSL::X509::V_ERR_CERT_REVOKED then 'V_ERR_CERT_REVOKED'
|
181
|
+
when OpenSSL::X509::V_ERR_CERT_SIGNATURE_FAILURE then 'V_ERR_CERT_SIGNATURE_FAILURE'
|
182
|
+
when OpenSSL::X509::V_ERR_CERT_UNTRUSTED then 'V_ERR_CERT_UNTRUSTED'
|
183
|
+
when OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED then 'V_ERR_CRL_HAS_EXPIRED'
|
184
|
+
when OpenSSL::X509::V_ERR_CRL_NOT_YET_VALID then 'V_ERR_CRL_NOT_YET_VALID'
|
185
|
+
when OpenSSL::X509::V_ERR_CRL_SIGNATURE_FAILURE then 'V_ERR_CRL_SIGNATURE_FAILURE'
|
186
|
+
when OpenSSL::X509::V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT then 'V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT'
|
187
|
+
when OpenSSL::X509::V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD then 'V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD'
|
188
|
+
when OpenSSL::X509::V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD then 'V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD'
|
189
|
+
when OpenSSL::X509::V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD then 'V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD'
|
190
|
+
when OpenSSL::X509::V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD then 'V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD'
|
191
|
+
when OpenSSL::X509::V_ERR_INVALID_CA then 'V_ERR_INVALID_CA'
|
192
|
+
when OpenSSL::X509::V_ERR_INVALID_PURPOSE then 'V_ERR_INVALID_PURPOSE'
|
193
|
+
when OpenSSL::X509::V_ERR_KEYUSAGE_NO_CERTSIGN then 'V_ERR_KEYUSAGE_NO_CERTSIGN'
|
194
|
+
when OpenSSL::X509::V_ERR_OUT_OF_MEM then 'V_ERR_OUT_OF_MEM'
|
195
|
+
when OpenSSL::X509::V_ERR_PATH_LENGTH_EXCEEDED then 'V_ERR_PATH_LENGTH_EXCEEDED'
|
196
|
+
when OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN then 'V_ERR_SELF_SIGNED_CERT_IN_CHAIN'
|
197
|
+
when OpenSSL::X509::V_ERR_SUBJECT_ISSUER_MISMATCH then 'V_ERR_SUBJECT_ISSUER_MISMATCH'
|
198
|
+
when OpenSSL::X509::V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY then 'V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY'
|
199
|
+
when OpenSSL::X509::V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE then 'V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY'
|
200
|
+
when OpenSSL::X509::V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE then 'V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE'
|
201
|
+
when OpenSSL::X509::V_ERR_UNABLE_TO_GET_CRL then 'V_ERR_UNABLE_TO_GET_CRL'
|
202
|
+
when OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT then 'V_ERR_UNABLE_TO_GET_ISSUER_CERT'
|
203
|
+
when OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY then 'V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY'
|
204
|
+
when OpenSSL::X509::V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE then 'V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE'
|
205
|
+
end
|
84
206
|
end
|
85
207
|
|
86
208
|
# socket_create_socks ?
|
87
209
|
|
210
|
+
module WrappedSocket
|
211
|
+
class TCP < ::TCPSocket
|
212
|
+
def remote_addr; peeraddr[3]; end
|
213
|
+
def remote_host; peeraddr[2]; end
|
214
|
+
def remote_port; peeraddr[1]; end
|
215
|
+
end
|
216
|
+
class UDP < ::UDPSocket
|
217
|
+
def remote_addr; peeraddr[3]; end
|
218
|
+
def remote_host; peeraddr[2]; end
|
219
|
+
def remote_port; peeraddr[1]; end
|
220
|
+
end
|
221
|
+
class TLS < OpenSSL::SSL::SSLSocket
|
222
|
+
def remote_addr; peeraddr[3]; end
|
223
|
+
def remote_host; peeraddr[2]; end
|
224
|
+
def remote_port; peeraddr[1]; end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
88
228
|
def initialize
|
89
229
|
super
|
90
230
|
# @_sockets = [] # for keepalived sockets / connection pool
|
@@ -24,7 +24,7 @@ module Fluent
|
|
24
24
|
FORMAT_STRUCT_LINGER = 'I!I!' # { int l_onoff; int l_linger; }
|
25
25
|
FORMAT_STRUCT_TIMEVAL = 'L!L!' # { time_t tv_sec; suseconds_t tv_usec; }
|
26
26
|
|
27
|
-
def socket_option_validate!(protocol, resolve_name: nil, linger_timeout: nil, recv_timeout: nil, send_timeout: nil
|
27
|
+
def socket_option_validate!(protocol, resolve_name: nil, linger_timeout: nil, recv_timeout: nil, send_timeout: nil)
|
28
28
|
unless resolve_name.nil?
|
29
29
|
if protocol != :tcp && protocol != :udp && protocol != :tls
|
30
30
|
raise ArgumentError, "BUG: resolve_name in available for tcp/udp/tls"
|
@@ -35,23 +35,9 @@ module Fluent
|
|
35
35
|
raise ArgumentError, "BUG: linger_timeout is available for tcp/tls"
|
36
36
|
end
|
37
37
|
end
|
38
|
-
if certopts
|
39
|
-
if protocol != :tls
|
40
|
-
raise ArgumentError, "BUG: certopts is available only for tls"
|
41
|
-
end
|
42
|
-
else
|
43
|
-
if protocol == :tls
|
44
|
-
raise ArgumentError, "BUG: certopts (certificate options) not specified for TLS"
|
45
|
-
socket_option_certopts_validate!(certopts)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def socket_option_certopts_validate!(certopts)
|
51
|
-
raise "not implemented yet"
|
52
38
|
end
|
53
39
|
|
54
|
-
def socket_option_set(sock, resolve_name: nil, nonblock: false, linger_timeout: nil, recv_timeout: nil, send_timeout: nil
|
40
|
+
def socket_option_set(sock, resolve_name: nil, nonblock: false, linger_timeout: nil, recv_timeout: nil, send_timeout: nil)
|
55
41
|
unless resolve_name.nil?
|
56
42
|
sock.do_not_reverse_lookup = !resolve_name
|
57
43
|
end
|
@@ -70,7 +56,6 @@ module Fluent
|
|
70
56
|
optval = [send_timeout.to_i, 0].pack(FORMAT_STRUCT_TIMEVAL)
|
71
57
|
socket_option_set_one(sock, :SO_SNDTIMEO, optval)
|
72
58
|
end
|
73
|
-
# TODO: certopts for TLS
|
74
59
|
sock
|
75
60
|
end
|
76
61
|
|
@@ -33,6 +33,9 @@ module Fluent
|
|
33
33
|
if conf && !conf.arg.empty?
|
34
34
|
usage = conf.arg
|
35
35
|
end
|
36
|
+
if !usage.empty? && usage !~ /^[a-zA-Z][-_.a-zA-Z0-9]*$/
|
37
|
+
raise Fluent::ConfigError, "Argument in <storage ARG> uses invalid characters: '#{usage}'"
|
38
|
+
end
|
36
39
|
|
37
40
|
s = @_storages[usage]
|
38
41
|
if s && s.running
|
@@ -59,7 +62,7 @@ module Fluent
|
|
59
62
|
conf = Hash[conf.map{|k,v| [k.to_s, v]}]
|
60
63
|
Fluent::Config::Element.new('storage', usage, conf, [])
|
61
64
|
when nil
|
62
|
-
Fluent::Config::Element.new('storage', usage, {}, [])
|
65
|
+
Fluent::Config::Element.new('storage', usage, {'@type' => type}, [])
|
63
66
|
else
|
64
67
|
raise ArgumentError, "BUG: conf must be a Element, Hash (or unspecified), but '#{conf.class}'"
|
65
68
|
end
|
@@ -98,6 +101,9 @@ module Fluent
|
|
98
101
|
super
|
99
102
|
|
100
103
|
@storage_configs.each do |section|
|
104
|
+
if !section.usage.empty? && section.usage !~ /^[a-zA-Z][-_.a-zA-Z0-9]*$/
|
105
|
+
raise Fluent::ConfigError, "Argument in <storage ARG> uses invalid characters: '#{section.usage}'"
|
106
|
+
end
|
101
107
|
if @_storages[section.usage]
|
102
108
|
raise Fluent::ConfigError, "duplicated storages configured: #{section.usage}"
|
103
109
|
end
|
@@ -14,10 +14,13 @@
|
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
16
|
|
17
|
+
require 'fluent/clock'
|
18
|
+
|
17
19
|
module Fluent
|
18
20
|
module PluginHelper
|
19
21
|
module Thread
|
20
22
|
THREAD_DEFAULT_WAIT_SECONDS = 1
|
23
|
+
THREAD_SHUTDOWN_HARD_TIMEOUT_IN_TESTS = 100 # second
|
21
24
|
|
22
25
|
# stop : mark callback thread as stopped
|
23
26
|
# shutdown : [-]
|
@@ -38,9 +41,18 @@ module Fluent
|
|
38
41
|
end
|
39
42
|
|
40
43
|
def thread_wait_until_stop
|
41
|
-
|
44
|
+
timeout_at = Fluent::Clock.now + THREAD_SHUTDOWN_HARD_TIMEOUT_IN_TESTS
|
45
|
+
until @_threads_mutex.synchronize{ @_threads.values.reduce(true){|r,t| r && !t[:_fluentd_plugin_helper_thread_running] } }
|
46
|
+
break if Fluent::Clock.now > timeout_at
|
42
47
|
sleep 0.1
|
43
48
|
end
|
49
|
+
@_threads_mutex.synchronize{ @_threads.values }.each do |t|
|
50
|
+
if t.alive?
|
51
|
+
puts "going to kill the thread still running: #{t[:_fluentd_plugin_helper_thread_title]}"
|
52
|
+
t.kill rescue nil
|
53
|
+
t[:_fluentd_plugin_helper_thread_running] = false
|
54
|
+
end
|
55
|
+
end
|
44
56
|
end
|
45
57
|
|
46
58
|
# Ruby 2.2.3 or earlier (and all 2.1.x) cause bug about Threading ("Stack consistency error")
|
@@ -70,13 +82,13 @@ module Fluent
|
|
70
82
|
thread_exit = true
|
71
83
|
raise
|
72
84
|
ensure
|
73
|
-
if ::Thread.current.alive? && !thread_exit
|
74
|
-
log.warn "thread doesn't exit correctly (killed or other reason)", plugin: self.class, title: title, thread: ::Thread.current, error: $!
|
75
|
-
end
|
76
85
|
@_threads_mutex.synchronize do
|
77
86
|
@_threads.delete(::Thread.current.object_id)
|
78
87
|
end
|
79
88
|
::Thread.current[:_fluentd_plugin_helper_thread_running] = false
|
89
|
+
if ::Thread.current.alive? && !thread_exit
|
90
|
+
log.warn "thread doesn't exit correctly (killed or other reason)", plugin: self.class, title: title, thread: ::Thread.current, error: $!
|
91
|
+
end
|
80
92
|
end
|
81
93
|
end
|
82
94
|
thread.abort_on_exception = true
|
data/lib/fluent/registry.rb
CHANGED
@@ -19,13 +19,14 @@ require 'fluent/config/error'
|
|
19
19
|
module Fluent
|
20
20
|
class Registry
|
21
21
|
DEFAULT_PLUGIN_PATH = File.expand_path('../plugin', __FILE__)
|
22
|
+
FLUENT_LIB_PATH = File.dirname(File.dirname(DEFAULT_PLUGIN_PATH))
|
22
23
|
|
23
24
|
def initialize(kind, search_prefix, dir_search_prefix: nil)
|
24
25
|
@kind = kind
|
25
26
|
@search_prefix = search_prefix
|
26
27
|
@dir_search_prefix = dir_search_prefix
|
27
28
|
@map = {}
|
28
|
-
@paths = [
|
29
|
+
@paths = []
|
29
30
|
end
|
30
31
|
|
31
32
|
attr_reader :kind, :paths, :map, :dir_search_prefix
|
@@ -73,8 +74,12 @@ module Fluent
|
|
73
74
|
|
74
75
|
# prefer LOAD_PATH than gems
|
75
76
|
files = $LOAD_PATH.map { |lp|
|
76
|
-
|
77
|
-
|
77
|
+
if lp == FLUENT_LIB_PATH
|
78
|
+
nil
|
79
|
+
else
|
80
|
+
lpath = File.expand_path(File.join(lp, "#{path}.rb"))
|
81
|
+
File.exist?(lpath) ? lpath : nil
|
82
|
+
end
|
78
83
|
}.compact
|
79
84
|
unless files.empty?
|
80
85
|
# prefer newer version
|
@@ -82,18 +87,30 @@ module Fluent
|
|
82
87
|
return
|
83
88
|
end
|
84
89
|
|
90
|
+
# Find from gems and prefer newer version
|
85
91
|
specs = Gem::Specification.find_all { |spec|
|
86
|
-
spec.
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
92
|
+
if spec.name == 'fluentd'.freeze
|
93
|
+
false
|
94
|
+
else
|
95
|
+
spec.contains_requirable_file? path
|
96
|
+
end
|
97
|
+
}.sort_by { |spec| spec.version }
|
91
98
|
if spec = specs.last
|
92
99
|
spec.require_paths.each { |lib|
|
93
100
|
file = "#{spec.full_gem_path}/#{lib}/#{path}"
|
94
|
-
|
101
|
+
if File.exist?("#{file}.rb")
|
102
|
+
require file
|
103
|
+
return
|
104
|
+
end
|
95
105
|
}
|
96
106
|
end
|
107
|
+
|
108
|
+
# Lastly, load built-in plugin
|
109
|
+
lpath = File.expand_path(File.join(FLUENT_LIB_PATH, "#{@search_prefix}#{type}.rb"))
|
110
|
+
if File.exist?(lpath)
|
111
|
+
require lpath
|
112
|
+
return
|
113
|
+
end
|
97
114
|
end
|
98
115
|
end
|
99
116
|
end
|
data/lib/fluent/root_agent.rb
CHANGED
@@ -87,7 +87,7 @@ module Fluent
|
|
87
87
|
|
88
88
|
# initialize <source> elements
|
89
89
|
if @without_source
|
90
|
-
log.info "'--without-source' is applied. Ignore <source> sections"
|
90
|
+
log.info :worker0, "'--without-source' is applied. Ignore <source> sections"
|
91
91
|
else
|
92
92
|
conf.elements(name: 'source').each { |e|
|
93
93
|
type = e['@type']
|
@@ -196,7 +196,11 @@ module Fluent
|
|
196
196
|
t = Thread.new do
|
197
197
|
Thread.current.abort_on_exception = true
|
198
198
|
begin
|
199
|
-
|
199
|
+
if method == :shutdown
|
200
|
+
log.info "#{operation} #{kind} plugin", type: Plugin.lookup_type_from_class(instance.class), plugin_id: instance.plugin_id
|
201
|
+
else
|
202
|
+
log.debug "#{operation} #{kind} plugin", type: Plugin.lookup_type_from_class(instance.class), plugin_id: instance.plugin_id
|
203
|
+
end
|
200
204
|
instance.send(method) unless instance.send(checker)
|
201
205
|
rescue Exception => e
|
202
206
|
log.warn "unexpected error while #{operation} on #{kind} plugin", plugin: instance.class, plugin_id: instance.plugin_id, error: e
|
@@ -227,7 +231,7 @@ module Fluent
|
|
227
231
|
end
|
228
232
|
|
229
233
|
def add_source(type, conf)
|
230
|
-
log.info "adding source", type: type
|
234
|
+
log.info :worker0, "adding source", type: type
|
231
235
|
|
232
236
|
input = Plugin.new_input(type)
|
233
237
|
# <source> emits events to the top-level event router (RootAgent#event_router).
|
data/lib/fluent/supervisor.rb
CHANGED
@@ -14,8 +14,6 @@
|
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
16
|
|
17
|
-
require 'etc'
|
18
|
-
require 'fcntl'
|
19
17
|
require 'fileutils'
|
20
18
|
|
21
19
|
require 'fluent/config'
|
@@ -27,7 +25,6 @@ require 'fluent/plugin'
|
|
27
25
|
require 'fluent/rpc'
|
28
26
|
require 'fluent/system_config'
|
29
27
|
require 'serverengine'
|
30
|
-
require 'shellwords'
|
31
28
|
|
32
29
|
if Fluent.windows?
|
33
30
|
require 'windows/library'
|
@@ -230,9 +227,13 @@ module Fluent
|
|
230
227
|
fluentd_conf = Fluent::Config.parse(config_data, config_fname, config_basedir, params['use_v1_config'])
|
231
228
|
system_config = SystemConfig.create(fluentd_conf)
|
232
229
|
|
233
|
-
|
234
|
-
|
235
|
-
|
230
|
+
# these params must NOT be configured via system config here.
|
231
|
+
# these may be overridden by command line params.
|
232
|
+
workers = params['workers']
|
233
|
+
root_dir = params['root_dir']
|
234
|
+
log_level = params['log_level']
|
235
|
+
suppress_repeated_stacktrace = params['suppress_repeated_stacktrace']
|
236
|
+
|
236
237
|
log_path = params['log_path']
|
237
238
|
chuser = params['chuser']
|
238
239
|
chgroup = params['chgroup']
|
@@ -248,7 +249,7 @@ module Fluent
|
|
248
249
|
log_rotate_size: log_rotate_size
|
249
250
|
)
|
250
251
|
# this #init sets initialized logger to $log
|
251
|
-
logger_initializer.init
|
252
|
+
logger_initializer.init(:supervisor, 0)
|
252
253
|
logger = $log
|
253
254
|
|
254
255
|
command_sender = Fluent.windows? ? "pipe" : "signal"
|
@@ -261,7 +262,7 @@ module Fluent
|
|
261
262
|
|
262
263
|
se_config = {
|
263
264
|
worker_type: 'spawn',
|
264
|
-
workers:
|
265
|
+
workers: workers,
|
265
266
|
log_stdin: false,
|
266
267
|
log_stdout: false,
|
267
268
|
log_stderr: false,
|
@@ -318,7 +319,10 @@ module Fluent
|
|
318
319
|
@log_rotate_size = log_rotate_size
|
319
320
|
end
|
320
321
|
|
321
|
-
def init
|
322
|
+
def init(process_type, worker_id)
|
323
|
+
@opts[:process_type] = process_type
|
324
|
+
@opts[:worker_id] = worker_id
|
325
|
+
|
322
326
|
if @path && @path != "-"
|
323
327
|
@logdev = if @log_rotate_age || @log_rotate_size
|
324
328
|
Fluent::LogDeviceIO.new(@path, shift_age: @log_rotate_age, shift_size: @log_rotate_size)
|
@@ -374,7 +378,7 @@ module Fluent
|
|
374
378
|
root_dir: nil,
|
375
379
|
suppress_interval: 0,
|
376
380
|
suppress_repeated_stacktrace: true,
|
377
|
-
without_source:
|
381
|
+
without_source: nil,
|
378
382
|
use_v1_config: true,
|
379
383
|
supervise: true,
|
380
384
|
standalone_worker: false,
|
@@ -400,12 +404,14 @@ module Fluent
|
|
400
404
|
@rpc_server = nil
|
401
405
|
@process_name = nil
|
402
406
|
|
407
|
+
@workers = opt[:workers]
|
403
408
|
@root_dir = opt[:root_dir]
|
404
409
|
@log_level = opt[:log_level]
|
405
410
|
@log_rotate_age = opt[:log_rotate_age]
|
406
411
|
@log_rotate_size = opt[:log_rotate_size]
|
407
412
|
@suppress_interval = opt[:suppress_interval]
|
408
413
|
@suppress_config_dump = opt[:suppress_config_dump]
|
414
|
+
@log_event_verbose = opt[:log_event_verbose]
|
409
415
|
@without_source = opt[:without_source]
|
410
416
|
@signame = opt[:signame]
|
411
417
|
|
@@ -420,11 +426,15 @@ module Fluent
|
|
420
426
|
end
|
421
427
|
|
422
428
|
def run_supervisor
|
423
|
-
@log.init
|
429
|
+
@log.init(:supervisor, 0)
|
424
430
|
show_plugin_config if @show_plugin_config
|
425
431
|
read_config
|
426
432
|
set_system_config
|
427
433
|
|
434
|
+
if @workers < 1
|
435
|
+
raise Fluent::ConfigError, "invalid number of workers (must be > 0):#{@workers}"
|
436
|
+
end
|
437
|
+
|
428
438
|
if @root_dir
|
429
439
|
if File.exist?(@root_dir)
|
430
440
|
unless Dir.exist?(@root_dir)
|
@@ -459,7 +469,13 @@ module Fluent
|
|
459
469
|
rescue Exception
|
460
470
|
# ignore LoadError and others (related with signals): it may raise these errors in Windows
|
461
471
|
end
|
462
|
-
|
472
|
+
worker_id = ENV['SERVERENGINE_WORKER_ID'].to_i
|
473
|
+
process_type = case
|
474
|
+
when @standalone_worker then :standalone
|
475
|
+
when worker_id == 0 then :worker0
|
476
|
+
else :workers
|
477
|
+
end
|
478
|
+
@log.init(process_type, worker_id)
|
463
479
|
Process.setproctitle("worker:#{@process_name}") if @process_name
|
464
480
|
|
465
481
|
show_plugin_config if @show_plugin_config
|
@@ -468,7 +484,8 @@ module Fluent
|
|
468
484
|
|
469
485
|
install_main_process_signal_handlers
|
470
486
|
|
471
|
-
|
487
|
+
# This is the only log messsage for @standalone_worker
|
488
|
+
$log.info "starting fluentd-#{Fluent::VERSION} without supervision", pid: Process.pid if @standalone_worker
|
472
489
|
|
473
490
|
main_process do
|
474
491
|
create_socket_manager if @standalone_worker
|
@@ -542,12 +559,16 @@ module Fluent
|
|
542
559
|
params['daemonize'] = @daemonize
|
543
560
|
params['inline_config'] = @inline_config
|
544
561
|
params['log_path'] = @log_path
|
545
|
-
params['log_level'] = @log_level
|
546
562
|
params['log_rotate_age'] = @log_rotate_age
|
547
563
|
params['log_rotate_size'] = @log_rotate_size
|
548
564
|
params['chuser'] = @chuser
|
549
565
|
params['chgroup'] = @chgroup
|
550
566
|
params['use_v1_config'] = @use_v1_config
|
567
|
+
|
568
|
+
# system config parameters
|
569
|
+
params['workers'] = @workers
|
570
|
+
params['root_dir'] = @root_dir
|
571
|
+
params['log_level'] = @log_level
|
551
572
|
params['suppress_repeated_stacktrace'] = @suppress_repeated_stacktrace
|
552
573
|
params['signame'] = @signame
|
553
574
|
|
@@ -681,7 +702,7 @@ module Fluent
|
|
681
702
|
end
|
682
703
|
|
683
704
|
def read_config
|
684
|
-
$log.info "reading config file", path: @config_path
|
705
|
+
$log.info :supervisor, "reading config file", path: @config_path
|
685
706
|
@config_fname = File.basename(@config_path)
|
686
707
|
@config_basedir = File.dirname(@config_path)
|
687
708
|
@config_data = File.read(@config_path)
|
@@ -695,6 +716,7 @@ module Fluent
|
|
695
716
|
|
696
717
|
def set_system_config
|
697
718
|
@system_config = SystemConfig.create(@conf) # @conf is set in read_config
|
719
|
+
@system_config.attach(self)
|
698
720
|
@system_config.apply(self)
|
699
721
|
end
|
700
722
|
|