fluentd 0.14.3 → 0.14.4

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.

Potentially problematic release.


This version of fluentd might be problematic. Click here for more details.

Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +59 -1131
  3. data/Rakefile +15 -0
  4. data/appveyor.yml +2 -2
  5. data/example/multi_filters.conf +61 -0
  6. data/fluentd.gemspec +19 -16
  7. data/lib/fluent/agent.rb +3 -0
  8. data/lib/fluent/command/debug.rb +4 -4
  9. data/lib/fluent/compat/handle_tag_and_time_mixin.rb +2 -0
  10. data/lib/fluent/compat/output.rb +5 -2
  11. data/lib/fluent/config/configure_proxy.rb +26 -5
  12. data/lib/fluent/config/error.rb +3 -0
  13. data/lib/fluent/config/section.rb +15 -0
  14. data/lib/fluent/event_router.rb +77 -4
  15. data/lib/fluent/plugin/base.rb +12 -3
  16. data/lib/fluent/plugin/filter.rb +48 -6
  17. data/lib/fluent/plugin/filter_record_transformer.rb +3 -1
  18. data/lib/fluent/plugin/filter_stdout.rb +0 -4
  19. data/lib/fluent/plugin/in_debug_agent.rb +5 -5
  20. data/lib/fluent/plugin/in_dummy.rb +9 -1
  21. data/lib/fluent/plugin/in_forward.rb +32 -14
  22. data/lib/fluent/plugin/in_monitor_agent.rb +31 -77
  23. data/lib/fluent/plugin/in_tail.rb +37 -9
  24. data/lib/fluent/plugin/out_forward.rb +2 -13
  25. data/lib/fluent/plugin/output.rb +16 -1
  26. data/lib/fluent/plugin/storage_local.rb +16 -0
  27. data/lib/fluent/plugin_helper/timer.rb +6 -1
  28. data/lib/fluent/root_agent.rb +3 -0
  29. data/lib/fluent/supervisor.rb +62 -9
  30. data/lib/fluent/test/base.rb +3 -0
  31. data/lib/fluent/test/driver/base.rb +5 -0
  32. data/lib/fluent/test/formatter_test.rb +2 -0
  33. data/lib/fluent/test/parser_test.rb +2 -0
  34. data/lib/fluent/version.rb +1 -1
  35. data/lib/fluent/winsvc.rb +1 -2
  36. data/test/compat/test_calls_super.rb +2 -0
  37. data/test/config/test_configurable.rb +88 -0
  38. data/test/config/test_types.rb +7 -3
  39. data/test/plugin/test_filter.rb +121 -23
  40. data/test/plugin/test_filter_record_transformer.rb +22 -6
  41. data/test/plugin/test_in_debug_agent.rb +2 -2
  42. data/test/plugin/test_in_forward.rb +54 -6
  43. data/test/plugin/test_in_monitor_agent.rb +329 -0
  44. data/test/plugin/test_in_tail.rb +73 -0
  45. data/test/plugin/test_out_forward.rb +1 -0
  46. data/test/plugin/test_output.rb +53 -0
  47. data/test/plugin/test_output_as_buffered.rb +13 -0
  48. data/test/plugin/test_output_as_buffered_overflow.rb +3 -0
  49. data/test/plugin/test_output_as_buffered_retries.rb +11 -0
  50. data/test/plugin/test_output_as_buffered_secondary.rb +12 -0
  51. data/test/plugin/test_output_as_standard.rb +12 -0
  52. data/test/plugin_helper/test_compat_parameters.rb +2 -0
  53. data/test/plugin_helper/test_timer.rb +31 -0
  54. data/test/test_event_router.rb +87 -0
  55. data/test/test_filter.rb +48 -6
  56. data/test/test_log.rb +5 -2
  57. data/test/test_output.rb +41 -1
  58. data/test/test_plugin_classes.rb +17 -9
  59. data/test/test_root_agent.rb +146 -0
  60. metadata +51 -67
@@ -67,14 +67,10 @@ module Fluent
67
67
  config_param :multiline_flush_interval, :time, default: nil
68
68
  desc 'Enable the additional watch timer.'
69
69
  config_param :enable_watch_timer, :bool, default: true
70
+ desc 'The encoding after conversion of the input.'
71
+ config_param :encoding, :string, default: nil
70
72
  desc 'The encoding of the input.'
71
- config_param :encoding, default: nil do |encoding_name|
72
- begin
73
- Encoding.find(encoding_name)
74
- rescue ArgumentError => e
75
- raise ConfigError, e.message
76
- end
77
- end
73
+ config_param :from_encoding, :string, default: nil
78
74
  desc 'Add the log path being tailed to records. Specify the field name to be used.'
79
75
  config_param :path_key, :string, default: nil
80
76
 
@@ -95,6 +91,7 @@ module Fluent
95
91
 
96
92
  configure_parser(conf)
97
93
  configure_tag
94
+ configure_encoding
98
95
 
99
96
  @multiline_mode = conf['format'] =~ /multiline/
100
97
  @receive_handler = if @multiline_mode
@@ -120,6 +117,25 @@ module Fluent
120
117
  end
121
118
  end
122
119
 
120
+ def configure_encoding
121
+ unless @encoding
122
+ if @from_encoding
123
+ raise ConfigError, "tail: 'from_encoding' parameter must be specified with 'encoding' parameter."
124
+ end
125
+ end
126
+
127
+ @encoding = parse_encoding_param(@encoding) if @encoding
128
+ @from_encoding = parse_encoding_param(@from_encoding) if @from_encoding
129
+ end
130
+
131
+ def parse_encoding_param(encoding_name)
132
+ begin
133
+ Encoding.find(encoding_name) if encoding_name
134
+ rescue ArgumentError => e
135
+ raise ConfigError, e.message
136
+ end
137
+ end
138
+
123
139
  def start
124
140
  super
125
141
 
@@ -254,7 +270,13 @@ module Fluent
254
270
  def flush_buffer(tw)
255
271
  if lb = tw.line_buffer
256
272
  lb.chomp!
257
- lb.force_encoding(@encoding) if @encoding
273
+ if @encoding
274
+ if @from_encoding
275
+ lb.encode!(@encoding, @from_encoding)
276
+ else
277
+ lb.force_encoding(@encoding)
278
+ end
279
+ end
258
280
  @parser.parse(lb) { |time, record|
259
281
  if time && record
260
282
  tag = if @tag_prefix || @tag_suffix
@@ -303,7 +325,13 @@ module Fluent
303
325
  def convert_line_to_event(line, es, tail_watcher)
304
326
  begin
305
327
  line.chomp! # remove \n
306
- line.force_encoding(@encoding) if @encoding
328
+ if @encoding
329
+ if @from_encoding
330
+ line.encode!(@encoding, @from_encoding)
331
+ else
332
+ line.force_encoding(@encoding)
333
+ end
334
+ end
307
335
  @parser.parse(line) { |time, record|
308
336
  if time && record
309
337
  record[@path_key] ||= tail_watcher.path unless @path_key.nil?
@@ -89,23 +89,12 @@ module Fluent
89
89
 
90
90
  attr_reader :nodes
91
91
 
92
- # backward compatibility
93
- config_param :port, :integer, default: LISTEN_PORT
94
- config_param :host, :string, default: nil
92
+ config_param :port, :integer, default: LISTEN_PORT, obsoleted: "User <server> section instead."
93
+ config_param :host, :string, default: nil, obsoleted: "Use <server> section instead."
95
94
 
96
95
  def configure(conf)
97
96
  super
98
97
 
99
- # backward compatibility
100
- if host = conf['host']
101
- log.warn "'host' option in forward output is obsoleted. Use '<server> host xxx </server>' instead."
102
- port = conf['port']
103
- port = port ? port.to_i : LISTEN_PORT
104
- element = conf.add_element('server')
105
- element['host'] = host
106
- element['port'] = port.to_s
107
- end
108
-
109
98
  recover_sample_size = @recover_wait / @heartbeat_interval
110
99
 
111
100
  if @dns_round_robin
@@ -301,7 +301,7 @@ module Fluent
301
301
  @secondary.acts_as_secondary(self)
302
302
  @secondary.configure(secondary_conf)
303
303
  @secondary.router = router if @secondary.has_router?
304
- if self.class != @secondary.class
304
+ if (self.class != @secondary.class) && (@custom_format || @secondary.implement?(:custom_format))
305
305
  log.warn "secondary type should be same with primary one", primary: self.class.to_s, secondary: @secondary.class.to_s
306
306
  end
307
307
  else
@@ -384,6 +384,11 @@ module Fluent
384
384
  @secondary.start if @secondary
385
385
  end
386
386
 
387
+ def after_start
388
+ super
389
+ @secondary.after_start if @secondary
390
+ end
391
+
387
392
  def stop
388
393
  @secondary.stop if @secondary
389
394
  @buffer.stop if @buffering && @buffer
@@ -922,6 +927,11 @@ module Fluent
922
927
  interval = @buffer_config.flush_thread_interval
923
928
  end
924
929
 
930
+ while !self.after_started? && !self.stopped?
931
+ sleep 0.5
932
+ end
933
+ log.debug "enqueue_thread actually running"
934
+
925
935
  begin
926
936
  while @output_flush_threads_running
927
937
  now_int = Time.now.to_i
@@ -969,6 +979,11 @@ module Fluent
969
979
  clock_id = Process::CLOCK_MONOTONIC rescue Process::CLOCK_MONOTONIC_RAW
970
980
  state.next_time = Process.clock_gettime(clock_id) + flush_thread_interval
971
981
 
982
+ while !self.after_started? && !self.stopped?
983
+ sleep 0.5
984
+ end
985
+ log.debug "flush_thread actually running"
986
+
972
987
  begin
973
988
  # This thread don't use `thread_current_running?` because this thread should run in `before_shutdown` phase
974
989
  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
@@ -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
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '0.14.3'
19
+ VERSION = '0.14.4'
20
20
 
21
21
  end