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.

Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -5
  3. data/ChangeLog +54 -2
  4. data/example/in_dummy_blocks.conf +17 -0
  5. data/example/in_forward_tls.conf +14 -0
  6. data/example/in_forward_workers.conf +21 -0
  7. data/example/logevents.conf +25 -0
  8. data/example/out_forward_heartbeat_none.conf +16 -0
  9. data/example/out_forward_tls.conf +18 -0
  10. data/example/suppress_config_dump.conf +7 -0
  11. data/lib/fluent/agent.rb +3 -32
  12. data/lib/fluent/clock.rb +62 -0
  13. data/lib/fluent/command/fluentd.rb +12 -0
  14. data/lib/fluent/compat/input.rb +10 -1
  15. data/lib/fluent/compat/output.rb +40 -1
  16. data/lib/fluent/config/configure_proxy.rb +30 -7
  17. data/lib/fluent/config/section.rb +4 -0
  18. data/lib/fluent/config/types.rb +2 -2
  19. data/lib/fluent/configurable.rb +31 -5
  20. data/lib/fluent/engine.rb +61 -12
  21. data/lib/fluent/event_router.rb +6 -0
  22. data/lib/fluent/load.rb +0 -1
  23. data/lib/fluent/log.rb +118 -42
  24. data/lib/fluent/match.rb +37 -0
  25. data/lib/fluent/plugin.rb +25 -3
  26. data/lib/fluent/plugin/base.rb +4 -0
  27. data/lib/fluent/plugin/buf_file.rb +38 -14
  28. data/lib/fluent/plugin/buffer.rb +20 -20
  29. data/lib/fluent/plugin/buffer/file_chunk.rb +2 -2
  30. data/lib/fluent/plugin/compressable.rb +1 -0
  31. data/lib/fluent/plugin/filter_record_transformer.rb +3 -6
  32. data/lib/fluent/plugin/formatter_csv.rb +4 -1
  33. data/lib/fluent/plugin/formatter_hash.rb +5 -1
  34. data/lib/fluent/plugin/formatter_json.rb +10 -0
  35. data/lib/fluent/plugin/formatter_ltsv.rb +2 -1
  36. data/lib/fluent/plugin/in_dummy.rb +4 -0
  37. data/lib/fluent/plugin/in_exec.rb +4 -0
  38. data/lib/fluent/plugin/in_forward.rb +11 -3
  39. data/lib/fluent/plugin/in_gc_stat.rb +4 -0
  40. data/lib/fluent/plugin/in_http.rb +4 -0
  41. data/lib/fluent/plugin/in_monitor_agent.rb +29 -2
  42. data/lib/fluent/plugin/in_object_space.rb +4 -1
  43. data/lib/fluent/plugin/in_syslog.rb +4 -0
  44. data/lib/fluent/plugin/in_tail.rb +193 -116
  45. data/lib/fluent/plugin/in_tcp.rb +5 -1
  46. data/lib/fluent/plugin/in_udp.rb +4 -0
  47. data/lib/fluent/plugin/input.rb +4 -0
  48. data/lib/fluent/plugin/out_copy.rb +4 -0
  49. data/lib/fluent/plugin/out_exec.rb +4 -0
  50. data/lib/fluent/plugin/out_exec_filter.rb +4 -0
  51. data/lib/fluent/plugin/out_file.rb +70 -30
  52. data/lib/fluent/plugin/out_forward.rb +132 -28
  53. data/lib/fluent/plugin/out_null.rb +10 -0
  54. data/lib/fluent/plugin/out_relabel.rb +4 -0
  55. data/lib/fluent/plugin/out_roundrobin.rb +4 -0
  56. data/lib/fluent/plugin/out_secondary_file.rb +5 -0
  57. data/lib/fluent/plugin/out_stdout.rb +5 -0
  58. data/lib/fluent/plugin/output.rb +18 -9
  59. data/lib/fluent/plugin/storage_local.rb +25 -2
  60. data/lib/fluent/plugin_helper/cert_option.rb +159 -0
  61. data/lib/fluent/plugin_helper/child_process.rb +6 -6
  62. data/lib/fluent/plugin_helper/compat_parameters.rb +1 -1
  63. data/lib/fluent/plugin_helper/event_loop.rb +29 -4
  64. data/lib/fluent/plugin_helper/inject.rb +14 -1
  65. data/lib/fluent/plugin_helper/server.rb +275 -31
  66. data/lib/fluent/plugin_helper/socket.rb +144 -4
  67. data/lib/fluent/plugin_helper/socket_option.rb +2 -17
  68. data/lib/fluent/plugin_helper/storage.rb +7 -1
  69. data/lib/fluent/plugin_helper/thread.rb +16 -4
  70. data/lib/fluent/registry.rb +26 -9
  71. data/lib/fluent/root_agent.rb +7 -3
  72. data/lib/fluent/supervisor.rb +37 -15
  73. data/lib/fluent/system_config.rb +37 -10
  74. data/lib/fluent/test.rb +2 -0
  75. data/lib/fluent/test/driver/base.rb +24 -26
  76. data/lib/fluent/test/helpers.rb +21 -0
  77. data/lib/fluent/version.rb +1 -1
  78. data/test/command/test_fluentd.rb +274 -4
  79. data/test/config/test_configurable.rb +154 -0
  80. data/test/config/test_configure_proxy.rb +180 -1
  81. data/test/config/test_system_config.rb +10 -0
  82. data/test/config/test_types.rb +1 -0
  83. data/test/plugin/test_base.rb +4 -0
  84. data/test/plugin/test_buf_file.rb +241 -9
  85. data/test/plugin/test_buffer.rb +11 -11
  86. data/test/plugin/test_buffer_file_chunk.rb +6 -6
  87. data/test/plugin/test_compressable.rb +3 -0
  88. data/test/plugin/test_filter.rb +4 -0
  89. data/test/plugin/test_filter_record_transformer.rb +20 -0
  90. data/test/plugin/test_formatter_csv.rb +9 -0
  91. data/test/plugin/test_formatter_hash.rb +35 -0
  92. data/test/plugin/test_formatter_json.rb +8 -0
  93. data/test/plugin/test_formatter_ltsv.rb +7 -0
  94. data/test/plugin/test_in_dummy.rb +7 -3
  95. data/test/plugin/test_in_monitor_agent.rb +43 -5
  96. data/test/plugin/test_in_tail.rb +97 -4
  97. data/test/plugin/test_input.rb +4 -0
  98. data/test/plugin/test_out_file.rb +46 -7
  99. data/test/plugin/test_out_forward.rb +59 -7
  100. data/test/plugin/test_output.rb +10 -4
  101. data/test/plugin/test_output_as_buffered.rb +37 -25
  102. data/test/plugin/test_output_as_buffered_compress.rb +1 -1
  103. data/test/plugin/test_output_as_buffered_retries.rb +6 -6
  104. data/test/plugin/test_output_as_buffered_secondary.rb +91 -31
  105. data/test/plugin/test_storage_local.rb +40 -1
  106. data/test/plugin_helper/test_child_process.rb +29 -28
  107. data/test/plugin_helper/test_compat_parameters.rb +1 -1
  108. data/test/plugin_helper/test_inject.rb +27 -9
  109. data/test/plugin_helper/test_server.rb +822 -50
  110. data/test/plugin_helper/test_storage.rb +11 -0
  111. data/test/plugin_helper/test_timer.rb +1 -0
  112. data/test/test_clock.rb +164 -0
  113. data/test/test_log.rb +146 -15
  114. data/test/test_plugin.rb +251 -0
  115. data/test/test_supervisor.rb +65 -57
  116. data/test/test_test_drivers.rb +2 -2
  117. metadata +18 -7
  118. data/lib/fluent/process.rb +0 -504
  119. 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 = TCPSocket.new(host, port)
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 = UDPSocket.new(family)
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(host, port, resolve_name: false, certopts: {}, &block)
83
- raise "not implemented yet"
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, certopts: 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, certopts: 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
- until @_threads_mutex.synchronize{ @_threads.values.reduce(true){|r,t| r && ![:_fluentd_plugin_helper_thread_running] } }
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
@@ -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 = [DEFAULT_PLUGIN_PATH]
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
- lpath = File.expand_path(File.join(lp, "#{path}.rb"))
77
- File.exist?(lpath) ? lpath : nil
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.contains_requirable_file? path
87
- }
88
-
89
- # prefer newer version
90
- specs = specs.sort_by { |spec| spec.version }
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
- require file
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
@@ -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
- log.info "#{operation} #{kind} plugin", type: Plugin.lookup_type_from_class(instance.class), plugin_id: instance.plugin_id
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).
@@ -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
- root_dir = system_config.root_dir || params['root_dir']
234
- log_level = system_config.log_level || params['log_level']
235
- suppress_repeated_stacktrace = system_config.suppress_repeated_stacktrace || params['suppress_repeated_stacktrace']
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: 1,
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: false,
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
- @log.init
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
- $log.info "starting fluentd-#{Fluent::VERSION} without supervision", pid: Process.pid
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