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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -1
- data/ChangeLog +13 -0
- data/Rakefile +18 -2
- data/fluentd.gemspec +3 -1
- data/lib/fluent/command/fluentd.rb +5 -0
- data/lib/fluent/config.rb +17 -333
- data/lib/fluent/config/basic_parser.rb +108 -0
- data/lib/fluent/config/configure_proxy.rb +145 -0
- data/lib/fluent/{config_dsl.rb → config/dsl.rb} +5 -1
- data/lib/fluent/config/element.rb +82 -0
- data/lib/fluent/config/error.rb +7 -0
- data/lib/fluent/config/literal_parser.rb +158 -0
- data/lib/fluent/config/parser.rb +96 -0
- data/lib/fluent/config/section.rb +115 -0
- data/lib/fluent/config/types.rb +86 -0
- data/lib/fluent/config/v1_parser.rb +156 -0
- data/lib/fluent/configurable.rb +108 -0
- data/lib/fluent/engine.rb +4 -3
- data/lib/fluent/load.rb +0 -1
- data/lib/fluent/parser.rb +15 -5
- data/lib/fluent/plugin/buf_memory.rb +13 -5
- data/lib/fluent/plugin/in_forward.rb +18 -5
- data/lib/fluent/plugin/in_http.rb +4 -2
- data/lib/fluent/plugin/in_tail.rb +1 -1
- data/lib/fluent/plugin/out_forward.rb +33 -29
- data/lib/fluent/registry.rb +76 -0
- data/lib/fluent/supervisor.rb +2 -1
- data/lib/fluent/test/base.rb +3 -1
- data/lib/fluent/version.rb +1 -1
- data/spec/config/config_parser_spec.rb +176 -0
- data/spec/config/configurable_spec.rb +373 -0
- data/spec/config/configure_proxy_spec.rb +96 -0
- data/spec/config/dsl_spec.rb +239 -0
- data/spec/config/helper.rb +50 -0
- data/spec/config/literal_parser_spec.rb +190 -0
- data/spec/config/section_spec.rb +97 -0
- data/spec/spec_helper.rb +60 -0
- data/test/plugin/{in_exec.rb → test_in_exec.rb} +0 -0
- data/test/plugin/{in_forward.rb → test_in_forward.rb} +5 -0
- data/test/plugin/{in_gc_stat.rb → test_in_gc_stat.rb} +0 -0
- data/test/plugin/{in_http.rb → test_in_http.rb} +0 -0
- data/test/plugin/{in_object_space.rb → test_in_object_space.rb} +0 -0
- data/test/plugin/{in_status.rb → test_in_status.rb} +0 -0
- data/test/plugin/{in_stream.rb → test_in_stream.rb} +0 -0
- data/test/plugin/{in_syslog.rb → test_in_syslog.rb} +0 -0
- data/test/plugin/{in_tail.rb → test_in_tail.rb} +0 -0
- data/test/plugin/{out_copy.rb → test_out_copy.rb} +0 -0
- data/test/plugin/{out_exec.rb → test_out_exec.rb} +0 -0
- data/test/plugin/{out_exec_filter.rb → test_out_exec_filter.rb} +0 -0
- data/test/plugin/{out_file.rb → test_out_file.rb} +0 -0
- data/test/plugin/{out_forward.rb → test_out_forward.rb} +15 -0
- data/test/plugin/{out_roundrobin.rb → test_out_roundrobin.rb} +0 -0
- data/test/plugin/{out_stdout.rb → test_out_stdout.rb} +0 -0
- data/test/plugin/{out_stream.rb → test_out_stream.rb} +0 -0
- data/test/scripts/fluent/plugin/parser_known.rb +3 -0
- data/test/{config.rb → test_config.rb} +1 -0
- data/test/{configdsl.rb → test_configdsl.rb} +1 -1
- data/test/{match.rb → test_match.rb} +0 -0
- data/test/{mixin.rb → test_mixin.rb} +0 -0
- data/test/{output.rb → test_output.rb} +0 -0
- data/test/{parser.rb → test_parser.rb} +22 -5
- 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.
|
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,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
|