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.
- checksums.yaml +4 -4
- data/ChangeLog +28 -0
- data/example/worker_section.conf +36 -0
- data/lib/fluent/agent.rb +5 -2
- data/lib/fluent/command/fluentd.rb +28 -12
- data/lib/fluent/command/plugin_generator.rb +1 -1
- data/lib/fluent/compat/detach_process_mixin.rb +8 -0
- data/lib/fluent/compat/input.rb +0 -10
- data/lib/fluent/compat/output.rb +0 -10
- data/lib/fluent/config/element.rb +22 -0
- data/lib/fluent/engine.rb +22 -9
- data/lib/fluent/plugin/base.rb +3 -0
- data/lib/fluent/plugin/filter.rb +2 -2
- data/lib/fluent/plugin/in_http.rb +2 -0
- data/lib/fluent/plugin/in_tail.rb +5 -2
- data/lib/fluent/plugin/out_file.rb +5 -0
- data/lib/fluent/plugin/output.rb +6 -1
- data/lib/fluent/plugin_helper/compat_parameters.rb +1 -1
- data/lib/fluent/root_agent.rb +26 -1
- data/lib/fluent/supervisor.rb +0 -1
- data/lib/fluent/version.rb +1 -1
- data/lib/fluent/winsvc.rb +25 -11
- data/test/command/test_fluentd.rb +208 -2
- data/test/config/test_element.rb +63 -0
- data/test/plugin/test_in_http.rb +36 -4
- data/test/plugin/test_out_file.rb +9 -0
- data/test/plugin/test_output_as_buffered.rb +30 -2
- data/test/test_plugin_classes.rb +15 -0
- data/test/test_root_agent.rb +204 -0
- metadata +4 -3
@@ -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]
|
data/lib/fluent/plugin/output.rb
CHANGED
@@ -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
|
-
"
|
58
|
+
"localtime" => nil,
|
59
59
|
"utc" => nil,
|
60
60
|
"delimiter" => "delimiter",
|
61
61
|
"keep_time_key" => "keep_time_key",
|
data/lib/fluent/root_agent.rb
CHANGED
@@ -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
|
-
|
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).
|
data/lib/fluent/supervisor.rb
CHANGED
data/lib/fluent/version.rb
CHANGED
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
|
-
|
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
|
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
|
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
|
-
|
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(
|
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
|
data/test/config/test_element.rb
CHANGED
@@ -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
|