fluentd 0.10.62 → 0.12.0.pre.1
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/.gitignore +1 -2
- data/.travis.yml +0 -4
- data/ChangeLog +0 -72
- data/Gemfile +0 -6
- data/Rakefile +12 -3
- data/example/in_http.conf +14 -0
- data/example/in_syslog.conf +15 -0
- data/example/in_tail.conf +14 -0
- data/example/in_tcp.conf +13 -0
- data/example/in_udp.conf +13 -0
- data/example/out_copy.conf +20 -0
- data/example/out_file.conf +13 -0
- data/example/out_forward.conf +30 -0
- data/fluent.conf +2 -12
- data/fluentd.gemspec +8 -11
- data/lib/fluent/agent.rb +180 -0
- data/lib/fluent/buffer.rb +6 -12
- data/lib/fluent/command/cat.rb +1 -3
- data/lib/fluent/command/debug.rb +1 -3
- data/lib/fluent/command/fluentd.rb +0 -10
- data/lib/fluent/config.rb +9 -3
- data/lib/fluent/config/basic_parser.rb +1 -6
- data/lib/fluent/config/configure_proxy.rb +25 -61
- data/lib/fluent/config/dsl.rb +16 -0
- data/lib/fluent/config/element.rb +21 -2
- data/lib/fluent/config/error.rb +16 -0
- data/lib/fluent/config/literal_parser.rb +9 -27
- data/lib/fluent/config/parser.rb +16 -0
- data/lib/fluent/config/section.rb +16 -2
- data/lib/fluent/config/types.rb +16 -1
- data/lib/fluent/config/v1_parser.rb +4 -12
- data/lib/fluent/configurable.rb +16 -0
- data/lib/fluent/engine.rb +43 -163
- data/lib/fluent/env.rb +16 -1
- data/lib/fluent/event.rb +20 -48
- data/lib/fluent/event_router.rb +187 -0
- data/lib/fluent/filter.rb +32 -0
- data/lib/fluent/formatter.rb +29 -101
- data/lib/fluent/input.rb +6 -4
- data/lib/fluent/label.rb +18 -0
- data/lib/fluent/load.rb +1 -3
- data/lib/fluent/log.rb +1 -3
- data/lib/fluent/match.rb +12 -19
- data/lib/fluent/mixin.rb +9 -25
- data/lib/fluent/output.rb +27 -45
- data/lib/fluent/parser.rb +93 -99
- data/lib/fluent/plugin.rb +22 -48
- data/lib/fluent/plugin/buf_file.rb +10 -7
- data/lib/fluent/plugin/buf_memory.rb +2 -3
- data/lib/fluent/plugin/buf_zfile.rb +75 -0
- data/lib/fluent/plugin/exec_util.rb +16 -0
- data/lib/fluent/plugin/in_debug_agent.rb +2 -3
- data/lib/fluent/plugin/in_exec.rb +2 -9
- data/lib/fluent/plugin/in_forward.rb +4 -22
- data/lib/fluent/plugin/in_gc_stat.rb +2 -3
- data/lib/fluent/plugin/in_http.rb +19 -59
- data/lib/fluent/plugin/in_monitor_agent.rb +21 -47
- data/lib/fluent/plugin/in_object_space.rb +2 -3
- data/lib/fluent/plugin/in_status.rb +2 -3
- data/lib/fluent/plugin/in_stream.rb +6 -16
- data/lib/fluent/plugin/in_syslog.rb +8 -17
- data/lib/fluent/plugin/in_tail.rb +17 -24
- data/lib/fluent/plugin/in_tcp.rb +16 -0
- data/lib/fluent/plugin/in_udp.rb +16 -0
- data/lib/fluent/plugin/out_copy.rb +3 -4
- data/lib/fluent/plugin/out_exec.rb +2 -4
- data/lib/fluent/plugin/out_exec_filter.rb +2 -13
- data/lib/fluent/plugin/out_file.rb +5 -6
- data/lib/fluent/plugin/out_forward.rb +4 -5
- data/lib/fluent/plugin/out_null.rb +2 -3
- data/lib/fluent/plugin/out_relabel.rb +26 -0
- data/lib/fluent/plugin/out_roundrobin.rb +3 -4
- data/lib/fluent/plugin/out_stdout.rb +2 -3
- data/lib/fluent/plugin/out_stream.rb +2 -3
- data/{test/scripts → lib}/fluent/plugin/out_test.rb +2 -3
- data/lib/fluent/plugin/socket_util.rb +19 -10
- data/lib/fluent/process.rb +4 -6
- data/lib/fluent/registry.rb +16 -0
- data/lib/fluent/root_agent.rb +212 -0
- data/lib/fluent/status.rb +2 -3
- data/lib/fluent/supervisor.rb +33 -54
- data/lib/fluent/test.rb +16 -0
- data/lib/fluent/test/base.rb +3 -17
- data/lib/fluent/test/input_test.rb +52 -7
- data/lib/fluent/test/output_test.rb +4 -20
- data/lib/fluent/version.rb +17 -1
- data/spec/config/config_parser_spec.rb +314 -0
- data/spec/config/configurable_spec.rb +524 -0
- data/spec/config/configure_proxy_spec.rb +96 -0
- data/spec/config/dsl_spec.rb +239 -0
- data/spec/config/helper.rb +49 -0
- data/spec/config/literal_parser_spec.rb +222 -0
- data/spec/config/section_spec.rb +97 -0
- data/spec/config/system_config_spec.rb +49 -0
- data/test/helper.rb +0 -25
- data/test/plugin/test_in_exec.rb +1 -1
- data/test/plugin/test_in_forward.rb +2 -1
- data/test/plugin/test_in_gc_stat.rb +1 -1
- data/test/plugin/test_in_http.rb +3 -78
- data/test/plugin/test_in_object_space.rb +1 -1
- data/test/plugin/test_in_status.rb +1 -1
- data/test/plugin/test_in_stream.rb +2 -1
- data/test/plugin/test_in_syslog.rb +2 -1
- data/test/plugin/test_in_tail.rb +6 -11
- data/test/plugin/test_in_tcp.rb +2 -1
- data/test/plugin/test_in_udp.rb +2 -1
- data/test/plugin/test_out_copy.rb +1 -12
- data/test/plugin/test_out_exec.rb +1 -1
- data/test/plugin/test_out_exec_filter.rb +1 -1
- data/test/plugin/test_out_file.rb +7 -96
- data/test/plugin/test_out_forward.rb +2 -1
- data/test/plugin/test_out_roundrobin.rb +1 -12
- data/test/plugin/test_out_stdout.rb +1 -1
- data/test/plugin/test_out_stream.rb +2 -1
- data/test/scripts/fluent/plugin/formatter_known.rb +1 -4
- data/test/scripts/fluent/plugin/parser_known.rb +1 -2
- data/test/test_config.rb +1 -1
- data/test/test_configdsl.rb +2 -1
- data/test/test_formatter.rb +3 -395
- data/test/test_match.rb +2 -1
- data/test/test_mixin.rb +3 -75
- data/test/test_output.rb +1 -112
- data/test/test_parser.rb +85 -152
- metadata +58 -167
- data/example/v1_literal_example.conf +0 -36
- data/lib/fluent/plugin/in_dummy.rb +0 -103
- data/lib/fluent/timezone.rb +0 -131
- data/test/config/assertions.rb +0 -42
- data/test/config/test_config_parser.rb +0 -389
- data/test/config/test_configurable.rb +0 -652
- data/test/config/test_configure_proxy.rb +0 -99
- data/test/config/test_dsl.rb +0 -237
- data/test/config/test_literal_parser.rb +0 -295
- data/test/config/test_section.rb +0 -112
- data/test/config/test_system_config.rb +0 -99
- data/test/config/test_types.rb +0 -63
- data/test/plugin/test_in_dummy.rb +0 -95
- data/test/test_event.rb +0 -168
- data/test/test_input.rb +0 -21
data/lib/fluent/status.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# Copyright (C) 2011 FURUHASHI Sadayuki
|
2
|
+
# Fluentd
|
5
3
|
#
|
6
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
5
|
# you may not use this file except in compliance with the License.
|
@@ -15,6 +13,7 @@
|
|
15
13
|
# See the License for the specific language governing permissions and
|
16
14
|
# limitations under the License.
|
17
15
|
#
|
16
|
+
|
18
17
|
module Fluent
|
19
18
|
class StatusClass
|
20
19
|
def initialize
|
data/lib/fluent/supervisor.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# Copyright (C) 2011 FURUHASHI Sadayuki
|
2
|
+
# Fluentd
|
5
3
|
#
|
6
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
5
|
# you may not use this file except in compliance with the License.
|
@@ -73,11 +71,6 @@ module Fluent
|
|
73
71
|
end
|
74
72
|
self
|
75
73
|
end
|
76
|
-
|
77
|
-
def level=(level)
|
78
|
-
@level = level
|
79
|
-
$log.level = level
|
80
|
-
end
|
81
74
|
end
|
82
75
|
|
83
76
|
def self.default_options
|
@@ -94,14 +87,12 @@ module Fluent
|
|
94
87
|
:suppress_interval => 0,
|
95
88
|
:suppress_repeated_stacktrace => false,
|
96
89
|
:without_source => false,
|
97
|
-
:use_v1_config =>
|
98
|
-
:supervise => true,
|
90
|
+
:use_v1_config => true,
|
99
91
|
}
|
100
92
|
end
|
101
93
|
|
102
94
|
def initialize(opt)
|
103
95
|
@daemonize = opt[:daemonize]
|
104
|
-
@supervise = opt[:supervise]
|
105
96
|
@config_path = opt[:config_path]
|
106
97
|
@inline_config = opt[:inline_config]
|
107
98
|
@use_v1_config = opt[:use_v1_config]
|
@@ -112,6 +103,8 @@ module Fluent
|
|
112
103
|
@chgroup = opt[:chgroup]
|
113
104
|
@chuser = opt[:chuser]
|
114
105
|
|
106
|
+
apply_system_config(opt)
|
107
|
+
|
115
108
|
@log_level = opt[:log_level]
|
116
109
|
@suppress_interval = opt[:suppress_interval]
|
117
110
|
@suppress_config_dump = opt[:suppress_config_dump]
|
@@ -125,28 +118,13 @@ module Fluent
|
|
125
118
|
|
126
119
|
def start
|
127
120
|
@log.init
|
128
|
-
read_config
|
129
|
-
apply_system_config
|
130
121
|
|
131
122
|
dry_run if @dry_run
|
132
123
|
start_daemonize if @daemonize
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
change_privilege
|
138
|
-
init_engine
|
139
|
-
install_main_process_signal_handlers
|
140
|
-
run_configure
|
141
|
-
finish_daemonize if @daemonize
|
142
|
-
run_engine
|
143
|
-
exit 0
|
144
|
-
end
|
145
|
-
$log.error "fluentd main process died unexpectedly. restarting." unless @finished
|
146
|
-
end
|
147
|
-
else
|
148
|
-
$log.info "starting fluentd-#{Fluent::VERSION} without supervision"
|
149
|
-
main_process do
|
124
|
+
install_supervisor_signal_handlers
|
125
|
+
until @finished
|
126
|
+
supervise do
|
127
|
+
read_config
|
150
128
|
change_privilege
|
151
129
|
init_engine
|
152
130
|
install_main_process_signal_handlers
|
@@ -155,6 +133,7 @@ module Fluent
|
|
155
133
|
run_engine
|
156
134
|
exit 0
|
157
135
|
end
|
136
|
+
$log.error "fluentd main process died unexpectedly. restarting." unless @finished
|
158
137
|
end
|
159
138
|
end
|
160
139
|
|
@@ -172,6 +151,7 @@ module Fluent
|
|
172
151
|
def dry_run
|
173
152
|
$log.info "starting fluentd-#{Fluent::VERSION} as dry run mode"
|
174
153
|
|
154
|
+
read_config
|
175
155
|
change_privilege
|
176
156
|
init_engine
|
177
157
|
install_main_process_signal_handlers
|
@@ -323,16 +303,10 @@ module Fluent
|
|
323
303
|
trap :HUP do
|
324
304
|
$log.debug "fluentd supervisor process get SIGHUP"
|
325
305
|
$log.info "restarting"
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
apply_system_config
|
331
|
-
if pid = @main_pid
|
332
|
-
Process.kill(:TERM, pid)
|
333
|
-
# don't resuce Erro::ESRSH here (invalid status)
|
334
|
-
end
|
335
|
-
}.run
|
306
|
+
if pid = @main_pid
|
307
|
+
Process.kill(:TERM, pid)
|
308
|
+
# don't resuce Erro::ESRSH here (invalid status)
|
309
|
+
end
|
336
310
|
end
|
337
311
|
|
338
312
|
trap :USR1 do
|
@@ -355,7 +329,6 @@ module Fluent
|
|
355
329
|
elsif @inline_config
|
356
330
|
@config_data << "\n" << @inline_config.gsub("\\n","\n")
|
357
331
|
end
|
358
|
-
@conf = Fluent::Config.parse(@config_data, @config_fname, @config_basedir, @use_v1_config)
|
359
332
|
end
|
360
333
|
|
361
334
|
class SystemConfig
|
@@ -374,31 +347,37 @@ module Fluent
|
|
374
347
|
configure(conf)
|
375
348
|
end
|
376
349
|
|
377
|
-
def
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
}
|
350
|
+
def to_opt
|
351
|
+
opt = {}
|
352
|
+
opt[:log_level] = @log_level unless @log_level.nil?
|
353
|
+
opt[:suppress_interval] = @emit_error_log_interval unless @emit_error_log_interval.nil?
|
354
|
+
opt[:suppress_config_dump] = @suppress_config_dump unless @suppress_config_dump.nil?
|
355
|
+
opt[:suppress_repeated_stacktrace] = @suppress_repeated_stacktrace unless @suppress_repeated_stacktrace.nil?
|
356
|
+
opt[:without_source] = @without_source unless @without_source.nil?
|
357
|
+
opt
|
386
358
|
end
|
387
359
|
end
|
388
360
|
|
389
361
|
# TODO: this method should be moved to SystemConfig class method
|
390
|
-
def apply_system_config
|
391
|
-
|
362
|
+
def apply_system_config(opt)
|
363
|
+
# Create NULL file to avoid $log uninitialized problem before call @log.init
|
364
|
+
file = File.open(File::NULL)
|
365
|
+
$log = Fluent::Log.new(file, Log::LEVEL_INFO)
|
366
|
+
read_config
|
367
|
+
systems = Fluent::Config.parse(@config_data, @config_fname, @config_basedir, @use_v1_config).elements.select { |e|
|
392
368
|
e.name == 'system'
|
393
369
|
}
|
394
370
|
return if systems.empty?
|
395
371
|
raise ConfigError, "<system> is duplicated. <system> should be only one" if systems.size > 1
|
396
372
|
|
397
|
-
SystemConfig.new(systems.first).
|
373
|
+
opt.merge!(SystemConfig.new(systems.first).to_opt)
|
374
|
+
ensure
|
375
|
+
file.close
|
398
376
|
end
|
399
377
|
|
400
378
|
def run_configure
|
401
|
-
Fluent::
|
379
|
+
conf = Fluent::Config.parse(@config_data, @config_fname, @config_basedir, @use_v1_config)
|
380
|
+
Fluent::Engine.run_configure(conf)
|
402
381
|
end
|
403
382
|
|
404
383
|
def change_privilege
|
data/lib/fluent/test.rb
CHANGED
@@ -1,3 +1,19 @@
|
|
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
|
+
|
1
17
|
require 'test/unit'
|
2
18
|
require 'fluent/load'
|
3
19
|
require 'fluent/test/base'
|
data/lib/fluent/test/base.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# Copyright (C) 2011 FURUHASHI Sadayuki
|
2
|
+
# Fluentd
|
5
3
|
#
|
6
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
5
|
# you may not use this file except in compliance with the License.
|
@@ -15,22 +13,9 @@
|
|
15
13
|
# See the License for the specific language governing permissions and
|
16
14
|
# limitations under the License.
|
17
15
|
#
|
16
|
+
|
18
17
|
module Fluent
|
19
18
|
module Test
|
20
|
-
def self.setup
|
21
|
-
Fluent.__send__(:remove_const, :Engine)
|
22
|
-
engine = Fluent.const_set(:Engine, EngineClass.new).init
|
23
|
-
|
24
|
-
engine.define_singleton_method(:now=) {|n|
|
25
|
-
@now = n.to_i
|
26
|
-
}
|
27
|
-
engine.define_singleton_method(:now) {
|
28
|
-
@now || super()
|
29
|
-
}
|
30
|
-
|
31
|
-
nil
|
32
|
-
end
|
33
|
-
|
34
19
|
class TestDriver
|
35
20
|
include ::Test::Unit::Assertions
|
36
21
|
|
@@ -46,6 +31,7 @@ module Fluent
|
|
46
31
|
else
|
47
32
|
@instance = klass
|
48
33
|
end
|
34
|
+
@instance.router = Engine.root_agent.event_router
|
49
35
|
@instance.log = TestLogger.new
|
50
36
|
|
51
37
|
@config = Config.new
|
@@ -1,7 +1,5 @@
|
|
1
1
|
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# Copyright (C) 2011 FURUHASHI Sadayuki
|
2
|
+
# Fluentd
|
5
3
|
#
|
6
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
5
|
# you may not use this file except in compliance with the License.
|
@@ -15,6 +13,7 @@
|
|
15
13
|
# See the License for the specific language governing permissions and
|
16
14
|
# limitations under the License.
|
17
15
|
#
|
16
|
+
|
18
17
|
module Fluent
|
19
18
|
class FileBuffer < BasicBuffer
|
20
19
|
def self.clear_buffer_paths
|
@@ -75,19 +74,65 @@ module Fluent
|
|
75
74
|
all
|
76
75
|
end
|
77
76
|
|
77
|
+
def register_run_post_condition(&block)
|
78
|
+
if block
|
79
|
+
@run_post_conditions ||= []
|
80
|
+
@run_post_conditions << block
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def register_run_breaking_condition(&block)
|
85
|
+
if block
|
86
|
+
@run_breaking_conditions ||= []
|
87
|
+
@run_breaking_conditions << block
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def run_should_stop?
|
92
|
+
# Should stop running if post conditions are not registered.
|
93
|
+
return true unless @run_post_conditions
|
94
|
+
|
95
|
+
# Should stop running if all of the post conditions are true.
|
96
|
+
return true if @run_post_conditions.all? {|proc| proc.call }
|
97
|
+
|
98
|
+
# Should stop running if any of the breaking conditions is true.
|
99
|
+
# In this case, some post conditions may be not true.
|
100
|
+
return true if @run_breaking_conditions && @run_breaking_conditions.any? {|proc| proc.call }
|
101
|
+
|
102
|
+
false
|
103
|
+
end
|
104
|
+
|
78
105
|
def run(&block)
|
79
106
|
m = method(:emit_stream)
|
80
107
|
Engine.define_singleton_method(:emit_stream) {|tag,es|
|
81
108
|
m.call(tag, es)
|
82
109
|
}
|
110
|
+
instance.router.define_singleton_method(:emit_stream) {|tag,es|
|
111
|
+
m.call(tag, es)
|
112
|
+
}
|
83
113
|
super {
|
84
114
|
block.call if block
|
85
115
|
|
86
|
-
if @expected_emits_length || @expects
|
87
|
-
|
88
|
-
started_at = Time.now
|
116
|
+
if @expected_emits_length || @expects || @run_post_conditions
|
117
|
+
# counters for emits and emit_streams
|
89
118
|
i, j = 0, 0
|
90
|
-
|
119
|
+
|
120
|
+
# Events of expected length will be emitted at the end.
|
121
|
+
max_length = @expected_emits_length
|
122
|
+
max_length ||= @expects.length if @expects
|
123
|
+
if max_length
|
124
|
+
register_run_post_condition do
|
125
|
+
i == max_length
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Set runnning timeout to avoid infinite loop caused by some errors.
|
130
|
+
started_at = Time.now
|
131
|
+
register_run_breaking_condition do
|
132
|
+
Time.now >= started_at + @run_timeout
|
133
|
+
end
|
134
|
+
|
135
|
+
until run_should_stop?
|
91
136
|
if j >= @emit_streams.length
|
92
137
|
sleep 0.01
|
93
138
|
next
|
@@ -1,7 +1,5 @@
|
|
1
1
|
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# Copyright (C) 2011 FURUHASHI Sadayuki
|
2
|
+
# Fluentd
|
5
3
|
#
|
6
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
5
|
# you may not use this file except in compliance with the License.
|
@@ -15,6 +13,7 @@
|
|
15
13
|
# See the License for the specific language governing permissions and
|
16
14
|
# limitations under the License.
|
17
15
|
#
|
16
|
+
|
18
17
|
module Fluent
|
19
18
|
module Test
|
20
19
|
class TestOutputChain
|
@@ -53,10 +52,6 @@ module Fluent
|
|
53
52
|
@entries = []
|
54
53
|
@expected_buffer = nil
|
55
54
|
@tag = tag
|
56
|
-
|
57
|
-
def @instance.buffer
|
58
|
-
@buffer
|
59
|
-
end
|
60
55
|
end
|
61
56
|
|
62
57
|
attr_accessor :tag
|
@@ -82,19 +77,8 @@ module Fluent
|
|
82
77
|
assert_equal(@expected_buffer, buffer)
|
83
78
|
end
|
84
79
|
|
85
|
-
|
86
|
-
|
87
|
-
# this block is only for test_out_file
|
88
|
-
time, record = @entries.first
|
89
|
-
key = @instance.time_slicer.call(time)
|
90
|
-
end
|
91
|
-
chunk = @instance.buffer.new_chunk(key)
|
92
|
-
chunk << buffer
|
93
|
-
begin
|
94
|
-
result = @instance.write(chunk)
|
95
|
-
ensure
|
96
|
-
chunk.purge
|
97
|
-
end
|
80
|
+
chunk = MemoryBufferChunk.new('', buffer)
|
81
|
+
result = @instance.write(chunk)
|
98
82
|
}
|
99
83
|
result
|
100
84
|
end
|
data/lib/fluent/version.rb
CHANGED
@@ -1,5 +1,21 @@
|
|
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
|
+
|
1
17
|
module Fluent
|
2
18
|
|
3
|
-
VERSION = '0.
|
19
|
+
VERSION = '0.12.0.pre.1'
|
4
20
|
|
5
21
|
end
|
@@ -0,0 +1,314 @@
|
|
1
|
+
require "json"
|
2
|
+
require "config/helper"
|
3
|
+
require "fluent/config/error"
|
4
|
+
require "fluent/config/basic_parser"
|
5
|
+
require "fluent/config/literal_parser"
|
6
|
+
require "fluent/config/v1_parser"
|
7
|
+
|
8
|
+
describe Fluent::Config::V1Parser do
|
9
|
+
include_context 'config_helper'
|
10
|
+
|
11
|
+
def read_config(path)
|
12
|
+
path = File.expand_path(path)
|
13
|
+
data = File.read(path)
|
14
|
+
Fluent::Config::V1Parser.parse(data, File.basename(path), File.dirname(path))
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse_text(text)
|
18
|
+
basepath = File.expand_path(File.dirname(__FILE__) + '/../../')
|
19
|
+
Fluent::Config::V1Parser.parse(text, '(test)', basepath, nil)
|
20
|
+
end
|
21
|
+
|
22
|
+
def root(*elements)
|
23
|
+
if elements.first.is_a?(Fluent::Config::Element)
|
24
|
+
attrs = {}
|
25
|
+
else
|
26
|
+
attrs = elements.shift || {}
|
27
|
+
end
|
28
|
+
Fluent::Config::Element.new('ROOT', '', attrs, elements)
|
29
|
+
end
|
30
|
+
|
31
|
+
def e(name, arg='', attrs={}, elements=[])
|
32
|
+
Fluent::Config::Element.new(name, arg, attrs, elements)
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'attribute parsing' do
|
36
|
+
it "parses attributes" do
|
37
|
+
expect(%[
|
38
|
+
k1 v1
|
39
|
+
k2 v2
|
40
|
+
]).to be_parsed_as(e('ROOT', '', {"k1"=>"v1", "k2"=>"v2"}))
|
41
|
+
end
|
42
|
+
|
43
|
+
it "allows attribute without value" do
|
44
|
+
expect(%[
|
45
|
+
k1
|
46
|
+
k2 v2
|
47
|
+
]).to be_parsed_as(e('ROOT', '', {"k1"=>"", "k2"=>"v2"}))
|
48
|
+
end
|
49
|
+
|
50
|
+
it "parses attribute key always string" do
|
51
|
+
expect("1 1").to be_parsed_as(e('ROOT', '', {"1" => "1"}))
|
52
|
+
end
|
53
|
+
|
54
|
+
[
|
55
|
+
"_.%$!,",
|
56
|
+
"/=~-~@\`:?",
|
57
|
+
"()*{}.[]",
|
58
|
+
].each do |v|
|
59
|
+
it "parses a value with symbol #{v.inspect}" do
|
60
|
+
expect("k #{v}").to be_parsed_as(e('ROOT', '', {"k" => v}))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it "ignores spacing around value" do
|
65
|
+
expect(" k1 a ").to be_parsed_as(e('ROOT', '', {"k1" => "a"}))
|
66
|
+
end
|
67
|
+
|
68
|
+
it "allows spaces in value" do
|
69
|
+
expect("k1 a b c").to be_parsed_as(e('ROOT', '', {"k1" => "a b c"}))
|
70
|
+
end
|
71
|
+
|
72
|
+
it "ignores comments after value" do
|
73
|
+
expect(" k1 a#comment").to be_parsed_as(e('ROOT', '', {"k1" => "a"}))
|
74
|
+
end
|
75
|
+
|
76
|
+
it "allows # in value if quoted" do
|
77
|
+
expect(' k1 "a#comment"').to be_parsed_as(e('ROOT', '', {"k1" => "a#comment"}))
|
78
|
+
end
|
79
|
+
|
80
|
+
it "rejects characters after quoted string" do
|
81
|
+
expect(' k1 "a" 1').to be_parse_error
|
82
|
+
end
|
83
|
+
|
84
|
+
it "rejects @ prefix in parameter name" do
|
85
|
+
expect(' @k v').to be_parse_error
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'element parsing' do
|
90
|
+
it do
|
91
|
+
expect("").to be_parsed_as(root)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "accepts empty element" do
|
95
|
+
expect(%[
|
96
|
+
<test>
|
97
|
+
</test>
|
98
|
+
]).to be_parsed_as(
|
99
|
+
root(
|
100
|
+
e("test")
|
101
|
+
)
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "accepts argument and attributes" do
|
106
|
+
expect(%[
|
107
|
+
<test var>
|
108
|
+
key val
|
109
|
+
</test>
|
110
|
+
]).to be_parsed_as(root(
|
111
|
+
e("test", 'var', {'key'=>"val"})
|
112
|
+
))
|
113
|
+
end
|
114
|
+
|
115
|
+
it "accepts nested elements" do
|
116
|
+
expect(%[
|
117
|
+
<test var>
|
118
|
+
key 1
|
119
|
+
<nested1>
|
120
|
+
</nested1>
|
121
|
+
<nested2>
|
122
|
+
</nested2>
|
123
|
+
</test>
|
124
|
+
]).to be_parsed_as(root(
|
125
|
+
e("test", 'var', {'key'=>'1'}, [
|
126
|
+
e('nested1'),
|
127
|
+
e('nested2')
|
128
|
+
])
|
129
|
+
))
|
130
|
+
end
|
131
|
+
|
132
|
+
it "accepts multiline json values" do
|
133
|
+
expect(%[
|
134
|
+
<test var>
|
135
|
+
key ["a",
|
136
|
+
"b", "c",
|
137
|
+
"d"]
|
138
|
+
</test>
|
139
|
+
]).to be_parsed_as(root(
|
140
|
+
e("test", 'var', {'key'=>"[\"a\",\"b\",\"c\",\"d\"]"})
|
141
|
+
))
|
142
|
+
end
|
143
|
+
|
144
|
+
[
|
145
|
+
"**",
|
146
|
+
"*.*",
|
147
|
+
"1",
|
148
|
+
"_.%$!",
|
149
|
+
"/",
|
150
|
+
"()*{}.[]",
|
151
|
+
].each do |arg|
|
152
|
+
it "parses element argument #{arg.inspect}" do
|
153
|
+
expect(%[
|
154
|
+
<test #{arg}>
|
155
|
+
</test>
|
156
|
+
]).to be_parsed_as(root(
|
157
|
+
e("test", arg)
|
158
|
+
))
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
it "parses empty element argument to nil" do
|
163
|
+
expect(%[
|
164
|
+
<test >
|
165
|
+
</test>
|
166
|
+
]).to be_parsed_as(root(
|
167
|
+
e("test", '')
|
168
|
+
))
|
169
|
+
end
|
170
|
+
|
171
|
+
it "ignores spacing around element argument" do
|
172
|
+
expect(%[
|
173
|
+
<test a >
|
174
|
+
</test>
|
175
|
+
]).to be_parsed_as(root(
|
176
|
+
e("test", "a")
|
177
|
+
))
|
178
|
+
end
|
179
|
+
|
180
|
+
it "considers comments in element argument" do
|
181
|
+
expect(%[
|
182
|
+
<test #a>
|
183
|
+
</test>
|
184
|
+
]).to be_parse_error
|
185
|
+
end
|
186
|
+
|
187
|
+
it "requires line_end after begin tag" do
|
188
|
+
expect(%[
|
189
|
+
<test></test>
|
190
|
+
]).to be_parse_error
|
191
|
+
end
|
192
|
+
|
193
|
+
it "requires line_end after end tag" do
|
194
|
+
expect(%[
|
195
|
+
<test>
|
196
|
+
</test><test>
|
197
|
+
</test>
|
198
|
+
]).to be_parse_error
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# port from test_config.rb
|
203
|
+
describe '@include parsing' do
|
204
|
+
TMP_DIR = File.dirname(__FILE__) + "/tmp/v1_config#{ENV['TEST_ENV_NUMBER']}"
|
205
|
+
|
206
|
+
def write_config(path, data)
|
207
|
+
FileUtils.mkdir_p(File.dirname(path))
|
208
|
+
File.open(path, "w") { |f| f.write data }
|
209
|
+
end
|
210
|
+
|
211
|
+
def prepare_config
|
212
|
+
write_config "#{TMP_DIR}/config_test_1.conf", %[
|
213
|
+
k1 root_config
|
214
|
+
include dir/config_test_2.conf #
|
215
|
+
@include #{TMP_DIR}/config_test_4.conf
|
216
|
+
include file://#{TMP_DIR}/config_test_5.conf
|
217
|
+
@include config.d/*.conf
|
218
|
+
]
|
219
|
+
write_config "#{TMP_DIR}/dir/config_test_2.conf", %[
|
220
|
+
k2 relative_path_include
|
221
|
+
@include ../config_test_3.conf
|
222
|
+
]
|
223
|
+
write_config "#{TMP_DIR}/config_test_3.conf", %[
|
224
|
+
k3 relative_include_in_included_file
|
225
|
+
]
|
226
|
+
write_config "#{TMP_DIR}/config_test_4.conf", %[
|
227
|
+
k4 absolute_path_include
|
228
|
+
]
|
229
|
+
write_config "#{TMP_DIR}/config_test_5.conf", %[
|
230
|
+
k5 uri_include
|
231
|
+
]
|
232
|
+
write_config "#{TMP_DIR}/config.d/config_test_6.conf", %[
|
233
|
+
k6 wildcard_include_1
|
234
|
+
<elem1 name>
|
235
|
+
include normal_parameter
|
236
|
+
</elem1>
|
237
|
+
]
|
238
|
+
write_config "#{TMP_DIR}/config.d/config_test_7.conf", %[
|
239
|
+
k7 wildcard_include_2
|
240
|
+
]
|
241
|
+
write_config "#{TMP_DIR}/config.d/config_test_8.conf", %[
|
242
|
+
<elem2 name>
|
243
|
+
@include ../dir/config_test_9.conf
|
244
|
+
</elem2>
|
245
|
+
]
|
246
|
+
write_config "#{TMP_DIR}/dir/config_test_9.conf", %[
|
247
|
+
k9 embeded
|
248
|
+
<elem3 name>
|
249
|
+
nested nested_value
|
250
|
+
include hoge
|
251
|
+
</elem3>
|
252
|
+
]
|
253
|
+
write_config "#{TMP_DIR}/config.d/00_config_test_8.conf", %[
|
254
|
+
k8 wildcard_include_3
|
255
|
+
<elem4 name>
|
256
|
+
include normal_parameter
|
257
|
+
</elem4>
|
258
|
+
]
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'parses @include / include correctly' do
|
262
|
+
prepare_config
|
263
|
+
c = read_config("#{TMP_DIR}/config_test_1.conf")
|
264
|
+
expect(c['k1']).to eq('root_config')
|
265
|
+
expect(c['k2']).to eq('relative_path_include')
|
266
|
+
expect(c['k3']).to eq('relative_include_in_included_file')
|
267
|
+
expect(c['k4']).to eq('absolute_path_include')
|
268
|
+
expect(c['k5']).to eq('uri_include')
|
269
|
+
expect(c['k6']).to eq('wildcard_include_1')
|
270
|
+
expect(c['k7']).to eq('wildcard_include_2')
|
271
|
+
expect(c['k8']).to eq('wildcard_include_3')
|
272
|
+
expect(c.keys).to eq([
|
273
|
+
'k1',
|
274
|
+
'k2',
|
275
|
+
'k3',
|
276
|
+
'k4',
|
277
|
+
'k5',
|
278
|
+
'k8', # Because of the file name this comes first.
|
279
|
+
'k6',
|
280
|
+
'k7',
|
281
|
+
])
|
282
|
+
|
283
|
+
elem1 = c.elements.find { |e| e.name == 'elem1' }
|
284
|
+
expect(elem1).to be
|
285
|
+
expect(elem1.arg).to eq('name')
|
286
|
+
expect(elem1['include']).to eq('normal_parameter')
|
287
|
+
|
288
|
+
elem2 = c.elements.find { |e| e.name == 'elem2' }
|
289
|
+
expect(elem2).to be
|
290
|
+
expect(elem2.arg).to eq('name')
|
291
|
+
expect(elem2['k9']).to eq('embeded')
|
292
|
+
expect(elem2.has_key?('include')).to be(false)
|
293
|
+
|
294
|
+
elem3 = elem2.elements.find { |e| e.name == 'elem3' }
|
295
|
+
expect(elem3).to be
|
296
|
+
expect(elem3['nested']).to eq('nested_value')
|
297
|
+
expect(elem3['include']).to eq('hoge')
|
298
|
+
end
|
299
|
+
|
300
|
+
# TODO: Add uri based include spec
|
301
|
+
end
|
302
|
+
|
303
|
+
describe 'unescape parameter' do
|
304
|
+
it 'parses dumpped configuration' do
|
305
|
+
original = %q!a\\\\\n\r\f\b\\'\\"z!
|
306
|
+
expected = %!a\\\n\r\f\b'"z!
|
307
|
+
|
308
|
+
conf = parse_text(%[k1 #{original}])
|
309
|
+
expect(conf['k1']).to eq(expected) # escape check
|
310
|
+
conf2 = parse_text(conf.to_s) # use dumpped configuration to check unescape
|
311
|
+
expect(conf2.elements.first['k1']).to eq(expected)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|