fluentd 1.13.3 → 1.16.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/{bug_report.yaml → bug_report.yml} +2 -0
  3. data/.github/ISSUE_TEMPLATE/config.yml +2 -2
  4. data/.github/ISSUE_TEMPLATE/{feature_request.yaml → feature_request.yml} +1 -0
  5. data/.github/workflows/stale-actions.yml +11 -9
  6. data/.github/workflows/test.yml +32 -0
  7. data/CHANGELOG.md +490 -10
  8. data/CONTRIBUTING.md +2 -2
  9. data/MAINTAINERS.md +7 -5
  10. data/README.md +3 -23
  11. data/Rakefile +1 -1
  12. data/SECURITY.md +14 -0
  13. data/fluentd.gemspec +7 -8
  14. data/lib/fluent/command/cat.rb +13 -3
  15. data/lib/fluent/command/ctl.rb +6 -3
  16. data/lib/fluent/command/fluentd.rb +73 -65
  17. data/lib/fluent/command/plugin_config_formatter.rb +1 -1
  18. data/lib/fluent/compat/output.rb +9 -6
  19. data/lib/fluent/config/dsl.rb +1 -1
  20. data/lib/fluent/config/error.rb +12 -0
  21. data/lib/fluent/config/literal_parser.rb +2 -2
  22. data/lib/fluent/config/parser.rb +1 -1
  23. data/lib/fluent/config/v1_parser.rb +3 -3
  24. data/lib/fluent/config/yaml_parser/fluent_value.rb +47 -0
  25. data/lib/fluent/config/yaml_parser/loader.rb +108 -0
  26. data/lib/fluent/config/yaml_parser/parser.rb +166 -0
  27. data/lib/fluent/config/yaml_parser/section_builder.rb +107 -0
  28. data/lib/fluent/config/yaml_parser.rb +56 -0
  29. data/lib/fluent/config.rb +14 -1
  30. data/lib/fluent/counter/server.rb +1 -1
  31. data/lib/fluent/counter/validator.rb +3 -3
  32. data/lib/fluent/daemon.rb +2 -4
  33. data/lib/fluent/engine.rb +1 -1
  34. data/lib/fluent/env.rb +4 -0
  35. data/lib/fluent/error.rb +3 -0
  36. data/lib/fluent/event.rb +8 -4
  37. data/lib/fluent/event_router.rb +47 -2
  38. data/lib/fluent/file_wrapper.rb +137 -0
  39. data/lib/fluent/log/console_adapter.rb +66 -0
  40. data/lib/fluent/log.rb +44 -5
  41. data/lib/fluent/match.rb +1 -1
  42. data/lib/fluent/msgpack_factory.rb +6 -1
  43. data/lib/fluent/oj_options.rb +1 -2
  44. data/lib/fluent/plugin/bare_output.rb +49 -8
  45. data/lib/fluent/plugin/base.rb +26 -9
  46. data/lib/fluent/plugin/buf_file.rb +34 -5
  47. data/lib/fluent/plugin/buf_file_single.rb +32 -3
  48. data/lib/fluent/plugin/buffer/file_chunk.rb +1 -1
  49. data/lib/fluent/plugin/buffer.rb +216 -70
  50. data/lib/fluent/plugin/filter.rb +35 -1
  51. data/lib/fluent/plugin/filter_record_transformer.rb +1 -1
  52. data/lib/fluent/plugin/in_forward.rb +2 -2
  53. data/lib/fluent/plugin/in_http.rb +39 -10
  54. data/lib/fluent/plugin/in_monitor_agent.rb +4 -2
  55. data/lib/fluent/plugin/in_sample.rb +1 -1
  56. data/lib/fluent/plugin/in_syslog.rb +13 -1
  57. data/lib/fluent/plugin/in_tail/group_watch.rb +204 -0
  58. data/lib/fluent/plugin/in_tail/position_file.rb +33 -33
  59. data/lib/fluent/plugin/in_tail.rb +216 -84
  60. data/lib/fluent/plugin/in_tcp.rb +47 -2
  61. data/lib/fluent/plugin/input.rb +39 -1
  62. data/lib/fluent/plugin/metrics.rb +119 -0
  63. data/lib/fluent/plugin/metrics_local.rb +96 -0
  64. data/lib/fluent/plugin/multi_output.rb +43 -6
  65. data/lib/fluent/plugin/out_copy.rb +1 -1
  66. data/lib/fluent/plugin/out_exec_filter.rb +2 -2
  67. data/lib/fluent/plugin/out_file.rb +20 -2
  68. data/lib/fluent/plugin/out_forward/ack_handler.rb +19 -4
  69. data/lib/fluent/plugin/out_forward/socket_cache.rb +2 -0
  70. data/lib/fluent/plugin/out_forward.rb +17 -9
  71. data/lib/fluent/plugin/out_secondary_file.rb +39 -22
  72. data/lib/fluent/plugin/output.rb +167 -78
  73. data/lib/fluent/plugin/parser.rb +3 -4
  74. data/lib/fluent/plugin/parser_apache2.rb +1 -1
  75. data/lib/fluent/plugin/parser_json.rb +1 -1
  76. data/lib/fluent/plugin/parser_syslog.rb +1 -1
  77. data/lib/fluent/plugin/storage_local.rb +3 -5
  78. data/lib/fluent/plugin.rb +10 -1
  79. data/lib/fluent/plugin_helper/child_process.rb +3 -0
  80. data/lib/fluent/plugin_helper/event_emitter.rb +8 -1
  81. data/lib/fluent/plugin_helper/event_loop.rb +2 -2
  82. data/lib/fluent/plugin_helper/http_server/server.rb +2 -1
  83. data/lib/fluent/plugin_helper/metrics.rb +129 -0
  84. data/lib/fluent/plugin_helper/record_accessor.rb +1 -1
  85. data/lib/fluent/plugin_helper/retry_state.rb +14 -4
  86. data/lib/fluent/plugin_helper/server.rb +35 -6
  87. data/lib/fluent/plugin_helper/service_discovery.rb +2 -2
  88. data/lib/fluent/plugin_helper/socket.rb +13 -2
  89. data/lib/fluent/plugin_helper/thread.rb +3 -3
  90. data/lib/fluent/plugin_helper.rb +1 -0
  91. data/lib/fluent/plugin_id.rb +3 -2
  92. data/lib/fluent/registry.rb +2 -1
  93. data/lib/fluent/root_agent.rb +6 -0
  94. data/lib/fluent/rpc.rb +4 -3
  95. data/lib/fluent/supervisor.rb +283 -259
  96. data/lib/fluent/system_config.rb +13 -3
  97. data/lib/fluent/test/driver/base.rb +11 -5
  98. data/lib/fluent/test/driver/filter.rb +4 -0
  99. data/lib/fluent/test/startup_shutdown.rb +6 -8
  100. data/lib/fluent/time.rb +21 -20
  101. data/lib/fluent/version.rb +1 -1
  102. data/lib/fluent/win32api.rb +38 -0
  103. data/lib/fluent/winsvc.rb +5 -8
  104. data/templates/new_gem/test/helper.rb.erb +0 -1
  105. data/test/command/test_cat.rb +31 -2
  106. data/test/command/test_ctl.rb +1 -2
  107. data/test/command/test_fluentd.rb +209 -24
  108. data/test/command/test_plugin_config_formatter.rb +0 -1
  109. data/test/compat/test_parser.rb +6 -6
  110. data/test/config/test_system_config.rb +13 -11
  111. data/test/config/test_types.rb +1 -1
  112. data/test/log/test_console_adapter.rb +110 -0
  113. data/test/plugin/in_tail/test_io_handler.rb +26 -8
  114. data/test/plugin/in_tail/test_position_file.rb +48 -59
  115. data/test/plugin/out_forward/test_ack_handler.rb +39 -0
  116. data/test/plugin/out_forward/test_socket_cache.rb +26 -1
  117. data/test/plugin/test_bare_output.rb +14 -1
  118. data/test/plugin/test_base.rb +133 -1
  119. data/test/plugin/test_buf_file.rb +62 -23
  120. data/test/plugin/test_buf_file_single.rb +65 -0
  121. data/test/plugin/test_buffer.rb +267 -3
  122. data/test/plugin/test_buffer_chunk.rb +11 -0
  123. data/test/plugin/test_filter.rb +12 -1
  124. data/test/plugin/test_filter_parser.rb +1 -1
  125. data/test/plugin/test_filter_stdout.rb +2 -2
  126. data/test/plugin/test_in_forward.rb +9 -11
  127. data/test/plugin/test_in_http.rb +65 -3
  128. data/test/plugin/test_in_monitor_agent.rb +216 -11
  129. data/test/plugin/test_in_object_space.rb +9 -3
  130. data/test/plugin/test_in_syslog.rb +35 -0
  131. data/test/plugin/test_in_tail.rb +1393 -385
  132. data/test/plugin/test_in_tcp.rb +87 -2
  133. data/test/plugin/test_in_udp.rb +28 -0
  134. data/test/plugin/test_in_unix.rb +2 -2
  135. data/test/plugin/test_input.rb +12 -1
  136. data/test/plugin/test_metrics.rb +294 -0
  137. data/test/plugin/test_metrics_local.rb +96 -0
  138. data/test/plugin/test_multi_output.rb +25 -1
  139. data/test/plugin/test_out_exec.rb +6 -4
  140. data/test/plugin/test_out_exec_filter.rb +6 -2
  141. data/test/plugin/test_out_file.rb +34 -17
  142. data/test/plugin/test_out_forward.rb +78 -77
  143. data/test/plugin/test_out_http.rb +1 -0
  144. data/test/plugin/test_out_stdout.rb +2 -2
  145. data/test/plugin/test_output.rb +297 -12
  146. data/test/plugin/test_output_as_buffered.rb +44 -44
  147. data/test/plugin/test_output_as_buffered_compress.rb +32 -18
  148. data/test/plugin/test_output_as_buffered_retries.rb +54 -7
  149. data/test/plugin/test_output_as_buffered_secondary.rb +4 -4
  150. data/test/plugin/test_parser_regexp.rb +1 -6
  151. data/test/plugin/test_parser_syslog.rb +1 -1
  152. data/test/plugin_helper/test_cert_option.rb +1 -1
  153. data/test/plugin_helper/test_child_process.rb +38 -16
  154. data/test/plugin_helper/test_event_emitter.rb +29 -0
  155. data/test/plugin_helper/test_http_server_helper.rb +1 -1
  156. data/test/plugin_helper/test_metrics.rb +137 -0
  157. data/test/plugin_helper/test_retry_state.rb +602 -38
  158. data/test/plugin_helper/test_server.rb +78 -6
  159. data/test/plugin_helper/test_timer.rb +2 -2
  160. data/test/test_config.rb +191 -24
  161. data/test/test_event_router.rb +17 -0
  162. data/test/test_file_wrapper.rb +53 -0
  163. data/test/test_formatter.rb +24 -21
  164. data/test/test_log.rb +122 -40
  165. data/test/test_msgpack_factory.rb +32 -0
  166. data/test/test_plugin_classes.rb +102 -0
  167. data/test/test_root_agent.rb +30 -1
  168. data/test/test_supervisor.rb +477 -257
  169. data/test/test_time_parser.rb +22 -0
  170. metadata +55 -34
  171. data/.drone.yml +0 -35
  172. data/.github/workflows/issue-auto-closer.yml +0 -12
  173. data/.github/workflows/linux-test.yaml +0 -36
  174. data/.github/workflows/macos-test.yaml +0 -30
  175. data/.github/workflows/windows-test.yaml +0 -46
  176. data/.gitlab-ci.yml +0 -103
  177. data/lib/fluent/plugin/file_wrapper.rb +0 -187
  178. data/test/plugin/test_file_wrapper.rb +0 -126
  179. data/test/test_logger_initializer.rb +0 -46
@@ -16,6 +16,7 @@
16
16
 
17
17
  require 'fileutils'
18
18
  require 'open3'
19
+ require 'pathname'
19
20
 
20
21
  require 'fluent/config'
21
22
  require 'fluent/counter'
@@ -31,12 +32,6 @@ require 'fluent/variable_store'
31
32
  require 'serverengine'
32
33
 
33
34
  if Fluent.windows?
34
- require 'windows/library'
35
- require 'windows/synchronize'
36
- require 'windows/system_info'
37
- include Windows::Library
38
- include Windows::Synchronize
39
- include Windows::SystemInfo
40
35
  require 'win32/ipc'
41
36
  require 'win32/event'
42
37
  end
@@ -49,6 +44,9 @@ module Fluent
49
44
  @rpc_server = nil
50
45
  @counter = nil
51
46
 
47
+ @fluentd_lock_dir = Dir.mktmpdir("fluentd-lock-")
48
+ ENV['FLUENTD_LOCK_DIR'] = @fluentd_lock_dir
49
+
52
50
  if config[:rpc_endpoint]
53
51
  @rpc_endpoint = config[:rpc_endpoint]
54
52
  @enable_get_dump = config[:enable_get_dump]
@@ -68,9 +66,8 @@ module Fluent
68
66
  if config[:disable_shared_socket]
69
67
  $log.info "shared socket for multiple workers is disabled"
70
68
  else
71
- socket_manager_path = ServerEngine::SocketManager::Server.generate_path
72
- ServerEngine::SocketManager::Server.open(socket_manager_path)
73
- ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = socket_manager_path.to_s
69
+ server = ServerEngine::SocketManager::Server.open
70
+ ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = server.path.to_s
74
71
  end
75
72
  end
76
73
 
@@ -78,21 +75,27 @@ module Fluent
78
75
  stop_windows_event_thread if Fluent.windows?
79
76
  stop_rpc_server if @rpc_endpoint
80
77
  stop_counter_server if @counter
78
+ cleanup_lock_dir
81
79
  Fluent::Supervisor.cleanup_resources
82
80
  end
83
81
 
82
+ def cleanup_lock_dir
83
+ FileUtils.rm(Dir.glob(File.join(@fluentd_lock_dir, "fluentd-*.lock")))
84
+ FileUtils.rmdir(@fluentd_lock_dir)
85
+ end
86
+
84
87
  def run_rpc_server
85
88
  @rpc_server = RPC::Server.new(@rpc_endpoint, $log)
86
89
 
87
90
  # built-in RPC for signals
88
91
  @rpc_server.mount_proc('/api/processes.interruptWorkers') { |req, res|
89
92
  $log.debug "fluentd RPC got /api/processes.interruptWorkers request"
90
- Process.kill :INT, $$
93
+ Process.kill :INT, Process.pid
91
94
  nil
92
95
  }
93
96
  @rpc_server.mount_proc('/api/processes.killWorkers') { |req, res|
94
97
  $log.debug "fluentd RPC got /api/processes.killWorkers request"
95
- Process.kill :TERM, $$
98
+ Process.kill :TERM, Process.pid
96
99
  nil
97
100
  }
98
101
  @rpc_server.mount_proc('/api/processes.flushBuffersAndKillWorkers') { |req, res|
@@ -101,8 +104,8 @@ module Fluent
101
104
  supervisor_sigusr1_handler
102
105
  stop(true)
103
106
  else
104
- Process.kill :USR1, $$
105
- Process.kill :TERM, $$
107
+ Process.kill :USR1, Process.pid
108
+ Process.kill :TERM, Process.pid
106
109
  end
107
110
  nil
108
111
  }
@@ -111,7 +114,7 @@ module Fluent
111
114
  if Fluent.windows?
112
115
  supervisor_sigusr1_handler
113
116
  else
114
- Process.kill :USR1, $$
117
+ Process.kill :USR1, Process.pid
115
118
  end
116
119
  nil
117
120
  }
@@ -121,7 +124,7 @@ module Fluent
121
124
  # restart worker with auto restarting by killing
122
125
  kill_worker
123
126
  else
124
- Process.kill :HUP, $$
127
+ Process.kill :HUP, Process.pid
125
128
  end
126
129
  nil
127
130
  }
@@ -137,7 +140,7 @@ module Fluent
137
140
  if Fluent.windows?
138
141
  supervisor_sigusr2_handler
139
142
  else
140
- Process.kill :USR2, $$
143
+ Process.kill :USR2, Process.pid
141
144
  end
142
145
 
143
146
  nil
@@ -209,50 +212,57 @@ module Fluent
209
212
  def install_windows_event_handler
210
213
  return unless Fluent.windows?
211
214
 
212
- @pid_signame = "fluentd_#{$$}"
215
+ @pid_signame = "fluentd_#{Process.pid}"
213
216
  @signame = config[:signame]
214
217
 
215
218
  Thread.new do
216
219
  ipc = Win32::Ipc.new(nil)
217
220
  events = [
218
- Win32::Event.new("#{@pid_signame}_STOP_EVENT_THREAD"),
219
- Win32::Event.new("#{@pid_signame}"),
220
- Win32::Event.new("#{@pid_signame}_HUP"),
221
- Win32::Event.new("#{@pid_signame}_USR1"),
222
- Win32::Event.new("#{@pid_signame}_USR2"),
221
+ {win32_event: Win32::Event.new("#{@pid_signame}_STOP_EVENT_THREAD"), action: :stop_event_thread},
222
+ {win32_event: Win32::Event.new("#{@pid_signame}"), action: :stop},
223
+ {win32_event: Win32::Event.new("#{@pid_signame}_HUP"), action: :hup},
224
+ {win32_event: Win32::Event.new("#{@pid_signame}_USR1"), action: :usr1},
225
+ {win32_event: Win32::Event.new("#{@pid_signame}_USR2"), action: :usr2},
226
+ {win32_event: Win32::Event.new("#{@pid_signame}_CONT"), action: :cont},
223
227
  ]
224
228
  if @signame
225
229
  signame_events = [
226
- Win32::Event.new("#{@signame}"),
227
- Win32::Event.new("#{@signame}_HUP"),
228
- Win32::Event.new("#{@signame}_USR1"),
229
- Win32::Event.new("#{@signame}_USR2"),
230
+ {win32_event: Win32::Event.new("#{@signame}"), action: :stop},
231
+ {win32_event: Win32::Event.new("#{@signame}_HUP"), action: :hup},
232
+ {win32_event: Win32::Event.new("#{@signame}_USR1"), action: :usr1},
233
+ {win32_event: Win32::Event.new("#{@signame}_USR2"), action: :usr2},
234
+ {win32_event: Win32::Event.new("#{@signame}_CONT"), action: :cont},
230
235
  ]
231
236
  events.concat(signame_events)
232
237
  end
233
238
  begin
234
239
  loop do
235
- idx = ipc.wait_any(events, Windows::Synchronize::INFINITE)
236
- if idx > 0 && idx <= events.length
237
- $log.debug("Got Win32 event \"#{events[idx - 1].name}\"")
240
+ infinite = 0xFFFFFFFF
241
+ ipc_idx = ipc.wait_any(events.map {|e| e[:win32_event]}, infinite)
242
+ event_idx = ipc_idx - 1
243
+
244
+ if event_idx >= 0 && event_idx < events.length
245
+ $log.debug("Got Win32 event \"#{events[event_idx][:win32_event].name}\"")
238
246
  else
239
- $log.warn("Unexpected reutrn value of Win32::Ipc#wait_any: #{idx}")
247
+ $log.warn("Unexpected return value of Win32::Ipc#wait_any: #{ipc_idx}")
240
248
  end
241
- case idx
242
- when 2, 6
249
+ case events[event_idx][:action]
250
+ when :stop
243
251
  stop(true)
244
- when 3, 7
252
+ when :hup
245
253
  supervisor_sighup_handler
246
- when 4, 8
254
+ when :usr1
247
255
  supervisor_sigusr1_handler
248
- when 5, 9
256
+ when :usr2
249
257
  supervisor_sigusr2_handler
250
- when 1
258
+ when :cont
259
+ supervisor_dump_handler_for_windows
260
+ when :stop_event_thread
251
261
  break
252
262
  end
253
263
  end
254
264
  ensure
255
- events.each { |event| event.close }
265
+ events.each { |event| event[:win32_event].close }
256
266
  end
257
267
  end
258
268
  end
@@ -302,6 +312,26 @@ module Fluent
302
312
  $log.error "Failed to reload config file: #{e}"
303
313
  end
304
314
 
315
+ def supervisor_dump_handler_for_windows
316
+ # As for UNIX-like, SIGCONT signal to each process makes the process output its dump-file,
317
+ # and it is implemented before the implementation of the function for Windows.
318
+ # It is possible to trap SIGCONT and handle it here also on UNIX-like,
319
+ # but for backward compatibility, this handler is currently for a Windows-only.
320
+ raise "[BUG] This function is for Windows ONLY." unless Fluent.windows?
321
+
322
+ Thread.new do
323
+ begin
324
+ FluentSigdump.dump_windows
325
+ rescue => e
326
+ $log.error "failed to dump: #{e}"
327
+ end
328
+ end
329
+
330
+ send_signal_to_workers(:CONT)
331
+ rescue => e
332
+ $log.error "failed to dump: #{e}"
333
+ end
334
+
305
335
  def kill_worker
306
336
  if config[:worker_pid]
307
337
  pids = config[:worker_pid].clone
@@ -324,14 +354,18 @@ module Fluent
324
354
  { conf: @fluentd_conf }
325
355
  end
326
356
 
357
+ def dump
358
+ super unless @stop
359
+ end
360
+
327
361
  private
328
362
 
329
363
  def reopen_log
330
- if (log = config[:logger_initializer])
364
+ if $log
331
365
  # Creating new thread due to mutex can't lock
332
366
  # in main thread during trap context
333
367
  Thread.new do
334
- log.reopen!
368
+ $log.reopen!
335
369
  end
336
370
  end
337
371
  end
@@ -358,6 +392,14 @@ module Fluent
358
392
  restart(true)
359
393
  when :USR2
360
394
  reload
395
+ when :CONT
396
+ dump_all_windows_workers
397
+ end
398
+ end
399
+
400
+ def dump_all_windows_workers
401
+ @monitors.each do |m|
402
+ m.send_command("DUMP\n")
361
403
  end
362
404
  end
363
405
  end
@@ -374,46 +416,14 @@ module Fluent
374
416
  def after_start
375
417
  (config[:worker_pid] ||= {})[@worker_id] = @pm.pid
376
418
  end
419
+
420
+ def dump
421
+ super unless @stop
422
+ end
377
423
  end
378
424
 
379
425
  class Supervisor
380
- def self.load_config(path, params = {})
381
- pre_loadtime = 0
382
- pre_loadtime = params['pre_loadtime'].to_i if params['pre_loadtime']
383
- pre_config_mtime = nil
384
- pre_config_mtime = params['pre_config_mtime'] if params['pre_config_mtime']
385
- config_mtime = File.mtime(path)
386
-
387
- # reuse previous config if last load time is within 5 seconds and mtime of the config file is not changed
388
- if (Time.now - Time.at(pre_loadtime) < 5) && (config_mtime == pre_config_mtime)
389
- return params['pre_conf']
390
- end
391
-
392
- log_level = params['log_level']
393
- suppress_repeated_stacktrace = params['suppress_repeated_stacktrace']
394
- ignore_repeated_log_interval = params['ignore_repeated_log_interval']
395
- ignore_same_log_interval = params['ignore_same_log_interval']
396
-
397
- log_path = params['log_path']
398
- chuser = params['chuser']
399
- chgroup = params['chgroup']
400
- log_rotate_age = params['log_rotate_age']
401
- log_rotate_size = params['log_rotate_size']
402
-
403
- log_opts = {suppress_repeated_stacktrace: suppress_repeated_stacktrace, ignore_repeated_log_interval: ignore_repeated_log_interval,
404
- ignore_same_log_interval: ignore_same_log_interval}
405
- logger_initializer = Supervisor::LoggerInitializer.new(
406
- log_path, log_level, chuser, chgroup, log_opts,
407
- log_rotate_age: log_rotate_age,
408
- log_rotate_size: log_rotate_size
409
- )
410
- # this #init sets initialized logger to $log
411
- logger_initializer.init(:supervisor, 0)
412
- logger_initializer.apply_options(format: params['log_format'], time_format: params['log_time_format'])
413
- logger = $log
414
-
415
- command_sender = Fluent.windows? ? "pipe" : "signal"
416
-
426
+ def self.serverengine_config(params = {})
417
427
  # ServerEngine's "daemonize" option is boolean, and path of pid file is brought by "pid_path"
418
428
  pid_path = params['daemonize']
419
429
  daemonize = !!params['daemonize']
@@ -429,17 +439,12 @@ module Fluent
429
439
  unrecoverable_exit_codes: [2],
430
440
  stop_immediately_at_unrecoverable_exit: true,
431
441
  root_dir: params['root_dir'],
432
- logger: logger,
433
- log: logger.out,
434
- log_path: log_path,
435
- log_level: log_level,
436
- logger_initializer: logger_initializer,
437
- chuser: chuser,
438
- chgroup: chgroup,
439
- chumask: 0,
440
- suppress_repeated_stacktrace: suppress_repeated_stacktrace,
441
- ignore_repeated_log_interval: ignore_repeated_log_interval,
442
- ignore_same_log_interval: ignore_same_log_interval,
442
+ logger: $log,
443
+ log: $log.out,
444
+ log_level: params['log_level'],
445
+ chuser: params['chuser'],
446
+ chgroup: params['chgroup'],
447
+ chumask: params['chumask'],
443
448
  daemonize: daemonize,
444
449
  rpc_endpoint: params['rpc_endpoint'],
445
450
  counter_server: params['counter_server'],
@@ -448,112 +453,22 @@ module Fluent
448
453
  File.join(File.dirname(__FILE__), 'daemon.rb'),
449
454
  ServerModule.name,
450
455
  WorkerModule.name,
451
- path,
452
456
  JSON.dump(params)],
453
- command_sender: command_sender,
457
+ command_sender: Fluent.windows? ? "pipe" : "signal",
458
+ config_path: params['fluentd_conf_path'],
454
459
  fluentd_conf: params['fluentd_conf'],
455
460
  conf_encoding: params['conf_encoding'],
456
461
  inline_config: params['inline_config'],
457
- config_path: path,
458
462
  main_cmd: params['main_cmd'],
459
463
  signame: params['signame'],
460
- disable_shared_socket: params['disable_shared_socket']
464
+ disable_shared_socket: params['disable_shared_socket'],
465
+ restart_worker_interval: params['restart_worker_interval'],
461
466
  }
462
- if daemonize
463
- se_config[:pid_path] = pid_path
464
- end
465
- pre_params = params.dup
466
- params['pre_loadtime'] = Time.now.to_i
467
- params['pre_config_mtime'] = config_mtime
468
- params['pre_conf'] = se_config
469
- # prevent pre_conf from being too big by reloading many times.
470
- pre_params['pre_conf'] = nil
471
- params['pre_conf'][:windows_daemon_cmdline][5] = JSON.dump(pre_params)
467
+ se_config[:pid_path] = pid_path if daemonize
472
468
 
473
469
  se_config
474
470
  end
475
471
 
476
- class LoggerInitializer
477
- def initialize(path, level, chuser, chgroup, opts, log_rotate_age: nil, log_rotate_size: nil)
478
- @path = path
479
- @level = level
480
- @chuser = chuser
481
- @chgroup = chgroup
482
- @opts = opts
483
- @log_rotate_age = log_rotate_age
484
- @log_rotate_size = log_rotate_size
485
- end
486
-
487
- def worker_id_suffixed_path(worker_id, path)
488
- require 'pathname'
489
-
490
- Pathname(path).sub_ext("-#{worker_id}#{Pathname(path).extname}").to_s
491
- end
492
-
493
- def init(process_type, worker_id)
494
- @opts[:process_type] = process_type
495
- @opts[:worker_id] = worker_id
496
-
497
- if @path && @path != "-"
498
- unless File.exist?(@path)
499
- FileUtils.mkdir_p(File.dirname(@path))
500
- end
501
-
502
- @logdev = if @log_rotate_age || @log_rotate_size
503
- Fluent::LogDeviceIO.new(Fluent.windows? ?
504
- worker_id_suffixed_path(worker_id, @path) : @path,
505
- shift_age: @log_rotate_age, shift_size: @log_rotate_size)
506
- else
507
- File.open(@path, "a")
508
- end
509
- if @chuser || @chgroup
510
- chuid = @chuser ? ServerEngine::Privilege.get_etc_passwd(@chuser).uid : nil
511
- chgid = @chgroup ? ServerEngine::Privilege.get_etc_group(@chgroup).gid : nil
512
- File.chown(chuid, chgid, @path)
513
- end
514
- else
515
- @logdev = STDOUT
516
- end
517
-
518
- dl_opts = {}
519
- # subtract 1 to match serverengine daemon logger side logging severity.
520
- dl_opts[:log_level] = @level - 1
521
- dl_opts[:log_rotate_age] = @log_rotate_age if @log_rotate_age
522
- dl_opts[:log_rotate_size] = @log_rotate_size if @log_rotate_size
523
- logger = ServerEngine::DaemonLogger.new(@logdev, dl_opts)
524
- $log = Fluent::Log.new(logger, @opts)
525
- $log.enable_color(false) if @path
526
- $log.enable_debug if @level <= Fluent::Log::LEVEL_DEBUG
527
- end
528
-
529
- def stdout?
530
- @logdev == STDOUT
531
- end
532
-
533
- def reopen!
534
- if @path && @path != "-"
535
- @logdev.reopen(@path, "a")
536
- end
537
- self
538
- end
539
-
540
- def apply_options(format: nil, time_format: nil, log_dir_perm: nil, ignore_repeated_log_interval: nil, ignore_same_log_interval: nil)
541
- $log.format = format if format
542
- $log.time_format = time_format if time_format
543
- $log.ignore_repeated_log_interval = ignore_repeated_log_interval if ignore_repeated_log_interval
544
- $log.ignore_same_log_interval = ignore_same_log_interval if ignore_same_log_interval
545
-
546
- if @path && log_dir_perm
547
- File.chmod(log_dir_perm || 0755, File.dirname(@path))
548
- end
549
- end
550
-
551
- def level=(level)
552
- @level = level
553
- $log.level = level
554
- end
555
- end
556
-
557
472
  def self.default_options
558
473
  {
559
474
  config_path: Fluent::DEFAULT_CONFIG_PATH,
@@ -565,18 +480,22 @@ module Fluent
565
480
  setup_path: nil,
566
481
  chuser: nil,
567
482
  chgroup: nil,
483
+ chumask: "0",
568
484
  root_dir: nil,
569
485
  suppress_interval: 0,
570
486
  suppress_repeated_stacktrace: true,
571
487
  ignore_repeated_log_interval: nil,
572
488
  without_source: nil,
489
+ enable_input_metrics: nil,
490
+ enable_size_metrics: nil,
573
491
  use_v1_config: true,
574
492
  strict_config_value: nil,
575
493
  supervise: true,
576
494
  standalone_worker: false,
577
495
  signame: nil,
578
496
  conf_encoding: 'utf-8',
579
- disable_shared_socket: nil
497
+ disable_shared_socket: nil,
498
+ config_file_type: :guess,
580
499
  }
581
500
  end
582
501
 
@@ -588,7 +507,11 @@ module Fluent
588
507
  end
589
508
  end
590
509
 
591
- def initialize(opt)
510
+ def initialize(cl_opt)
511
+ @cl_opt = cl_opt
512
+ opt = self.class.default_options.merge(cl_opt)
513
+
514
+ @config_file_type = opt[:config_file_type]
592
515
  @daemonize = opt[:daemonize]
593
516
  @standalone_worker= opt[:standalone_worker]
594
517
  @config_path = opt[:config_path]
@@ -601,34 +524,19 @@ module Fluent
601
524
  @plugin_dirs = opt[:plugin_dirs]
602
525
  @chgroup = opt[:chgroup]
603
526
  @chuser = opt[:chuser]
527
+ @chumask = opt[:chumask]
528
+ @signame = opt[:signame]
604
529
 
530
+ # TODO: `@log_rotate_age` and `@log_rotate_size` should be removed
531
+ # since it should be merged with SystemConfig in `build_system_config()`.
532
+ # We should always use `system_config.log.rotate_age` and `system_config.log.rotate_size`.
533
+ # However, currently, there is a bug that `system_config.log` parameters
534
+ # are not in `Fluent::SystemConfig::SYSTEM_CONFIG_PARAMETERS`, and these
535
+ # parameters are not merged in `build_system_config()`.
536
+ # Until we fix the bug of `Fluent::SystemConfig`, we need to use these instance variables.
605
537
  @log_rotate_age = opt[:log_rotate_age]
606
538
  @log_rotate_size = opt[:log_rotate_size]
607
- @signame = opt[:signame]
608
539
 
609
- @cl_opt = opt
610
- @conf = nil
611
- # parse configuration immediately to initialize logger in early stage
612
- if @config_path and File.exist?(@config_path)
613
- @conf = Fluent::Config.build(config_path: @config_path,
614
- encoding: @conf_encoding ? @conf_encoding : 'utf-8',
615
- additional_config: @inline_config ? @inline_config : nil,
616
- use_v1_config: !!@use_v1_config)
617
- @system_config = build_system_config(@conf)
618
- if @system_config.log
619
- @log_rotate_age ||= @system_config.log.rotate_age
620
- @log_rotate_size ||= @system_config.log.rotate_size
621
- end
622
- @conf = nil
623
- end
624
-
625
- log_opts = {suppress_repeated_stacktrace: opt[:suppress_repeated_stacktrace], ignore_repeated_log_interval: opt[:ignore_repeated_log_interval],
626
- ignore_same_log_interval: opt[:ignore_same_log_interval]}
627
- @log = LoggerInitializer.new(
628
- @log_path, opt[:log_level], @chuser, @chgroup, log_opts,
629
- log_rotate_age: @log_rotate_age,
630
- log_rotate_size: @log_rotate_size
631
- )
632
540
  @finished = false
633
541
  end
634
542
 
@@ -649,7 +557,7 @@ module Fluent
649
557
  end
650
558
  else
651
559
  begin
652
- FileUtils.mkdir_p(root_dir, mode: @system_config.dir_permission || 0755)
560
+ FileUtils.mkdir_p(root_dir, mode: @system_config.dir_permission || Fluent::DEFAULT_DIR_PERMISSION)
653
561
  rescue => e
654
562
  raise Fluent::InvalidRootDirectory, "failed to create root directory:#{root_dir}, #{e.inspect}"
655
563
  end
@@ -686,12 +594,6 @@ module Fluent
686
594
  end
687
595
 
688
596
  def run_worker
689
- begin
690
- require 'sigdump/setup'
691
- rescue Exception
692
- # ignore LoadError and others (related with signals): it may raise these errors in Windows
693
- end
694
-
695
597
  Process.setproctitle("worker:#{@system_config.process_name}") if @process_name
696
598
 
697
599
  if @standalone_worker && @system_config.workers != 1
@@ -707,7 +609,7 @@ module Fluent
707
609
  create_socket_manager if @standalone_worker
708
610
  if @standalone_worker
709
611
  ServerEngine::Privilege.change(@chuser, @chgroup)
710
- File.umask(0)
612
+ File.umask(@chumask.to_i(8))
711
613
  end
712
614
  MessagePackFactory.init(enable_time_support: @system_config.enable_msgpack_time_support)
713
615
  Fluent::Engine.init(@system_config)
@@ -719,17 +621,7 @@ module Fluent
719
621
  end
720
622
 
721
623
  def configure(supervisor: false)
722
- if supervisor
723
- @log.init(:supervisor, 0)
724
- else
725
- worker_id = ENV['SERVERENGINE_WORKER_ID'].to_i
726
- process_type = case
727
- when @standalone_worker then :standalone
728
- when worker_id == 0 then :worker0
729
- else :workers
730
- end
731
- @log.init(process_type, worker_id)
732
- end
624
+ setup_global_logger(supervisor: supervisor)
733
625
 
734
626
  if @show_plugin_config
735
627
  show_plugin_config
@@ -739,17 +631,14 @@ module Fluent
739
631
  $log.warn('the value "-" for `inline_config` is deprecated. See https://github.com/fluent/fluentd/issues/2711')
740
632
  @inline_config = STDIN.read
741
633
  end
742
- @conf = Fluent::Config.build(config_path: @config_path, encoding: @conf_encoding, additional_config: @inline_config, use_v1_config: @use_v1_config)
743
- @system_config = build_system_config(@conf)
744
-
745
- @log.level = @system_config.log_level
746
- @log.apply_options(
747
- format: @system_config.log.format,
748
- time_format: @system_config.log.time_format,
749
- log_dir_perm: @system_config.dir_permission,
750
- ignore_repeated_log_interval: @system_config.ignore_repeated_log_interval,
751
- ignore_same_log_interval: @system_config.ignore_same_log_interval
634
+ @conf = Fluent::Config.build(
635
+ config_path: @config_path,
636
+ encoding: @conf_encoding,
637
+ additional_config: @inline_config,
638
+ use_v1_config: @use_v1_config,
639
+ type: @config_file_type,
752
640
  )
641
+ @system_config = build_system_config(@conf)
753
642
 
754
643
  $log.info :supervisor, 'parsing config file is succeeded', path: @config_path
755
644
 
@@ -774,10 +663,93 @@ module Fluent
774
663
 
775
664
  private
776
665
 
666
+ def setup_global_logger(supervisor: false)
667
+ if supervisor
668
+ worker_id = 0
669
+ process_type = :supervisor
670
+ else
671
+ worker_id = ENV['SERVERENGINE_WORKER_ID'].to_i
672
+ process_type = case
673
+ when @standalone_worker then :standalone
674
+ when worker_id == 0 then :worker0
675
+ else :workers
676
+ end
677
+ end
678
+
679
+ # Parse configuration immediately to initialize logger in early stage.
680
+ # Since we can't confirm the log messages in this parsing process,
681
+ # we must parse the config again after initializing logger.
682
+ conf = Fluent::Config.build(
683
+ config_path: @config_path,
684
+ encoding: @conf_encoding,
685
+ additional_config: @inline_config,
686
+ use_v1_config: @use_v1_config,
687
+ type: @config_file_type,
688
+ )
689
+ system_config = build_system_config(conf)
690
+
691
+ # TODO: we should remove this logic. This merging process should be done
692
+ # in `build_system_config()`.
693
+ @log_rotate_age ||= system_config.log.rotate_age
694
+ @log_rotate_size ||= system_config.log.rotate_size
695
+
696
+ rotate = @log_rotate_age || @log_rotate_size
697
+ actual_log_path = @log_path
698
+
699
+ # We need to prepare a unique path for each worker since Windows locks files.
700
+ if Fluent.windows? && rotate && @log_path && @log_path != "-"
701
+ actual_log_path = Fluent::Log.per_process_path(@log_path, process_type, worker_id)
702
+ end
703
+
704
+ if actual_log_path && actual_log_path != "-"
705
+ FileUtils.mkdir_p(File.dirname(actual_log_path)) unless File.exist?(actual_log_path)
706
+ if rotate
707
+ logdev = Fluent::LogDeviceIO.new(
708
+ actual_log_path,
709
+ shift_age: @log_rotate_age,
710
+ shift_size: @log_rotate_size,
711
+ )
712
+ else
713
+ logdev = File.open(actual_log_path, "a")
714
+ end
715
+
716
+ if @chuser || @chgroup
717
+ chuid = @chuser ? ServerEngine::Privilege.get_etc_passwd(@chuser).uid : nil
718
+ chgid = @chgroup ? ServerEngine::Privilege.get_etc_group(@chgroup).gid : nil
719
+ File.chown(chuid, chgid, actual_log_path)
720
+ end
721
+
722
+ if system_config.dir_permission
723
+ File.chmod(system_config.dir_permission || Fluent::DEFAULT_DIR_PERMISSION, File.dirname(actual_log_path))
724
+ end
725
+ else
726
+ logdev = STDOUT
727
+ end
728
+
729
+ $log = Fluent::Log.new(
730
+ # log_level: subtract 1 to match serverengine daemon logger side logging severity.
731
+ ServerEngine::DaemonLogger.new(logdev, log_level: system_config.log_level - 1),
732
+ path: actual_log_path,
733
+ process_type: process_type,
734
+ worker_id: worker_id,
735
+ format: system_config.log.format,
736
+ time_format: system_config.log.time_format,
737
+ suppress_repeated_stacktrace: system_config.suppress_repeated_stacktrace,
738
+ ignore_repeated_log_interval: system_config.ignore_repeated_log_interval,
739
+ ignore_same_log_interval: system_config.ignore_same_log_interval,
740
+ )
741
+ $log.enable_color(false) if actual_log_path
742
+ $log.enable_debug if system_config.log_level <= Fluent::Log::LEVEL_DEBUG
743
+
744
+ $log.info "init #{process_type} logger",
745
+ path: actual_log_path,
746
+ rotate_age: @log_rotate_age,
747
+ rotate_size: @log_rotate_size
748
+ end
749
+
777
750
  def create_socket_manager
778
- socket_manager_path = ServerEngine::SocketManager::Server.generate_path
779
- ServerEngine::SocketManager::Server.open(socket_manager_path)
780
- ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = socket_manager_path.to_s
751
+ server = ServerEngine::SocketManager::Server.open
752
+ ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = server.path.to_s
781
753
  end
782
754
 
783
755
  def show_plugin_config
@@ -797,32 +769,30 @@ module Fluent
797
769
  'main_cmd' => fluentd_spawn_cmd,
798
770
  'daemonize' => @daemonize,
799
771
  'inline_config' => @inline_config,
800
- 'log_path' => @log_path,
801
- 'log_rotate_age' => @log_rotate_age,
802
- 'log_rotate_size' => @log_rotate_size,
803
772
  'chuser' => @chuser,
804
773
  'chgroup' => @chgroup,
774
+ 'fluentd_conf_path' => @config_path,
775
+ 'fluentd_conf' => @conf.to_s,
805
776
  'use_v1_config' => @use_v1_config,
806
777
  'conf_encoding' => @conf_encoding,
807
778
  'signame' => @signame,
808
- 'fluentd_conf' => @conf.to_s,
809
779
 
810
780
  'workers' => @system_config.workers,
811
781
  'root_dir' => @system_config.root_dir,
812
782
  'log_level' => @system_config.log_level,
813
- 'suppress_repeated_stacktrace' => @system_config.suppress_repeated_stacktrace,
814
- 'ignore_repeated_log_interval' => @system_config.ignore_repeated_log_interval,
815
783
  'rpc_endpoint' => @system_config.rpc_endpoint,
816
784
  'enable_get_dump' => @system_config.enable_get_dump,
817
785
  'counter_server' => @system_config.counter_server,
818
- 'log_format' => @system_config.log.format,
819
- 'log_time_format' => @system_config.log.time_format,
820
- 'disable_shared_socket' => @system_config.disable_shared_socket
786
+ 'disable_shared_socket' => @system_config.disable_shared_socket,
787
+ 'restart_worker_interval' => @system_config.restart_worker_interval,
821
788
  }
822
789
 
823
- se = ServerEngine.create(ServerModule, WorkerModule){
824
- Fluent::Supervisor.load_config(@config_path, params)
790
+ se = ServerEngine.create(ServerModule, WorkerModule) {
791
+ # Note: This is called only at the initialization of ServerEngine, since
792
+ # Fluentd overwrites all related SIGNAL(HUP,USR1,USR2) and have own reloading feature.
793
+ Fluent::Supervisor.serverengine_config(params)
825
794
  }
795
+
826
796
  se.run
827
797
  end
828
798
 
@@ -864,6 +834,10 @@ module Fluent
864
834
  trap :USR2 do
865
835
  reload_config
866
836
  end
837
+
838
+ trap :CONT do
839
+ dump_non_windows
840
+ end
867
841
  end
868
842
  end
869
843
 
@@ -891,6 +865,9 @@ module Fluent
891
865
  when "RELOAD"
892
866
  $log.debug "fluentd main process get #{cmd} command"
893
867
  reload_config
868
+ when "DUMP"
869
+ $log.debug "fluentd main process get #{cmd} command"
870
+ dump_windows
894
871
  else
895
872
  $log.warn "fluentd main process get unknown command [#{cmd}]"
896
873
  end
@@ -905,7 +882,7 @@ module Fluent
905
882
  begin
906
883
  $log.debug "fluentd main process get SIGUSR1"
907
884
  $log.info "force flushing buffered events"
908
- @log.reopen!
885
+ $log.reopen!
909
886
  Fluent::Engine.flush!
910
887
  $log.debug "flushing thread: flushed"
911
888
  rescue Exception => e
@@ -924,6 +901,7 @@ module Fluent
924
901
  encoding: @conf_encoding,
925
902
  additional_config: @inline_config,
926
903
  use_v1_config: @use_v1_config,
904
+ type: @config_file_type,
927
905
  )
928
906
 
929
907
  Fluent::VariableStore.try_to_reset do
@@ -940,9 +918,27 @@ module Fluent
940
918
  end
941
919
  end
942
920
 
921
+ def dump_non_windows
922
+ begin
923
+ Sigdump.dump unless @finished
924
+ rescue => e
925
+ $log.error("failed to dump: #{e}")
926
+ end
927
+ end
928
+
929
+ def dump_windows
930
+ Thread.new do
931
+ begin
932
+ FluentSigdump.dump_windows
933
+ rescue => e
934
+ $log.error("failed to dump: #{e}")
935
+ end
936
+ end
937
+ end
938
+
943
939
  def logging_with_console_output
944
940
  yield $log
945
- unless @log.stdout?
941
+ unless $log.stdout?
946
942
  logger = ServerEngine::DaemonLogger.new(STDOUT)
947
943
  log = Fluent::Log.new(logger)
948
944
  log.level = @system_config.log_level
@@ -998,15 +994,15 @@ module Fluent
998
994
 
999
995
  def build_system_config(conf)
1000
996
  system_config = SystemConfig.create(conf, @cl_opt[:strict_config_value])
997
+ # Prefer the options explicitly specified in the command line
998
+ #
999
+ # TODO: There is a bug that `system_config.log.rotate_age/rotate_size` are
1000
+ # not merged with the command line options since they are not in
1001
+ # `SYSTEM_CONFIG_PARAMETERS`.
1002
+ # We have to fix this bug.
1001
1003
  opt = {}
1002
1004
  Fluent::SystemConfig::SYSTEM_CONFIG_PARAMETERS.each do |param|
1003
1005
  if @cl_opt.key?(param) && !@cl_opt[param].nil?
1004
- if param == :log_level && @cl_opt[:log_level] == Fluent::Log::LEVEL_INFO
1005
- # info level can't be specified via command line option.
1006
- # log_level is info here, it is default value and <system>'s log_level should be applied if exists.
1007
- next
1008
- end
1009
-
1010
1006
  opt[param] = @cl_opt[param]
1011
1007
  end
1012
1008
  end
@@ -1034,6 +1030,11 @@ module Fluent
1034
1030
  fluentd_spawn_cmd << '-Eascii-8bit:ascii-8bit'
1035
1031
  end
1036
1032
 
1033
+ if @system_config.enable_jit
1034
+ $log.info "enable Ruby JIT for workers (--jit)"
1035
+ fluentd_spawn_cmd << '--jit'
1036
+ end
1037
+
1037
1038
  # Adding `-h` so that it can avoid ruby's command blocking
1038
1039
  # e.g. `ruby -Eascii-8bit:ascii-8bit` will block. but `ruby -Eascii-8bit:ascii-8bit -h` won't.
1039
1040
  _, e, s = Open3.capture3(*fluentd_spawn_cmd, "-h")
@@ -1049,4 +1050,27 @@ module Fluent
1049
1050
  fluentd_spawn_cmd
1050
1051
  end
1051
1052
  end
1053
+
1054
+ module FluentSigdump
1055
+ def self.dump_windows
1056
+ raise "[BUG] WindowsSigdump::dump is for Windows ONLY." unless Fluent.windows?
1057
+
1058
+ # Sigdump outputs under `/tmp` dir without `SIGDUMP_PATH` specified,
1059
+ # but `/tmp` dir may not exist on Windows by default.
1060
+ # So use the systemroot-temp-dir instead.
1061
+ dump_filepath = ENV['SIGDUMP_PATH'].nil? || ENV['SIGDUMP_PATH'].empty? \
1062
+ ? "#{ENV['windir']}/Temp/fluentd-sigdump-#{Process.pid}.log"
1063
+ : get_path_with_pid(ENV['SIGDUMP_PATH'])
1064
+
1065
+ require 'sigdump'
1066
+ Sigdump.dump(dump_filepath)
1067
+
1068
+ $log.info "dump to #{dump_filepath}."
1069
+ end
1070
+
1071
+ def self.get_path_with_pid(raw_path)
1072
+ path = Pathname.new(raw_path)
1073
+ path.sub_ext("-#{Process.pid}#{path.extname}").to_s
1074
+ end
1075
+ end
1052
1076
  end