fluentd 0.10.45 → 0.10.46

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -1
  3. data/ChangeLog +13 -0
  4. data/Rakefile +18 -2
  5. data/fluentd.gemspec +3 -1
  6. data/lib/fluent/command/fluentd.rb +5 -0
  7. data/lib/fluent/config.rb +17 -333
  8. data/lib/fluent/config/basic_parser.rb +108 -0
  9. data/lib/fluent/config/configure_proxy.rb +145 -0
  10. data/lib/fluent/{config_dsl.rb → config/dsl.rb} +5 -1
  11. data/lib/fluent/config/element.rb +82 -0
  12. data/lib/fluent/config/error.rb +7 -0
  13. data/lib/fluent/config/literal_parser.rb +158 -0
  14. data/lib/fluent/config/parser.rb +96 -0
  15. data/lib/fluent/config/section.rb +115 -0
  16. data/lib/fluent/config/types.rb +86 -0
  17. data/lib/fluent/config/v1_parser.rb +156 -0
  18. data/lib/fluent/configurable.rb +108 -0
  19. data/lib/fluent/engine.rb +4 -3
  20. data/lib/fluent/load.rb +0 -1
  21. data/lib/fluent/parser.rb +15 -5
  22. data/lib/fluent/plugin/buf_memory.rb +13 -5
  23. data/lib/fluent/plugin/in_forward.rb +18 -5
  24. data/lib/fluent/plugin/in_http.rb +4 -2
  25. data/lib/fluent/plugin/in_tail.rb +1 -1
  26. data/lib/fluent/plugin/out_forward.rb +33 -29
  27. data/lib/fluent/registry.rb +76 -0
  28. data/lib/fluent/supervisor.rb +2 -1
  29. data/lib/fluent/test/base.rb +3 -1
  30. data/lib/fluent/version.rb +1 -1
  31. data/spec/config/config_parser_spec.rb +176 -0
  32. data/spec/config/configurable_spec.rb +373 -0
  33. data/spec/config/configure_proxy_spec.rb +96 -0
  34. data/spec/config/dsl_spec.rb +239 -0
  35. data/spec/config/helper.rb +50 -0
  36. data/spec/config/literal_parser_spec.rb +190 -0
  37. data/spec/config/section_spec.rb +97 -0
  38. data/spec/spec_helper.rb +60 -0
  39. data/test/plugin/{in_exec.rb → test_in_exec.rb} +0 -0
  40. data/test/plugin/{in_forward.rb → test_in_forward.rb} +5 -0
  41. data/test/plugin/{in_gc_stat.rb → test_in_gc_stat.rb} +0 -0
  42. data/test/plugin/{in_http.rb → test_in_http.rb} +0 -0
  43. data/test/plugin/{in_object_space.rb → test_in_object_space.rb} +0 -0
  44. data/test/plugin/{in_status.rb → test_in_status.rb} +0 -0
  45. data/test/plugin/{in_stream.rb → test_in_stream.rb} +0 -0
  46. data/test/plugin/{in_syslog.rb → test_in_syslog.rb} +0 -0
  47. data/test/plugin/{in_tail.rb → test_in_tail.rb} +0 -0
  48. data/test/plugin/{out_copy.rb → test_out_copy.rb} +0 -0
  49. data/test/plugin/{out_exec.rb → test_out_exec.rb} +0 -0
  50. data/test/plugin/{out_exec_filter.rb → test_out_exec_filter.rb} +0 -0
  51. data/test/plugin/{out_file.rb → test_out_file.rb} +0 -0
  52. data/test/plugin/{out_forward.rb → test_out_forward.rb} +15 -0
  53. data/test/plugin/{out_roundrobin.rb → test_out_roundrobin.rb} +0 -0
  54. data/test/plugin/{out_stdout.rb → test_out_stdout.rb} +0 -0
  55. data/test/plugin/{out_stream.rb → test_out_stream.rb} +0 -0
  56. data/test/scripts/fluent/plugin/parser_known.rb +3 -0
  57. data/test/{config.rb → test_config.rb} +1 -0
  58. data/test/{configdsl.rb → test_configdsl.rb} +1 -1
  59. data/test/{match.rb → test_match.rb} +0 -0
  60. data/test/{mixin.rb → test_mixin.rb} +0 -0
  61. data/test/{output.rb → test_output.rb} +0 -0
  62. data/test/{parser.rb → test_parser.rb} +22 -5
  63. metadata +114 -51
@@ -0,0 +1,96 @@
1
+ module Fluent
2
+ module Config
3
+ require 'fluent/config/error'
4
+ require 'fluent/config/element'
5
+
6
+ class Parser
7
+ def self.read(path)
8
+ path = File.expand_path(path)
9
+ File.open(path) { |io|
10
+ parse(io, File.basename(path), File.dirname(path))
11
+ }
12
+ end
13
+
14
+ def self.parse(io, fname, basepath = Dir.pwd)
15
+ attrs, elems = Parser.new(basepath, io.each_line, fname).parse!(true)
16
+ Element.new('ROOT', '', attrs, elems)
17
+ end
18
+
19
+ def initialize(basepath, iterator, fname, i = 0)
20
+ @basepath = basepath
21
+ @iterator = iterator
22
+ @i = i
23
+ @fname = fname
24
+ end
25
+
26
+ def parse!(allow_include, elem_name = nil, attrs = {}, elems = [])
27
+ while line = @iterator.next
28
+ line.force_encoding('UTF-8')
29
+ @i += 1
30
+ line.lstrip!
31
+ line.gsub!(/\s*(?:\#.*)?$/,'')
32
+ if line.empty?
33
+ next
34
+ elsif m = /^\<include\s*(.*)\s*\/\>$/.match(line)
35
+ value = m[1].strip
36
+ process_include(attrs, elems, value, allow_include)
37
+ elsif m = /^\<([a-zA-Z0-9_]+)\s*(.+?)?\>$/.match(line)
38
+ e_name = m[1]
39
+ e_arg = m[2] || ""
40
+ e_attrs, e_elems = parse!(false, e_name)
41
+ elems << Element.new(e_name, e_arg, e_attrs, e_elems)
42
+ elsif line == "</#{elem_name}>"
43
+ break
44
+ elsif m = /^([a-zA-Z0-9_]+)\s*(.*)$/.match(line)
45
+ key = m[1]
46
+ value = m[2]
47
+ if allow_include && key == 'include'
48
+ process_include(attrs, elems, value)
49
+ else
50
+ attrs[key] = value
51
+ end
52
+ next
53
+ else
54
+ raise ConfigParseError, "parse error at #{@fname} line #{@i}"
55
+ end
56
+ end
57
+
58
+ return attrs, elems
59
+ rescue StopIteration
60
+ return attrs, elems
61
+ end
62
+
63
+ def process_include(attrs, elems, uri, allow_include = true)
64
+ u = URI.parse(uri)
65
+ if u.scheme == 'file' || u.path == uri # file path
66
+ path = u.path
67
+ if path[0] != ?/
68
+ pattern = File.expand_path("#{@basepath}/#{path}")
69
+ else
70
+ pattern = path
71
+ end
72
+
73
+ Dir.glob(pattern).sort.each { |path|
74
+ basepath = File.dirname(path)
75
+ fname = File.basename(path)
76
+ File.open(path) { |f|
77
+ Parser.new(basepath, f.each_line, fname).parse!(allow_include, nil, attrs, elems)
78
+ }
79
+ }
80
+
81
+ else
82
+ basepath = '/'
83
+ fname = path
84
+ require 'open-uri'
85
+ open(uri) {|f|
86
+ Parser.new(basepath, f.each_line, fname).parse!(allow_include, nil, attrs, elems)
87
+ }
88
+ end
89
+
90
+ rescue SystemCallError => e
91
+ raise ConfigParseError, "include error at #{@fname} line #{@i}: #{e.to_s}"
92
+ end
93
+ end
94
+ end
95
+ end
96
+
@@ -0,0 +1,115 @@
1
+ module Fluent
2
+ require 'fluent/config/error'
3
+
4
+ module Config
5
+ class Section < BasicObject
6
+ def self.name
7
+ 'Fluent::Config::Section'
8
+ end
9
+
10
+ def initialize(params = {})
11
+ @klass = 'Fluent::Config::Section'
12
+ @params = params
13
+ end
14
+
15
+ def nil?
16
+ false
17
+ end
18
+
19
+ def to_h
20
+ @params
21
+ end
22
+
23
+ def +(other)
24
+ Section.new(self.to_h.merge(other.to_h))
25
+ end
26
+
27
+ def instance_of?(mod)
28
+ @klass == mod.name
29
+ end
30
+
31
+ def kind_of?(mod)
32
+ @klass == mod.name || BasicObject == mod
33
+ end
34
+ alias is_a? kind_of?
35
+
36
+ def [](key)
37
+ @params[key.to_sym]
38
+ end
39
+
40
+ def respond_to_missing?(symbol, include_private)
41
+ @params.has_key?(symbol)
42
+ end
43
+
44
+ def method_missing(name, *args)
45
+ if @params.has_key?(name)
46
+ @params[name]
47
+ else
48
+ super
49
+ end
50
+ end
51
+ end
52
+
53
+ module SectionGenerator
54
+ def self.generate(proxy, conf, logger, stack = [])
55
+ return nil if conf.nil?
56
+
57
+ section_stack = ""
58
+ unless stack.empty?
59
+ section_stack = ", in section " + stack.join(" > ")
60
+ end
61
+
62
+ section_params = {}
63
+
64
+ proxy.defaults.each_pair do |name, defval|
65
+ varname = name.to_sym
66
+ section_params[varname] = defval
67
+ end
68
+
69
+ if proxy.argument
70
+ unless conf.arg.empty?
71
+ key, block, opts = proxy.argument
72
+ section_params[key] = self.instance_exec(conf.arg, opts, name, &block)
73
+ end
74
+ unless section_params.has_key?(proxy.argument.first)
75
+ logger.error "config error in:\n#{conf}"
76
+ raise ConfigError, "'<#{proxy.name} ARG>' section requires argument" + section_stack
77
+ end
78
+ end
79
+
80
+ proxy.params.each_pair do |name, defval|
81
+ varname = name.to_sym
82
+ block, opts = defval
83
+ if val = conf[name.to_s]
84
+ section_params[varname] = self.instance_exec(val, opts, name, &block)
85
+ end
86
+ unless section_params.has_key?(varname)
87
+ logger.error "config error in:\n#{conf}"
88
+ raise ConfigError, "'#{name}' parameter is required" + section_stack
89
+ end
90
+ end
91
+
92
+ proxy.sections.each do |name, subproxy|
93
+ varname = subproxy.param_name.to_sym
94
+ elements = (conf.respond_to?(:elements) ? conf.elements : []).select{ |e| e.name == subproxy.name.to_s }
95
+
96
+ if subproxy.required? && elements.size < 1
97
+ logger.error "config error in:\n#{conf}"
98
+ raise ConfigError, "'<#{subproxy.name}>' sections are required" + section_stack
99
+ end
100
+ if subproxy.multi?
101
+ section_params[varname] = elements.map{ |e| generate(subproxy, e, logger, stack + [subproxy.name]) }
102
+ else
103
+ if elements.size > 1
104
+ logger.error "config error in:\n#{conf}"
105
+ raise ConfigError, "'<#{subproxy.name}>' section cannot be written twice or more" + section_stack
106
+ end
107
+ section_params[varname] = generate(subproxy, elements.first, logger, stack + [subproxy.name])
108
+ end
109
+ end
110
+
111
+ Section.new(section_params)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,86 @@
1
+ module Fluent
2
+ require 'json'
3
+
4
+ module Config
5
+ def self.size_value(str)
6
+ case str.to_s
7
+ when /([0-9]+)k/i
8
+ $~[1].to_i * 1024
9
+ when /([0-9]+)m/i
10
+ $~[1].to_i * (1024 ** 2)
11
+ when /([0-9]+)g/i
12
+ $~[1].to_i * (1024 ** 3)
13
+ when /([0-9]+)t/i
14
+ $~[1].to_i * (1024 ** 4)
15
+ else
16
+ str.to_i
17
+ end
18
+ end
19
+
20
+ def self.time_value(str)
21
+ case str.to_s
22
+ when /([0-9]+)s/
23
+ $~[1].to_i
24
+ when /([0-9]+)m/
25
+ $~[1].to_i * 60
26
+ when /([0-9]+)h/
27
+ $~[1].to_i * 60 * 60
28
+ when /([0-9]+)d/
29
+ $~[1].to_i * 24 * 60 * 60
30
+ else
31
+ str.to_f
32
+ end
33
+ end
34
+
35
+ def self.bool_value(str)
36
+ case str.to_s
37
+ when 'true', 'yes'
38
+ true
39
+ when 'false', 'no'
40
+ false
41
+ else
42
+ nil
43
+ end
44
+ end
45
+ end
46
+
47
+ Configurable.register_type(:string, Proc.new { |val, opts|
48
+ val
49
+ })
50
+
51
+ Configurable.register_type(:integer, Proc.new { |val, opts|
52
+ val.to_i
53
+ })
54
+
55
+ Configurable.register_type(:float, Proc.new { |val, opts|
56
+ val.to_f
57
+ })
58
+
59
+ Configurable.register_type(:size, Proc.new { |val, opts|
60
+ Config.size_value(val)
61
+ })
62
+
63
+ Configurable.register_type(:bool, Proc.new { |val, opts|
64
+ Config.bool_value(val)
65
+ })
66
+
67
+ Configurable.register_type(:time, Proc.new { |val, opts|
68
+ Config.time_value(val)
69
+ })
70
+
71
+ Configurable.register_type(:hash, Proc.new { |val, opts|
72
+ param = JSON.load(val)
73
+ if param.class != Hash
74
+ raise ConfigError, "hash required but got #{val.inspect}"
75
+ end
76
+ param
77
+ })
78
+
79
+ Configurable.register_type(:array, Proc.new { |val, opts|
80
+ param = JSON.load(val)
81
+ if param.class != Array
82
+ raise ConfigError, "array required but got #{val.inspect}"
83
+ end
84
+ param
85
+ })
86
+ end
@@ -0,0 +1,156 @@
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
+ module Fluent
17
+ module Config
18
+
19
+ require 'strscan'
20
+ require 'fluent/config/error'
21
+ require 'fluent/config/literal_parser'
22
+ require 'fluent/config/element'
23
+
24
+ class V1Parser < LiteralParser
25
+ ELEMENT_NAME = /[a-zA-Z0-9_]+/
26
+
27
+ def self.read(path, eval_context = nil)
28
+ path = File.expand_path(path)
29
+ data = File.read(path)
30
+ parse(data, File.basename(path), File.dirname(path), eval_context)
31
+ end
32
+
33
+ def self.parse(data, fname, basepath = Dir.pwd, eval_context = nil)
34
+ ss = StringScanner.new(data)
35
+ ps = V1Parser.new(ss, basepath, fname, eval_context)
36
+ ps.parse!
37
+ end
38
+
39
+ def initialize(strscan, include_basepath, fname, eval_context)
40
+ super(strscan, eval_context)
41
+ @include_basepath = include_basepath
42
+ @fname = fname
43
+ end
44
+
45
+ def parse!
46
+ attrs, elems = parse_element(true, nil)
47
+ root = Element.new('ROOT', '', attrs, elems)
48
+
49
+ spacing
50
+ unless eof?
51
+ parse_error! "expected EOF"
52
+ end
53
+
54
+ return root
55
+ end
56
+
57
+ def parse_element(root_element, elem_name, attrs = {}, elems = [])
58
+ while true
59
+ spacing
60
+ if eof?
61
+ if root_element
62
+ break
63
+ end
64
+ parse_error! "expected end tag '</#{elem_name}>' but got end of file"
65
+ end
66
+
67
+ if skip(/\<\//)
68
+ e_name = scan(ELEMENT_NAME)
69
+ spacing
70
+ unless skip(/\>/)
71
+ parse_error! "expected character in tag name"
72
+ end
73
+ unless line_end
74
+ parse_error! "expected end of line after end tag"
75
+ end
76
+ if e_name != elem_name
77
+ parse_error! "unmatched end tag"
78
+ end
79
+ break
80
+
81
+ elsif skip(/\</)
82
+ e_name = scan(ELEMENT_NAME)
83
+ spacing
84
+ e_arg = scan_nonquoted_string(/(?:#{SPACING}|\>)/)
85
+ spacing
86
+ unless skip(/\>/)
87
+ parse_error! "expected '>'"
88
+ end
89
+ unless line_end
90
+ parse_error! "expected end of line after tag"
91
+ end
92
+ e_arg ||= ''
93
+ # call parse_element recursively
94
+ e_attrs, e_elems = parse_element(false, e_name)
95
+ elems << Element.new(e_name, e_arg, e_attrs, e_elems)
96
+
97
+ elsif root_element && skip(/\@include#{SPACING}/)
98
+ uri = scan_string(LINE_END)
99
+ eval_include(attrs, elems, uri)
100
+ line_end
101
+
102
+ else
103
+ k = scan_string(SPACING)
104
+ spacing
105
+ v = parse_literal
106
+ unless line_end
107
+ parse_error! "expected end of line"
108
+ end
109
+ attrs[k] = v
110
+ end
111
+ end
112
+
113
+ return attrs, elems
114
+ end
115
+
116
+ def eval_include(attrs, elems, uri)
117
+ u = URI.parse(uri)
118
+ if u.scheme == 'file' || u.path == uri # file path
119
+ path = u.path
120
+ if path[0] != ?/
121
+ pattern = File.expand_path("#{@include_basepath}/#{path}")
122
+ else
123
+ pattern = path
124
+ end
125
+
126
+ Dir.glob(pattern).each { |path|
127
+ basepath = File.dirname(path)
128
+ fname = File.basename(path)
129
+ data = File.read(path)
130
+ ss = StringScanner.new(data)
131
+ V1Parser.new(ss, basepath, fname, @eval_context).parse(true, nil, attrs, elems)
132
+ }
133
+
134
+ else
135
+ basepath = '/'
136
+ fname = path
137
+ require 'open-uri'
138
+ data = nil
139
+ open(uri) { |f| read = f.read }
140
+ ss = StringScanner.new(data)
141
+ V1Parser.new(ss, basepath, fname, @eval_context).parse(true, nil, attrs, elems)
142
+ end
143
+
144
+ rescue SystemCallError => e
145
+ cpe = ConfigParseError.new("include error #{uri}")
146
+ cpe.set_backtrace(e.backtrace)
147
+ raise cpe
148
+ end
149
+
150
+ # override
151
+ def error_sample
152
+ "#{@fname} #{super}"
153
+ end
154
+ end
155
+ end
156
+ end