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,108 @@
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 'stringio'
20
+ require 'fluent/config/error'
21
+
22
+ class BasicParser
23
+ def initialize(strscan)
24
+ @ss = strscan
25
+ end
26
+
27
+ LINE_END = /(?:[ \t]*(?:\#.*)?(?:\z|[\r\n]))+/
28
+ SPACING = /(?:[ \t\r\n]|\z|\#.*?(?:\z|[\r\n]))+/
29
+
30
+ module ClassMethods
31
+ def symbol(string)
32
+ /#{Regexp.escape(string)}/
33
+ end
34
+
35
+ def def_symbol(method_name, string)
36
+ pattern = symbol(string)
37
+ define_method(method_name) do
38
+ skip(pattern) && string
39
+ end
40
+ end
41
+
42
+ def def_literal(method_name, string)
43
+ pattern = /#{string}#{LINE_END}/
44
+ define_method(method_name) do
45
+ skip(pattern) && string
46
+ end
47
+ end
48
+ end
49
+
50
+ extend ClassMethods
51
+
52
+ def skip(pattern)
53
+ @ss.skip(pattern)
54
+ end
55
+
56
+ def scan(pattern)
57
+ @ss.scan(pattern)
58
+ end
59
+
60
+ def getch
61
+ @ss.getch
62
+ end
63
+
64
+ def eof?
65
+ @ss.eos?
66
+ end
67
+
68
+ def line_end
69
+ skip(LINE_END)
70
+ end
71
+
72
+ def spacing
73
+ skip(SPACING)
74
+ end
75
+
76
+ def parse_error!(message)
77
+ raise ConfigParseError, "#{message} at #{error_sample}"
78
+ end
79
+
80
+ def error_sample
81
+ pos = @ss.pos
82
+
83
+ lines = @ss.string.lines.to_a
84
+ lines.each_with_index { |line, ln|
85
+ if line.size >= pos
86
+ msgs = ["line #{ln + 1},#{pos}\n"]
87
+
88
+ if ln > 0
89
+ last_line = lines[ln - 1]
90
+ msgs << "%3s: %s" % [ln, last_line]
91
+ end
92
+
93
+ msgs << "%3s: %s" % [ln + 1, line]
94
+ msgs << "\n #{'-' * pos}^\n"
95
+
96
+ if next_line = lines[ln + 1]
97
+ msgs << "%3s: %s" % [ln + 2, next_line]
98
+ end
99
+
100
+ return msgs.join
101
+ end
102
+ pos -= line.size
103
+ last_line = line
104
+ }
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,145 @@
1
+ module Fluent
2
+ module Config
3
+ class ConfigureProxy
4
+ attr_accessor :name, :param_name, :required, :multi, :argument, :params, :defaults, :sections
5
+ # config_param :desc, :string, :default => '....'
6
+ # config_set_default :buffer_type, :memory
7
+ #
8
+ # config_section :default, required: true, multi: false do
9
+ # config_argument :arg, :string
10
+ # config_param :required, :bool, default: false
11
+ # config_param :name, :string
12
+ # config_param :power, :integer
13
+ # end
14
+ #
15
+ # config_section :child, param_name: 'children', required: false, multi: true do
16
+ # config_param :name, :string
17
+ # config_param :power, :integer, default: nil
18
+ # config_section :item do
19
+ # config_param :name
20
+ # end
21
+ # end
22
+
23
+ def initialize(name, opts = {})
24
+ @name = name.to_sym
25
+
26
+ @param_name = (opts[:param_name] || @name).to_sym
27
+ @required = opts[:required]
28
+ @multi = opts[:multi]
29
+
30
+ @argument = nil # nil: ignore argument
31
+ @params = {}
32
+ @defaults = {}
33
+ @sections = {}
34
+ end
35
+
36
+ def required?
37
+ @required.nil? ? false : @required
38
+ end
39
+
40
+ def multi?
41
+ @multi.nil? ? true : @multi
42
+ end
43
+
44
+ def merge(other) # self is base class, other is subclass
45
+ options = {
46
+ param_name: other.param_name,
47
+ required: (other.required.nil? ? self.required : other.required),
48
+ multi: (other.multi.nil? ? self.multi : other.multi)
49
+ }
50
+ merged = self.class.new(other.name, options)
51
+
52
+ merged.argument = other.argument || self.argument
53
+ merged.params = self.params.merge(other.params)
54
+ merged.defaults = self.defaults.merge(other.defaults)
55
+ merged.sections = self.sections.merge(other.sections)
56
+
57
+ merged
58
+ end
59
+
60
+ def parameter_configuration(name, *args, &block)
61
+ name = name.to_sym
62
+
63
+ opts = {}
64
+ args.each { |a|
65
+ if a.is_a?(Symbol)
66
+ opts[:type] = a
67
+ elsif a.is_a?(Hash)
68
+ opts.merge!(a)
69
+ else
70
+ raise ArgumentError, "wrong number of arguments (#{1 + args.length} for #{block ? 2 : 3})"
71
+ end
72
+ }
73
+
74
+ type = opts[:type]
75
+ if block && type
76
+ raise ArgumentError, "both of block and type cannot be specified"
77
+ end
78
+
79
+ begin
80
+ type = :string if type.nil?
81
+ block ||= Configurable.lookup_type(type)
82
+ rescue ConfigError
83
+ # override error message
84
+ raise ArgumentError, "unknown config_argument type `#{type}'"
85
+ end
86
+
87
+ if opts.has_key?(:default)
88
+ config_set_default(name, opts[:default])
89
+ end
90
+
91
+ [name, block, opts]
92
+ end
93
+
94
+ def config_argument(name, *args, &block)
95
+ if @argument
96
+ raise ArgumentError, "config_argument called twice"
97
+ end
98
+ name, block, opts = parameter_configuration(name, *args, &block)
99
+
100
+ @argument = [name, block, opts]
101
+ name
102
+ end
103
+
104
+ def config_param(name, *args, &block)
105
+ name, block, opts = parameter_configuration(name, *args, &block)
106
+
107
+ @sections.delete(name)
108
+ @params[name] = [block, opts]
109
+ name
110
+ end
111
+
112
+ def config_set_default(name, defval)
113
+ name = name.to_sym
114
+
115
+ if @defaults.has_key?(name)
116
+ raise ArgumentError, "default value specified twice for #{name}"
117
+ end
118
+
119
+ @defaults[name] = defval
120
+ nil
121
+ end
122
+
123
+ def config_section(name, *args, &block)
124
+ unless block_given?
125
+ raise ArgumentError, "config_section requires block parameter"
126
+ end
127
+ name = name.to_sym
128
+
129
+ opts = {}
130
+ unless args.empty? || args.size == 1 && args.first.is_a?(Hash)
131
+ raise ArgumentError, "unknown config_section arguments: #{args.inspect}"
132
+ end
133
+
134
+ sub_proxy = ConfigureProxy.new(name, *args)
135
+ sub_proxy.instance_exec(&block)
136
+
137
+ @params.delete(name)
138
+ @sections[name] = sub_proxy
139
+
140
+ name
141
+ end
142
+ end
143
+ end
144
+ end
145
+
@@ -67,7 +67,11 @@ module Fluent
67
67
  proxy.element.instance_exec(&block)
68
68
  @elements.push(proxy.to_config_element)
69
69
  else
70
- @attrs[name.to_s] = value.to_s
70
+ @attrs[name.to_s] = if value.is_a?(Array) || value.is_a?(Hash)
71
+ JSON.dump(value)
72
+ else
73
+ value.to_s
74
+ end
71
75
  end
72
76
 
73
77
  self
@@ -0,0 +1,82 @@
1
+ module Fluent
2
+ require 'fluent/config/error'
3
+
4
+ module Config
5
+ class Element < Hash
6
+ def initialize(name, arg, attrs, elements, unused = nil)
7
+ @name = name
8
+ @arg = arg
9
+ @elements = elements
10
+ super()
11
+ attrs.each { |k, v|
12
+ self[k] = v
13
+ }
14
+ @unused = unused || attrs.keys
15
+ end
16
+
17
+ attr_accessor :name, :arg, :elements, :unused
18
+
19
+ def add_element(name, arg='')
20
+ e = Element.new(name, arg, {}, [])
21
+ @elements << e
22
+ e
23
+ end
24
+
25
+ def +(o)
26
+ Element.new(@name.dup, @arg.dup, o.merge(self), @elements + o.elements, (@unused + o.unused).uniq)
27
+ end
28
+
29
+ def each_element(*names, &block)
30
+ if names.empty?
31
+ @elements.each(&block)
32
+ else
33
+ @elements.each { |e|
34
+ if names.include?(e.name)
35
+ block.yield(e)
36
+ end
37
+ }
38
+ end
39
+ end
40
+
41
+ def has_key?(key)
42
+ @unused.delete(key)
43
+ super
44
+ end
45
+
46
+ def [](key)
47
+ @unused.delete(key)
48
+ super
49
+ end
50
+
51
+ def check_not_fetched(&block)
52
+ each_key { |key|
53
+ if @unused.include?(key)
54
+ block.call(key, self)
55
+ end
56
+ }
57
+ @elements.each { |e|
58
+ e.check_not_fetched(&block)
59
+ }
60
+ end
61
+
62
+ def to_s(nest = 0)
63
+ indent = " " * nest
64
+ nindent = " " * (nest + 1)
65
+ out = ""
66
+ if @arg.empty?
67
+ out << "#{indent}<#{@name}>\n"
68
+ else
69
+ out << "#{indent}<#{@name} #{@arg}>\n"
70
+ end
71
+ each_pair { |k, v|
72
+ out << "#{nindent}#{k} #{v}\n"
73
+ }
74
+ @elements.each { |e|
75
+ out << e.to_s(nest + 1)
76
+ }
77
+ out << "#{indent}</#{@name}>\n"
78
+ out
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,7 @@
1
+ module Fluent
2
+ class ConfigError < StandardError
3
+ end
4
+
5
+ class ConfigParseError < ConfigError
6
+ end
7
+ end
@@ -0,0 +1,158 @@
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 'yajl'
20
+ require 'fluent/config/basic_parser'
21
+ require 'irb/ruby-lex' # RubyLex
22
+
23
+ class LiteralParser < BasicParser
24
+ def initialize(strscan, eval_context)
25
+ super(strscan)
26
+ @eval_context = eval_context
27
+ end
28
+
29
+ def parse_literal(string_boundary_charset = LINE_END)
30
+ spacing
31
+
32
+ value = if skip(/\[/)
33
+ scan_json(true)
34
+ elsif skip(/\{/)
35
+ scan_json(false)
36
+ else
37
+ scan_string(string_boundary_charset)
38
+ end
39
+ value
40
+ end
41
+
42
+ def scan_string(string_boundary_charset = LINE_END)
43
+ if skip(/\"/)
44
+ return scan_quoted_string
45
+ else
46
+ return scan_nonquoted_string(string_boundary_charset)
47
+ end
48
+ end
49
+
50
+ def scan_quoted_string
51
+ string = []
52
+ while true
53
+ if skip(/\"/)
54
+ return string.join
55
+ elsif s = scan(/\\./)
56
+ string << eval_escape_char(s[1,1])
57
+ elsif skip(/\#\{/)
58
+ string << eval_embedded_code(scan_embedded_code)
59
+ skip(/\}/)
60
+ elsif s = scan(/./)
61
+ string << s
62
+ else
63
+ parse_error! "unexpected end of file in a quoted string"
64
+ end
65
+ end
66
+ end
67
+
68
+ def scan_nonquoted_string(boundary_charset = LINE_END)
69
+ charset = /(?!#{boundary_charset})./
70
+
71
+ string = []
72
+ while true
73
+ if s = scan(/\\./)
74
+ string << eval_escape_char(s[1,1])
75
+ elsif s = scan(charset)
76
+ string << s
77
+ else
78
+ break
79
+ end
80
+ end
81
+
82
+ if string.empty?
83
+ return nil
84
+ end
85
+
86
+ string.join
87
+ end
88
+
89
+ def scan_embedded_code
90
+ rlex = RubyLex.new
91
+ src = '"#{'+@ss.rest+"\n=end\n}"
92
+
93
+ input = StringIO.new(src)
94
+ input.define_singleton_method(:encoding) { external_encoding }
95
+ rlex.set_input(input)
96
+
97
+ tk = rlex.token
98
+ code = src[3,tk.seek-3]
99
+
100
+ if @ss.rest.length < code.length
101
+ @ss.pos += @ss.rest.length
102
+ parse_error! "expected end of embedded code but $end"
103
+ end
104
+
105
+ @ss.pos += code.length
106
+
107
+ code
108
+ end
109
+
110
+ def eval_embedded_code(code)
111
+ if @eval_context.nil?
112
+ parse_error! "embedded code is not allowed in this file"
113
+ end
114
+ @eval_context.instance_eval(code)
115
+ end
116
+
117
+ def eval_escape_char(c)
118
+ case c
119
+ when '"'
120
+ '"'
121
+ when "'"
122
+ "'"
123
+ when "r"
124
+ "\r"
125
+ when "n"
126
+ "\n"
127
+ when "t"
128
+ "\t"
129
+ when "f"
130
+ "\f"
131
+ when "b"
132
+ "\b"
133
+ when /[a-zA-Z0-9]/
134
+ parse_error! "unexpected back-slash escape character '#{c}'"
135
+ else # symbols
136
+ c
137
+ end
138
+ end
139
+
140
+ def scan_json(is_array)
141
+ result = nil
142
+
143
+ y = Yajl::Parser.new(:allow_comments => true)
144
+ y.on_parse_complete = Proc.new { |obj| result = obj }
145
+ y << (is_array ? '[' : '{')
146
+ until result
147
+ ch = getch
148
+ parse_error! "got incomplete #{is_array ? 'array' : 'hash'} configuration" if ch.nil?
149
+ y << ch
150
+ end
151
+
152
+ Yajl.dump(result) # Convert json to string for config_param
153
+ rescue Yajl::ParseError => e
154
+ parse_error! "unexpected #{is_array ? 'array' : 'hash'} parse error"
155
+ end
156
+ end
157
+ end
158
+ end