fluentd 0.14.2 → 0.14.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +77 -1131
  3. data/Rakefile +15 -0
  4. data/appveyor.yml +2 -2
  5. data/example/in_forward.conf +3 -0
  6. data/example/in_forward_client.conf +37 -0
  7. data/example/in_forward_shared_key.conf +15 -0
  8. data/example/in_forward_users.conf +24 -0
  9. data/example/multi_filters.conf +61 -0
  10. data/example/out_forward.conf +13 -13
  11. data/example/out_forward_client.conf +109 -0
  12. data/example/out_forward_shared_key.conf +36 -0
  13. data/example/out_forward_users.conf +65 -0
  14. data/example/{out_buffered_null.conf → out_null.conf} +10 -6
  15. data/example/secondary_file.conf +41 -0
  16. data/fluentd.gemspec +19 -16
  17. data/lib/fluent/agent.rb +5 -0
  18. data/lib/fluent/command/debug.rb +4 -4
  19. data/lib/fluent/compat/handle_tag_and_time_mixin.rb +2 -0
  20. data/lib/fluent/compat/output.rb +5 -2
  21. data/lib/fluent/config/configure_proxy.rb +26 -5
  22. data/lib/fluent/config/error.rb +3 -0
  23. data/lib/fluent/config/section.rb +15 -0
  24. data/lib/fluent/event_router.rb +77 -4
  25. data/lib/fluent/plugin/base.rb +12 -3
  26. data/lib/fluent/plugin/buffer.rb +5 -1
  27. data/lib/fluent/plugin/filter.rb +48 -6
  28. data/lib/fluent/plugin/filter_record_transformer.rb +3 -1
  29. data/lib/fluent/plugin/filter_stdout.rb +0 -4
  30. data/lib/fluent/plugin/in_debug_agent.rb +5 -5
  31. data/lib/fluent/plugin/in_dummy.rb +9 -1
  32. data/lib/fluent/plugin/in_forward.rb +330 -62
  33. data/lib/fluent/plugin/in_monitor_agent.rb +31 -77
  34. data/lib/fluent/plugin/in_tail.rb +76 -92
  35. data/lib/fluent/plugin/multi_output.rb +4 -0
  36. data/lib/fluent/plugin/out_forward.rb +328 -222
  37. data/lib/fluent/plugin/out_null.rb +37 -0
  38. data/lib/fluent/plugin/out_secondary_file.rb +128 -0
  39. data/lib/fluent/plugin/out_stdout.rb +38 -2
  40. data/lib/fluent/plugin/output.rb +29 -6
  41. data/lib/fluent/plugin/storage_local.rb +16 -0
  42. data/lib/fluent/plugin_helper/timer.rb +6 -1
  43. data/lib/fluent/root_agent.rb +4 -1
  44. data/lib/fluent/supervisor.rb +62 -9
  45. data/lib/fluent/test/base.rb +3 -0
  46. data/lib/fluent/test/driver/base.rb +5 -0
  47. data/lib/fluent/test/formatter_test.rb +2 -0
  48. data/lib/fluent/test/parser_test.rb +2 -0
  49. data/lib/fluent/test/startup_shutdown.rb +33 -0
  50. data/lib/fluent/version.rb +1 -1
  51. data/lib/fluent/winsvc.rb +1 -2
  52. data/test/compat/test_calls_super.rb +2 -0
  53. data/test/config/test_configurable.rb +88 -0
  54. data/test/config/test_types.rb +7 -3
  55. data/test/plugin/test_filter.rb +121 -23
  56. data/test/plugin/test_filter_record_transformer.rb +22 -6
  57. data/test/plugin/test_in_debug_agent.rb +2 -2
  58. data/test/plugin/test_in_forward.rb +920 -407
  59. data/test/plugin/test_in_monitor_agent.rb +333 -0
  60. data/test/plugin/test_in_tail.rb +686 -595
  61. data/test/plugin/test_out_forward.rb +150 -207
  62. data/test/plugin/test_out_null.rb +85 -9
  63. data/test/plugin/test_out_secondary_file.rb +432 -0
  64. data/test/plugin/test_out_stdout.rb +143 -45
  65. data/test/plugin/test_output.rb +53 -0
  66. data/test/plugin/test_output_as_buffered.rb +13 -0
  67. data/test/plugin/test_output_as_buffered_overflow.rb +3 -0
  68. data/test/plugin/test_output_as_buffered_retries.rb +11 -0
  69. data/test/plugin/test_output_as_buffered_secondary.rb +12 -0
  70. data/test/plugin/test_output_as_standard.rb +12 -0
  71. data/test/plugin_helper/test_compat_parameters.rb +2 -0
  72. data/test/plugin_helper/test_timer.rb +31 -0
  73. data/test/test_event_router.rb +87 -0
  74. data/test/test_filter.rb +48 -6
  75. data/test/test_log.rb +5 -2
  76. data/test/test_output.rb +41 -1
  77. data/test/test_plugin_classes.rb +17 -9
  78. data/test/test_root_agent.rb +188 -0
  79. metadata +62 -68
  80. data/lib/fluent/plugin/out_buffered_null.rb +0 -59
  81. data/lib/fluent/plugin/out_buffered_stdout.rb +0 -70
  82. data/test/plugin/test_out_buffered_null.rb +0 -79
  83. data/test/plugin/test_out_buffered_stdout.rb +0 -122
@@ -18,10 +18,47 @@ require 'fluent/plugin/output'
18
18
 
19
19
  module Fluent::Plugin
20
20
  class NullOutput < Output
21
+ # This plugin is for tests of non-buffered/buffered plugins
21
22
  Fluent::Plugin.register_output('null', self)
22
23
 
24
+ config_section :buffer do
25
+ config_set_default :chunk_keys, ['tag']
26
+ config_set_default :flush_at_shutdown, true
27
+ config_set_default :chunk_limit_size, 10 * 1024
28
+ end
29
+
30
+ def prefer_buffered_processing
31
+ false
32
+ end
33
+
34
+ def prefer_delayed_commit
35
+ @delayed
36
+ end
37
+
38
+ attr_accessor :feed_proc, :delayed
39
+
40
+ def initialize
41
+ super
42
+ @delayed = false
43
+ @feed_proc = nil
44
+ end
45
+
23
46
  def process(tag, es)
24
47
  # Do nothing
25
48
  end
49
+
50
+ def write(chunk)
51
+ if @feed_proc
52
+ @feed_proc.call(chunk)
53
+ end
54
+ end
55
+
56
+ def try_write(chunk)
57
+ if @feed_proc
58
+ @feed_proc.call(chunk)
59
+ end
60
+ # not to commit chunks for testing
61
+ # commit_write(chunk.unique_id)
62
+ end
26
63
  end
27
64
  end
@@ -0,0 +1,128 @@
1
+ #
2
+ # Fluentd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require "fileutils"
18
+ require "fluent/plugin/file_util"
19
+ require "fluent/plugin/output"
20
+ require "fluent/config/error"
21
+
22
+ module Fluent::Plugin
23
+ class SecondaryFileOutput < Output
24
+ Fluent::Plugin.register_output("secondary_file", self)
25
+
26
+ FILE_PERMISSION = 0644
27
+ DIR_PERMISSION = 0755
28
+ PLACEHOLDER_REGEX = /\${(tag(\[\d+\])?|[\w.@-]+)}/
29
+
30
+ desc "The directory path of the output file."
31
+ config_param :directory, :string
32
+ desc "The basename of the output file."
33
+ config_param :basename, :string, default: "dump.bin"
34
+ desc "The flushed chunk is appended to existence file or not."
35
+ config_param :append, :bool, default: false
36
+ config_param :compress, :enum, list: [:text, :gzip], default: :text
37
+
38
+ def configure(conf)
39
+ super
40
+
41
+ unless @as_secondary
42
+ raise Fluent::ConfigError, "This plugin can only be used in the <secondary> section"
43
+ end
44
+
45
+ if @basename.include?("/")
46
+ raise Fluent::ConfigError, "basename should not include `/`"
47
+ end
48
+
49
+ @path_without_suffix = File.join(@directory, @basename)
50
+ validate_compatible_with_primary_buffer!(@path_without_suffix)
51
+
52
+ @suffix = case @compress
53
+ when :text
54
+ ""
55
+ when :gzip
56
+ ".gz"
57
+ end
58
+
59
+ test_path = @path_without_suffix
60
+ unless Fluent::FileUtil.writable_p?(test_path)
61
+ raise Fluent::ConfigError, "out_secondary_file: `#{@directory}` should be writable"
62
+ end
63
+
64
+ @dir_perm = system_config.dir_permission || DIR_PERMISSION
65
+ @file_perm = system_config.file_permission || FILE_PERMISSION
66
+ end
67
+
68
+ def write(chunk)
69
+ path_without_suffix = extract_placeholders(@path_without_suffix, chunk.metadata)
70
+ path = generate_path(path_without_suffix)
71
+ FileUtils.mkdir_p File.dirname(path), mode: @dir_perm
72
+
73
+ case @compress
74
+ when :text
75
+ File.open(path, "ab", @file_perm) {|f|
76
+ f.flock(File::LOCK_EX)
77
+ chunk.write_to(f)
78
+ }
79
+ when :gzip
80
+ File.open(path, "ab", @file_perm) {|f|
81
+ f.flock(File::LOCK_EX)
82
+ gz = Zlib::GzipWriter.new(f)
83
+ chunk.write_to(gz)
84
+ gz.close
85
+ }
86
+ end
87
+
88
+ path
89
+ end
90
+
91
+ private
92
+
93
+ def validate_compatible_with_primary_buffer!(path_without_suffix)
94
+ placeholders = path_without_suffix.scan(PLACEHOLDER_REGEX).flat_map(&:first) # to trim suffix [\d+]
95
+
96
+ if !@chunk_key_time && has_time_format?(path_without_suffix)
97
+ raise Fluent::ConfigError, "out_secondary_file: basename or directory has an incompatible placeholder, remove time formats, like `%Y%m%d`, from basename or directory"
98
+ end
99
+
100
+ if !@chunk_key_tag && (ph = placeholders.find { |placeholder| placeholder.match(/tag(\[\d+\])?/) })
101
+ raise Fluent::ConfigError, "out_secondary_file: basename or directory has an incompatible placeholder #{ph}, remove tag placeholder, like `${tag}`, from basename or directory"
102
+ end
103
+
104
+ vars = placeholders.reject { |placeholder| placeholder.match(/tag(\[\d+\])?/) }
105
+
106
+ if ph = vars.find { |v| !@chunk_keys.include?(v) }
107
+ raise Fluent::ConfigError, "out_secondary_file: basename or directory has an incompatible placeholder #{ph}, remove variable placeholder, like `${varname}`, from basename or directory"
108
+ end
109
+ end
110
+
111
+ def has_time_format?(str)
112
+ str != Time.now.strftime(str)
113
+ end
114
+
115
+ def generate_path(path_without_suffix)
116
+ if @append
117
+ "#{path_without_suffix}#{@suffix}"
118
+ else
119
+ i = 0
120
+ loop do
121
+ path = "#{path_without_suffix}.#{i}#{@suffix}"
122
+ return path unless File.exist?(path)
123
+ i += 1
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -24,25 +24,61 @@ module Fluent::Plugin
24
24
 
25
25
  DEFAULT_FORMAT_TYPE = 'json'
26
26
 
27
+ config_section :buffer do
28
+ config_set_default :chunk_keys, ['tag']
29
+ config_set_default :flush_at_shutdown, true
30
+ config_set_default :chunk_limit_size, 10 * 1024
31
+ end
32
+
27
33
  config_section :format do
28
34
  config_set_default :@type, DEFAULT_FORMAT_TYPE
29
35
  end
30
36
 
37
+ def prefer_buffered_processing
38
+ false
39
+ end
40
+
41
+ def prefer_delayed_commit
42
+ @delayed
43
+ end
44
+
45
+ attr_accessor :delayed
46
+
47
+ def initialize
48
+ super
49
+ @delayed = false
50
+ end
51
+
31
52
  def configure(conf)
32
53
  if conf['output_type'] && !conf['format']
33
54
  conf['format'] = conf['output_type']
34
55
  end
35
56
  compat_parameters_convert(conf, :inject, :formatter)
57
+
36
58
  super
59
+
37
60
  @formatter = formatter_create(conf: conf.elements('format').first, default_type: DEFAULT_FORMAT_TYPE)
38
61
  end
39
62
 
40
63
  def process(tag, es)
41
64
  es.each {|time,record|
42
- r = inject_values_to_record(tag, time, record)
43
- $log.write "#{Time.at(time).localtime} #{tag}: #{@formatter.format(tag, time, r).chomp}\n"
65
+ $log.write(format(tag, time, record))
44
66
  }
45
67
  $log.flush
46
68
  end
69
+
70
+ def format(tag, time, record)
71
+ record = inject_values_to_record(tag, time, record)
72
+ "#{Time.at(time).localtime} #{tag}: #{@formatter.format(tag, time, record).chomp}\n"
73
+ end
74
+
75
+ def write(chunk)
76
+ chunk.write_to($log)
77
+ end
78
+
79
+ def try_write(chunk)
80
+ chunk.write_to($log)
81
+ commit_write(chunk.unique_id)
82
+ end
47
83
  end
48
84
  end
@@ -138,7 +138,7 @@ module Fluent
138
138
  end
139
139
  end
140
140
 
141
- attr_reader :as_secondary, :delayed_commit, :delayed_commit_timeout
141
+ attr_reader :as_secondary, :delayed_commit, :delayed_commit_timeout, :timekey_zone
142
142
  attr_reader :num_errors, :emit_count, :emit_records, :write_count, :rollback_count
143
143
 
144
144
  # for tests
@@ -185,13 +185,21 @@ module Fluent
185
185
  @simple_chunking = nil
186
186
  @chunk_keys = @chunk_key_time = @chunk_key_tag = nil
187
187
  @flush_mode = nil
188
+ @timekey_zone = nil
188
189
  end
189
190
 
190
191
  def acts_as_secondary(primary)
191
192
  @as_secondary = true
192
193
  @primary_instance = primary
194
+ @chunk_keys = @primary_instance.chunk_keys || []
195
+ @chunk_key_tag = @primary_instance.chunk_key_tag || false
196
+ if @primary_instance.chunk_key_time
197
+ @chunk_key_time = @primary_instance.chunk_key_time
198
+ @timekey_zone = @primary_instance.timekey_zone
199
+ @output_time_formatter_cache = {}
200
+ end
201
+
193
202
  (class << self; self; end).module_eval do
194
- define_method(:extract_placeholders){ |str, metadata| @primary_instance.extract_placeholders(str, metadata) }
195
203
  define_method(:commit_write){ |chunk_id| @primary_instance.commit_write(chunk_id, delayed: delayed_commit, secondary: true) }
196
204
  define_method(:rollback_write){ |chunk_id| @primary_instance.rollback_write(chunk_id) }
197
205
  end
@@ -251,7 +259,7 @@ module Fluent
251
259
  if @chunk_key_time
252
260
  raise Fluent::ConfigError, "<buffer ...> argument includes 'time', but timekey is not configured" unless @buffer_config.timekey
253
261
  Fluent::Timezone.validate!(@buffer_config.timekey_zone)
254
- @buffer_config.timekey_zone = '+0000' if @buffer_config.timekey_use_utc
262
+ @timekey_zone = @buffer_config.timekey_use_utc ? '+0000' : @buffer_config.timekey_zone
255
263
  @output_time_formatter_cache = {}
256
264
  end
257
265
 
@@ -301,7 +309,7 @@ module Fluent
301
309
  @secondary.acts_as_secondary(self)
302
310
  @secondary.configure(secondary_conf)
303
311
  @secondary.router = router if @secondary.has_router?
304
- if self.class != @secondary.class
312
+ if (self.class != @secondary.class) && (@custom_format || @secondary.implement?(:custom_format))
305
313
  log.warn "secondary type should be same with primary one", primary: self.class.to_s, secondary: @secondary.class.to_s
306
314
  end
307
315
  else
@@ -384,6 +392,11 @@ module Fluent
384
392
  @secondary.start if @secondary
385
393
  end
386
394
 
395
+ def after_start
396
+ super
397
+ @secondary.after_start if @secondary
398
+ end
399
+
387
400
  def stop
388
401
  @secondary.stop if @secondary
389
402
  @buffer.stop if @buffering && @buffer
@@ -472,13 +485,13 @@ module Fluent
472
485
 
473
486
  # TODO: optimize this code
474
487
  def extract_placeholders(str, metadata)
475
- if metadata.timekey.nil? && metadata.tag.nil? && metadata.variables.nil?
488
+ if metadata.empty?
476
489
  str
477
490
  else
478
491
  rvalue = str
479
492
  # strftime formatting
480
493
  if @chunk_key_time # this section MUST be earlier than rest to use raw 'str'
481
- @output_time_formatter_cache[str] ||= Fluent::Timezone.formatter(@buffer_config.timekey_zone, str)
494
+ @output_time_formatter_cache[str] ||= Fluent::Timezone.formatter(@timekey_zone, str)
482
495
  rvalue = @output_time_formatter_cache[str].call(metadata.timekey)
483
496
  end
484
497
  # ${tag}, ${tag[0]}, ${tag[1]}, ...
@@ -922,6 +935,11 @@ module Fluent
922
935
  interval = @buffer_config.flush_thread_interval
923
936
  end
924
937
 
938
+ while !self.after_started? && !self.stopped?
939
+ sleep 0.5
940
+ end
941
+ log.debug "enqueue_thread actually running"
942
+
925
943
  begin
926
944
  while @output_flush_threads_running
927
945
  now_int = Time.now.to_i
@@ -969,6 +987,11 @@ module Fluent
969
987
  clock_id = Process::CLOCK_MONOTONIC rescue Process::CLOCK_MONOTONIC_RAW
970
988
  state.next_time = Process.clock_gettime(clock_id) + flush_thread_interval
971
989
 
990
+ while !self.after_started? && !self.stopped?
991
+ sleep 0.5
992
+ end
993
+ log.debug "flush_thread actually running"
994
+
972
995
  begin
973
996
  # This thread don't use `thread_current_running?` because this thread should run in `before_shutdown` phase
974
997
  while @output_flush_threads_running
@@ -1,3 +1,19 @@
1
+ #
2
+ # Fluentd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
1
17
  require 'fluent/plugin'
2
18
  require 'fluent/plugin/storage'
3
19
 
@@ -66,6 +66,7 @@ module Fluent
66
66
  def initialize(title, interval, repeat, log, checker, &callback)
67
67
  @title = title
68
68
  @callback = callback
69
+ @repeat = repeat
69
70
  @log = log
70
71
  @checker = checker
71
72
  super(interval, repeat)
@@ -76,8 +77,12 @@ module Fluent
76
77
  rescue => e
77
78
  @log.error "Unexpected error raised. Stopping the timer.", title: @title, error: e
78
79
  @log.error_backtrace
79
- self.detach
80
+ detach
80
81
  @log.error "Timer detached.", title: @title
82
+ ensure
83
+ if attached?
84
+ detach unless @repeat
85
+ end
81
86
  end
82
87
  end
83
88
  end
@@ -91,7 +91,7 @@ module Fluent
91
91
  else
92
92
  conf.elements(name: 'source').each { |e|
93
93
  type = e['@type']
94
- raise ConfigError, "Missing 'type' parameter on <source> directive" unless type
94
+ raise ConfigError, "Missing '@type' parameter on <source> directive" unless type
95
95
  add_source(type, e)
96
96
  }
97
97
  end
@@ -137,6 +137,9 @@ module Fluent
137
137
  lifecycle(desc: true) do |i| # instance
138
138
  i.start unless i.started?
139
139
  end
140
+ lifecycle(desc: true) do |i|
141
+ i.after_start unless i.after_started?
142
+ end
140
143
  end
141
144
 
142
145
  def flush!
@@ -29,8 +29,10 @@ require 'shellwords'
29
29
 
30
30
  if Fluent.windows?
31
31
  require 'windows/library'
32
+ require 'windows/synchronize'
32
33
  require 'windows/system_info'
33
34
  include Windows::Library
35
+ include Windows::Synchronize
34
36
  include Windows::SystemInfo
35
37
  require 'win32/ipc'
36
38
  require 'win32/event'
@@ -48,16 +50,17 @@ module Fluent
48
50
  end
49
51
  install_supervisor_signal_handlers
50
52
 
53
+ if config[:signame]
54
+ @signame = config[:signame]
55
+ install_windows_event_handler
56
+ end
57
+
51
58
  socket_manager_path = ServerEngine::SocketManager::Server.generate_path
52
59
  ServerEngine::SocketManager::Server.open(socket_manager_path)
53
60
  ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = socket_manager_path.to_s
54
61
  end
55
62
 
56
63
  def after_run
57
- if Time.now - @start_time < 1
58
- $log.warn "process died within 1 second. exit."
59
- end
60
-
61
64
  stop_rpc_server if @rpc_endpoint
62
65
  end
63
66
 
@@ -135,6 +138,22 @@ module Fluent
135
138
  end unless Fluent.windows?
136
139
  end
137
140
 
141
+ def install_windows_event_handler
142
+ Thread.new do
143
+ ev = Win32::Event.new(@signame)
144
+ begin
145
+ ev.reset
146
+ until WaitForSingleObject(ev.handle, 0) == WAIT_OBJECT_0
147
+ sleep 1
148
+ end
149
+ kill_worker
150
+ stop(true)
151
+ ensure
152
+ ev.close
153
+ end
154
+ end
155
+ end
156
+
138
157
  def supervisor_sighup_handler
139
158
  kill_worker
140
159
  end
@@ -220,10 +239,13 @@ module Fluent
220
239
  logger_initializer.init
221
240
  logger = $log
222
241
 
242
+ command_sender = Fluent.windows? ? "pipe" : "signal"
243
+
223
244
  # ServerEngine's "daemonize" option is boolean, and path of pid file is brought by "pid_path"
224
245
  pid_path = params['daemonize']
225
246
  daemonize = !!params['daemonize']
226
247
  main_cmd = params['main_cmd']
248
+ signame = params['signame']
227
249
 
228
250
  se_config = {
229
251
  worker_type: 'spawn',
@@ -233,6 +255,8 @@ module Fluent
233
255
  log_stderr: false,
234
256
  enable_heartbeat: true,
235
257
  auto_heartbeat: false,
258
+ unrecoverable_exit_codes: [2],
259
+ stop_immediately_at_unrecoverable_exit: true,
236
260
  logger: logger,
237
261
  log: logger.out,
238
262
  log_path: log_path,
@@ -240,6 +264,7 @@ module Fluent
240
264
  logger_initializer: logger_initializer,
241
265
  chuser: chuser,
242
266
  chgroup: chgroup,
267
+ chumask: 0,
243
268
  suppress_repeated_stacktrace: suppress_repeated_stacktrace,
244
269
  daemonize: daemonize,
245
270
  rpc_endpoint: rpc_endpoint,
@@ -250,8 +275,10 @@ module Fluent
250
275
  WorkerModule.name,
251
276
  path,
252
277
  JSON.dump(params)],
278
+ command_sender: command_sender,
253
279
  fluentd_conf: fluentd_conf,
254
280
  main_cmd: main_cmd,
281
+ signame: signame,
255
282
  }
256
283
  if daemonize
257
284
  se_config[:pid_path] = pid_path
@@ -280,8 +307,8 @@ module Fluent
280
307
  if @path && @path != "-"
281
308
  @io = File.open(@path, "a")
282
309
  if @chuser || @chgroup
283
- chuid = @chuser ? ServerEngine::Daemon.get_etc_passwd(@chuser).uid : nil
284
- chgid = @chgroup ? ServerEngine::Daemon.get_etc_group(@chgroup).gid : nil
310
+ chuid = @chuser ? ServerEngine::Privilege.get_etc_passwd(@chuser).uid : nil
311
+ chgid = @chgroup ? ServerEngine::Privilege.get_etc_group(@chgroup).gid : nil
285
312
  File.chown(chuid, chgid, @path)
286
313
  end
287
314
  else
@@ -489,6 +516,7 @@ module Fluent
489
516
  params['chgroup'] = @chgroup
490
517
  params['use_v1_config'] = @use_v1_config
491
518
  params['suppress_repeated_stacktrace'] = @suppress_repeated_stacktrace
519
+ params['signame'] = @signame
492
520
 
493
521
  se = ServerEngine.create(ServerModule, WorkerModule){
494
522
  Fluent::Supervisor.load_config(@config_path, params)
@@ -527,6 +555,29 @@ module Fluent
527
555
  trap :USR1 do
528
556
  flush_buffer
529
557
  end unless Fluent.windows?
558
+
559
+ if Fluent.windows?
560
+ command_pipe = STDIN.dup
561
+ STDIN.reopen(File::NULL, "rb")
562
+ command_pipe.binmode
563
+ command_pipe.sync = true
564
+
565
+ Thread.new do
566
+ loop do
567
+ cmd = command_pipe.gets.chomp
568
+ case cmd
569
+ when "GRACEFUL_STOP", "IMMEDIATE_STOP"
570
+ $log.debug "fluentd main process get #{cmd} command"
571
+ @finished = true
572
+ $log.debug "getting start to shutdown main process"
573
+ Fluent::Engine.stop
574
+ break
575
+ else
576
+ $log.warn "fluentd main process get unknown command [#{cmd}]"
577
+ end
578
+ end
579
+ end
580
+ end
530
581
  end
531
582
 
532
583
  def flush_buffer
@@ -549,6 +600,8 @@ module Fluent
549
600
  def main_process(&block)
550
601
  Process.setproctitle("worker:#{@process_name}") if @process_name
551
602
 
603
+ configuration_error = false
604
+
552
605
  begin
553
606
  block.call
554
607
  rescue Fluent::ConfigError
@@ -562,7 +615,7 @@ module Fluent
562
615
  console.error "config error", file: @config_path, error: $!.to_s
563
616
  console.debug_backtrace
564
617
  end
565
-
618
+ configuration_error = true
566
619
  rescue
567
620
  $log.error "unexpected error", error: $!.to_s
568
621
  $log.error_backtrace
@@ -576,7 +629,7 @@ module Fluent
576
629
  end
577
630
  end
578
631
 
579
- exit! 1
632
+ exit!(configuration_error ? 2 : 1)
580
633
  end
581
634
 
582
635
  def read_config
@@ -598,7 +651,7 @@ module Fluent
598
651
  end
599
652
 
600
653
  def change_privilege
601
- ServerEngine::Daemon.change_privilege(@chuser, @chgroup)
654
+ ServerEngine::Privilege.change(@chuser, @chgroup)
602
655
  end
603
656
 
604
657
  def init_engine
@@ -30,7 +30,9 @@ module Fluent
30
30
  if block
31
31
  # Create new class for test w/ overwritten methods
32
32
  # klass.dup is worse because its ancestors does NOT include original class name
33
+ klass_name = klass.name
33
34
  klass = Class.new(klass)
35
+ klass.define_singleton_method("name") { klass_name }
34
36
  klass.module_eval(&block)
35
37
  end
36
38
  @instance = klass.new
@@ -62,6 +64,7 @@ module Fluent
62
64
  # num_waits is for checking thread status. This will be removed after improved plugin API
63
65
  def run(num_waits = 10, &block)
64
66
  @instance.start
67
+ @instance.after_start
65
68
  begin
66
69
  # wait until thread starts
67
70
  num_waits.times { sleep 0.05 }
@@ -31,7 +31,9 @@ module Fluent
31
31
  if block
32
32
  # Create new class for test w/ overwritten methods
33
33
  # klass.dup is worse because its ancestors does NOT include original class name
34
+ klass_name = klass.name
34
35
  klass = Class.new(klass)
36
+ klass.define_singleton_method("name") { klass_name }
35
37
  klass.module_eval(&block)
36
38
  end
37
39
  @instance = klass.new
@@ -86,6 +88,9 @@ module Fluent
86
88
  @instance.start
87
89
  instance_hook_after_started
88
90
  end
91
+ unless @instance.after_started?
92
+ @instance.after_start
93
+ end
89
94
  end
90
95
 
91
96
  def instance_hook_after_started
@@ -26,7 +26,9 @@ module Fluent
26
26
  if block
27
27
  # Create new class for test w/ overwritten methods
28
28
  # klass.dup is worse because its ancestors does NOT include original class name
29
+ klass_name = klass_or_str.name
29
30
  klass_or_str = Class.new(klass_or_str)
31
+ klass_or_str.define_singleton_method("name") { klass_name }
30
32
  klass_or_str.module_eval(&block)
31
33
  end
32
34
  @instance = klass_or_str.new
@@ -25,7 +25,9 @@ module Fluent
25
25
  if block
26
26
  # Create new class for test w/ overwritten methods
27
27
  # klass.dup is worse because its ancestors does NOT include original class name
28
+ klass_name = klass_or_str.name
28
29
  klass_or_str = Class.new(klass_or_str)
30
+ klass_or_str.define_singleton_method("name") { klass_name }
29
31
  klass_or_str.module_eval(&block)
30
32
  end
31
33
  case klass_or_str.instance_method(:initialize).arity
@@ -0,0 +1,33 @@
1
+ #
2
+ # Fluentd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'serverengine'
18
+
19
+ module Fluent
20
+ module Test
21
+ module StartupShutdown
22
+ def startup
23
+ socket_manager_path = ServerEngine::SocketManager::Server.generate_path
24
+ @server = ServerEngine::SocketManager::Server.open(socket_manager_path)
25
+ ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = socket_manager_path.to_s
26
+ end
27
+
28
+ def shutdown
29
+ @server.close
30
+ end
31
+ end
32
+ end
33
+ end
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '0.14.2'
19
+ VERSION = '0.14.5'
20
20
 
21
21
  end