fluentd 0.14.14 → 0.14.15

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.

@@ -105,6 +105,11 @@ module Fluent::Plugin
105
105
  buffer_conf['path'] = conf['path'] || '/tmp/dummy_path'
106
106
  end
107
107
 
108
+ if conf.has_key?('utc') || conf.has_key?('localtime')
109
+ param_name = conf.has_key?('utc') ? 'utc' : 'localtime'
110
+ log.warn "'#{param_name}' is deperecated for output plugin. This parameter is used for formatter plugin in compatibility layer. If you want to use same feature, use timekey_use_utc parameter in <buffer> directive instead"
111
+ end
112
+
108
113
  super
109
114
 
110
115
  @compress_method = SUPPORTED_COMPRESS_MAP[@compress]
@@ -122,12 +122,17 @@ module Fluent
122
122
  raise NotImplementedError, "BUG: output plugins MUST implement this method"
123
123
  end
124
124
 
125
- def formatted_to_msgpack_binary
125
+ def formatted_to_msgpack_binary?
126
126
  # To indicate custom format method (#format) returns msgpack binary or not.
127
127
  # If #format returns msgpack binary, override this method to return true.
128
128
  false
129
129
  end
130
130
 
131
+ # Compatibility for existing plugins
132
+ def formatted_to_msgpack_binary
133
+ formatted_to_msgpack_binary?
134
+ end
135
+
131
136
  def prefer_buffered_processing
132
137
  # override this method to return false only when all of these are true:
133
138
  # * plugin has both implementation for buffered and non-buffered methods
@@ -55,7 +55,7 @@ module Fluent
55
55
  "keys" => "keys", # CSVParser, TSVParser (old ValuesParser)
56
56
  "time_key" => "time_key",
57
57
  "time_format" => "time_format",
58
- "localtim" => nil,
58
+ "localtime" => nil,
59
59
  "utc" => nil,
60
60
  "delimiter" => "delimiter",
61
61
  "keep_time_key" => "keep_time_key",
@@ -64,11 +64,34 @@ module Fluent
64
64
  attr_reader :labels
65
65
 
66
66
  def configure(conf)
67
+ # initialize <worker> elements
68
+ conf.elements(name: 'worker').each do |e|
69
+ target_worker_id_str = e.arg
70
+ if target_worker_id_str.empty?
71
+ raise ConfigError, "Missing worker id on <worker> directive"
72
+ end
73
+
74
+ target_worker_id = target_worker_id_str.to_i
75
+ if target_worker_id < 0 || target_worker_id > (Fluent::Engine.system_config.workers - 1)
76
+ raise ConfigError, "worker id #{target_worker_id} specified by <worker> directive is not allowed. Available worker id is between 0 and #{(Fluent::Engine.system_config.workers - 1)}"
77
+ end
78
+
79
+ e.elements.each do |elem|
80
+ unless ['source', 'match', 'filter', 'label'].include?(elem.name)
81
+ raise ConfigError, "<worker> section cannot have <#{elem.name}> directive"
82
+ end
83
+ elem.set_target_worker_id(target_worker_id)
84
+ end
85
+ conf += e
86
+ end
87
+ conf.elements.delete_if{|e| e.name == 'worker'}
88
+
67
89
  error_label_config = nil
68
90
 
69
91
  # initialize <label> elements before configuring all plugins to avoid 'label not found' in input, filter and output.
70
92
  label_configs = {}
71
93
  conf.elements(name: 'label').each { |e|
94
+ next if e.for_another_worker?
72
95
  name = e.arg
73
96
  raise ConfigError, "Missing symbol argument on <label> directive" if name.empty?
74
97
 
@@ -90,6 +113,7 @@ module Fluent
90
113
  log.info :worker0, "'--without-source' is applied. Ignore <source> sections"
91
114
  else
92
115
  conf.elements(name: 'source').each { |e|
116
+ next if e.for_another_worker?
93
117
  type = e['@type']
94
118
  raise ConfigError, "Missing '@type' parameter on <source> directive" unless type
95
119
  add_source(type, e)
@@ -235,7 +259,8 @@ module Fluent
235
259
  end
236
260
 
237
261
  def add_source(type, conf)
238
- log.info :worker0, "adding source", type: type
262
+ log_type = conf.for_this_worker? ? :default : :worker0
263
+ log.info log_type, "adding source", type: type
239
264
 
240
265
  input = Plugin.new_input(type)
241
266
  # <source> emits events to the top-level event router (RootAgent#event_router).
@@ -384,7 +384,6 @@ module Fluent
384
384
  supervise: true,
385
385
  standalone_worker: false,
386
386
  signame: nil,
387
- winsvcreg: nil,
388
387
  }
389
388
  end
390
389
 
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '0.14.14'
19
+ VERSION = '0.14.15'
20
20
 
21
21
  end
data/lib/fluent/winsvc.rb CHANGED
@@ -14,10 +14,9 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- INTEVENTOBJ_NAME = "fluentdwinsvc"
18
-
19
17
  begin
20
18
 
19
+ require 'optparse'
21
20
  require 'windows/debug'
22
21
  require 'Windows/Library'
23
22
  require 'win32/daemon'
@@ -27,34 +26,50 @@ begin
27
26
  include Windows::Library
28
27
  include Windows::Debug
29
28
 
30
- def read_fluentdopt
29
+ op = OptionParser.new
30
+ opts = {service_name: nil}
31
+ op.on('--service-name NAME', "The name of the Windows Service") {|name|
32
+ opts[:service_name] = name
33
+ }
34
+ op.parse(ARGV)
35
+ if opts[:service_name] == nil
36
+ raise "Error: No Windows Service name set. Use '--service-name'"
37
+ end
38
+
39
+ def read_fluentdopt(service_name)
31
40
  require 'win32/Registry'
32
- Win32::Registry::HKEY_LOCAL_MACHINE.open("SYSTEM\\CurrentControlSet\\Services\\fluentdwinsvc") do |reg|
41
+ Win32::Registry::HKEY_LOCAL_MACHINE.open("SYSTEM\\CurrentControlSet\\Services\\#{service_name}") do |reg|
33
42
  reg.read("fluentdopt")[1] rescue ""
34
43
  end
35
44
  end
36
45
 
37
- def service_main_start
46
+ def service_main_start(service_name)
38
47
  ruby_path = 0.chr * 260
39
48
  GetModuleFileName.call(0, ruby_path,260)
40
49
  ruby_path = ruby_path.rstrip.gsub(/\\/, '/')
41
50
  rubybin_dir = ruby_path[0, ruby_path.rindex("/")]
42
- opt = read_fluentdopt
43
- Process.spawn(rubybin_dir + "/ruby.exe " + rubybin_dir + "/fluentd " + opt + " -x " + INTEVENTOBJ_NAME)
51
+ opt = read_fluentdopt(service_name)
52
+ Process.spawn("\"#{rubybin_dir}/ruby.exe\" \"#{rubybin_dir}/fluentd\" #{opt} -x #{service_name}")
44
53
  end
45
54
 
46
55
  class FluentdService < Daemon
47
56
  @pid = 0
57
+ @service_name = ''
48
58
 
59
+ def initialize(service_name)
60
+ @service_name = service_name
61
+ end
62
+
49
63
  def service_main
50
- @pid = service_main_start
64
+
65
+ @pid = service_main_start(@service_name)
51
66
  while running?
52
67
  sleep 10
53
68
  end
54
69
  end
55
70
 
56
71
  def service_stop
57
- ev = Win32::Event.open(INTEVENTOBJ_NAME)
72
+ ev = Win32::Event.open(@service_name)
58
73
  ev.set
59
74
  ev.close
60
75
  if @pid > 0
@@ -63,9 +78,8 @@ begin
63
78
  end
64
79
  end
65
80
 
66
- FluentdService.mainloop
81
+ FluentdService.new(opts[:service_name]).mainloop
67
82
 
68
83
  rescue Exception => err
69
84
  raise
70
85
  end
71
-
@@ -297,7 +297,7 @@ CONF
297
297
  assert_log_matches(
298
298
  create_cmdline(conf_path),
299
299
  "fluentd worker is now running",
300
- '[warn]: match for some tags of log events are not defined (to be ignored) tags=["fluent.trace", "fluent.debug", "fluent.info"]',
300
+ '[warn]: #0 match for some tags of log events are not defined (to be ignored) tags=["fluent.trace", "fluent.debug", "fluent.info"]',
301
301
  '[warn]: #0 no patterns matched tag="fluent.info"',
302
302
  )
303
303
  end
@@ -334,7 +334,7 @@ CONF
334
334
  assert_log_matches(
335
335
  create_cmdline(conf_path),
336
336
  "fluentd worker is now running",
337
- '[warn]: match for some tags of log events are not defined (to be ignored) tags=["fluent.info", "fluent.fatal"]',
337
+ '[warn]: #0 match for some tags of log events are not defined (to be ignored) tags=["fluent.info", "fluent.fatal"]',
338
338
  patterns_not_match: ['[warn]: no patterns matched tag="fluent.info"'],
339
339
  )
340
340
  end
@@ -614,5 +614,211 @@ CONF
614
614
  "config error file=\"#{conf_path}\" error_class=Fluent::ConfigError error=\"Plugin 'file' does not support multi workers configuration (Fluent::Plugin::FileBuffer)\"",
615
615
  )
616
616
  end
617
+
618
+ test 'failed to start workers when configured plugins as chidren of MultiOutput do not support multi worker configuration' do
619
+ script = <<-EOC
620
+ require 'fluent/plugin/output'
621
+ module Fluent::Plugin
622
+ class SingleOutput < Output
623
+ Fluent::Plugin.register_output('single', self)
624
+ def multi_workers_ready?
625
+ false
626
+ end
627
+ def write(chunk)
628
+ end
629
+ end
630
+ end
631
+ EOC
632
+ plugin_path = create_plugin_file('out_single.rb', script)
633
+
634
+ conf = <<CONF
635
+ <system>
636
+ workers 2
637
+ </system>
638
+ <source>
639
+ @type single
640
+ @id single
641
+ @label @dummydata
642
+ </source>
643
+ <label @dummydata>
644
+ <match dummy>
645
+ @type copy
646
+ <store>
647
+ @type single
648
+ </store>
649
+ <store>
650
+ @type single
651
+ </store>
652
+ </match>
653
+ </label>
654
+ CONF
655
+ conf_path = create_conf_file('workers_invalid3.conf', conf)
656
+ assert_fluentd_fails_to_start(
657
+ create_cmdline(conf_path, "-p", File.dirname(plugin_path)),
658
+ "Plugin 'single' does not support multi workers configuration (Fluent::Plugin::SingleOutput)",
659
+ )
660
+ end
661
+
662
+ test 'success to start a worker with worker specific configuration' do
663
+ conf = <<CONF
664
+ <system>
665
+ workers 2
666
+ root_dir #{@root_path}
667
+ </system>
668
+ <source>
669
+ @type dummy
670
+ @id dummy
671
+ @label @dummydata
672
+ tag dummy
673
+ dummy {"message": "yay!"}
674
+ </source>
675
+ <worker 1>
676
+ <source>
677
+ @type dummy
678
+ @id dummy_in_worker
679
+ @label @dummydata
680
+ tag dummy
681
+ dummy {"message": "yay!"}
682
+ </source>
683
+ </worker>
684
+ <label @dummydata>
685
+ <match dummy>
686
+ @type null
687
+ @id blackhole
688
+ </match>
689
+ </label>
690
+ CONF
691
+ conf_path = create_conf_file('worker_section0.conf', conf)
692
+ assert Dir.exist?(@root_path)
693
+
694
+ assert_log_matches(
695
+ create_cmdline(conf_path),
696
+ "#0 fluentd worker is now running worker=0",
697
+ "#1 fluentd worker is now running worker=1",
698
+ /(?!#\d) adding source type="dummy"/,
699
+ '#1 adding source type="dummy"'
700
+ )
701
+ end
702
+
703
+ test 'success to start workers when configured plugins only for specific worker do not support multi worker configuration' do
704
+ script = <<-EOC
705
+ require 'fluent/plugin/input'
706
+ module Fluent::Plugin
707
+ class SingleInput < Input
708
+ Fluent::Plugin.register_input('single', self)
709
+ def multi_workers_ready?
710
+ false
711
+ end
712
+ end
713
+ end
714
+ EOC
715
+ plugin_path = create_plugin_file('in_single.rb', script)
716
+
717
+ conf = <<CONF
718
+ <system>
719
+ workers 2
720
+ </system>
721
+ <worker 1>
722
+ <source>
723
+ @type single
724
+ @id single
725
+ @label @dummydata
726
+ </source>
727
+ </worker>
728
+ <label @dummydata>
729
+ <match dummy>
730
+ @type null
731
+ @id blackhole
732
+ </match>
733
+ </label>
734
+ CONF
735
+ conf_path = create_conf_file('worker_section1.conf', conf)
736
+ assert Dir.exist?(@root_path)
737
+
738
+ assert_log_matches(
739
+ create_cmdline(conf_path, "-p", File.dirname(plugin_path)),
740
+ "#0 fluentd worker is now running worker=0",
741
+ "#1 fluentd worker is now running worker=1",
742
+ '#1 adding source type="single"'
743
+ )
744
+ end
745
+
746
+ test 'success to start workers when file buffer is configured in non-workers way only for specific worker' do
747
+ conf = <<CONF
748
+ <system>
749
+ workers 2
750
+ </system>
751
+ <source>
752
+ @type dummy
753
+ @id dummy
754
+ tag dummy
755
+ dummy {"message": "yay!"}
756
+ </source>
757
+ <worker 1>
758
+ <match dummy>
759
+ @type null
760
+ @id blackhole
761
+ <buffer>
762
+ @type file
763
+ path #{File.join(@root_path, "buf", "file.*.log")}
764
+ </buffer>
765
+ </match>
766
+ </worker>
767
+ CONF
768
+ conf_path = create_conf_file('worker_section2.conf', conf)
769
+ assert_log_matches(
770
+ create_cmdline(conf_path),
771
+ "#0 fluentd worker is now running worker=0",
772
+ "#1 fluentd worker is now running worker=1",
773
+ '#1 adding match pattern="dummy" type="null"'
774
+ )
775
+ end
776
+
777
+ test 'success to start workers when configured plugins as a chidren of MultiOutput only for specific worker do not support multi worker configuration' do
778
+ script = <<-EOC
779
+ require 'fluent/plugin/output'
780
+ module Fluent::Plugin
781
+ class SingleOutput < Output
782
+ Fluent::Plugin.register_output('single', self)
783
+ def multi_workers_ready?
784
+ false
785
+ end
786
+ def write(chunk)
787
+ end
788
+ end
789
+ end
790
+ EOC
791
+ plugin_path = create_plugin_file('out_single.rb', script)
792
+
793
+ conf = <<CONF
794
+ <system>
795
+ workers 2
796
+ </system>
797
+ <source>
798
+ @type dummy
799
+ @id dummy
800
+ tag dummy
801
+ dummy {"message": "yay!"}
802
+ </source>
803
+ <worker 1>
804
+ <match dummy>
805
+ @type copy
806
+ <store>
807
+ @type single
808
+ </store>
809
+ <store>
810
+ @type single
811
+ </store>
812
+ </match>
813
+ </worker>
814
+ CONF
815
+ conf_path = create_conf_file('worker_section3.conf', conf)
816
+ assert_log_matches(
817
+ create_cmdline(conf_path, "-p", File.dirname(plugin_path)),
818
+ "#0 fluentd worker is now running worker=0",
819
+ "#1 fluentd worker is now running worker=1",
820
+ '#1 adding match pattern="dummy" type="copy"'
821
+ )
822
+ end
617
823
  end
618
824
  end
@@ -400,4 +400,67 @@ CONF
400
400
  end
401
401
  end
402
402
  end
403
+
404
+ sub_test_case '#set_target_worker' do
405
+ test 'set target_worker_id recursively' do
406
+ e = element('label', '@mytest', {}, [ element('filter', '**'), element('match', '**', {}, [ element('store'), element('store') ]) ])
407
+ e.set_target_worker_id(1)
408
+ assert_equal 1, e.target_worker_id
409
+ assert_equal 1, e.elements[0].target_worker_id
410
+ assert_equal 1, e.elements[1].target_worker_id
411
+ assert_equal 1, e.elements[1].elements[0].target_worker_id
412
+ assert_equal 1, e.elements[1].elements[1].target_worker_id
413
+ end
414
+ end
415
+
416
+ sub_test_case '#for_every_workers?' do
417
+ test 'has target_worker_id' do
418
+ e = element()
419
+ e.set_target_worker_id(1)
420
+ assert_false e.for_every_workers?
421
+ end
422
+
423
+ test "doesn't have target_worker_id" do
424
+ e = element()
425
+ assert e.for_every_workers?
426
+ end
427
+ end
428
+
429
+ sub_test_case '#for_this_workers?' do
430
+ test 'target_worker_id == current worker_id' do
431
+ e = element()
432
+ e.set_target_worker_id(0)
433
+ assert e.for_this_worker?
434
+ end
435
+
436
+ test 'target_worker_id != current worker_id' do
437
+ e = element()
438
+ e.set_target_worker_id(1)
439
+ assert_false e.for_this_worker?
440
+ end
441
+
442
+ test "doesn't have target_worker_id" do
443
+ e = element()
444
+ assert_false e.for_this_worker?
445
+ end
446
+ end
447
+
448
+ sub_test_case '#for_another_worker?' do
449
+ test 'target_worker_id == current worker_id' do
450
+ e = element()
451
+ e.set_target_worker_id(0)
452
+ assert_false e.for_another_worker?
453
+ end
454
+
455
+ test 'target_worker_id != current worker_id' do
456
+ e = element()
457
+ e.set_target_worker_id(1)
458
+ assert e.for_another_worker?
459
+ end
460
+
461
+ test "doesn't have target_worker_id" do
462
+ e = element()
463
+ assert_false e.for_another_worker?
464
+ end
465
+ end
403
466
  end