fluentd 0.12.40 → 0.14.0
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/.github/ISSUE_TEMPLATE.md +6 -0
- data/.gitignore +2 -0
- data/.travis.yml +33 -21
- data/CONTRIBUTING.md +1 -0
- data/ChangeLog +810 -237
- data/README.md +0 -25
- data/Rakefile +2 -1
- data/Vagrantfile +17 -0
- data/appveyor.yml +35 -0
- data/example/filter_stdout.conf +5 -5
- data/example/in_forward.conf +2 -2
- data/example/in_http.conf +2 -2
- data/example/in_out_forward.conf +17 -0
- data/example/in_syslog.conf +2 -2
- data/example/in_tail.conf +2 -2
- data/example/in_tcp.conf +2 -2
- data/example/in_udp.conf +2 -2
- data/example/out_copy.conf +4 -4
- data/example/out_file.conf +2 -2
- data/example/out_forward.conf +2 -2
- data/example/out_forward_buf_file.conf +23 -0
- data/example/v0_12_filter.conf +8 -8
- data/fluent.conf +29 -0
- data/fluentd.gemspec +18 -11
- data/lib/fluent/agent.rb +60 -58
- data/lib/fluent/command/cat.rb +1 -1
- data/lib/fluent/command/debug.rb +7 -5
- data/lib/fluent/command/fluentd.rb +97 -2
- data/lib/fluent/compat/call_super_mixin.rb +67 -0
- data/lib/fluent/compat/filter.rb +50 -0
- data/lib/fluent/compat/formatter.rb +109 -0
- data/lib/fluent/compat/input.rb +50 -0
- data/lib/fluent/compat/output.rb +617 -0
- data/lib/fluent/compat/output_chain.rb +60 -0
- data/lib/fluent/compat/parser.rb +163 -0
- data/lib/fluent/compat/propagate_default.rb +62 -0
- data/lib/fluent/config.rb +23 -20
- data/lib/fluent/config/configure_proxy.rb +119 -70
- data/lib/fluent/config/dsl.rb +5 -18
- data/lib/fluent/config/element.rb +72 -8
- data/lib/fluent/config/error.rb +0 -3
- data/lib/fluent/config/literal_parser.rb +0 -2
- data/lib/fluent/config/parser.rb +4 -4
- data/lib/fluent/config/section.rb +39 -28
- data/lib/fluent/config/types.rb +2 -13
- data/lib/fluent/config/v1_parser.rb +1 -3
- data/lib/fluent/configurable.rb +48 -16
- data/lib/fluent/daemon.rb +15 -0
- data/lib/fluent/engine.rb +26 -52
- data/lib/fluent/env.rb +6 -4
- data/lib/fluent/event.rb +58 -11
- data/lib/fluent/event_router.rb +5 -5
- data/lib/fluent/filter.rb +2 -50
- data/lib/fluent/formatter.rb +4 -293
- data/lib/fluent/input.rb +2 -32
- data/lib/fluent/label.rb +2 -2
- data/lib/fluent/load.rb +3 -2
- data/lib/fluent/log.rb +107 -38
- data/lib/fluent/match.rb +0 -36
- data/lib/fluent/mixin.rb +117 -7
- data/lib/fluent/msgpack_factory.rb +62 -0
- data/lib/fluent/output.rb +7 -612
- data/lib/fluent/output_chain.rb +23 -0
- data/lib/fluent/parser.rb +4 -800
- data/lib/fluent/plugin.rb +100 -121
- data/lib/fluent/plugin/bare_output.rb +63 -0
- data/lib/fluent/plugin/base.rb +121 -0
- data/lib/fluent/plugin/buf_file.rb +101 -182
- data/lib/fluent/plugin/buf_memory.rb +9 -92
- data/lib/fluent/plugin/buffer.rb +473 -0
- data/lib/fluent/plugin/buffer/chunk.rb +135 -0
- data/lib/fluent/plugin/buffer/file_chunk.rb +339 -0
- data/lib/fluent/plugin/buffer/memory_chunk.rb +100 -0
- data/lib/fluent/plugin/exec_util.rb +80 -75
- data/lib/fluent/plugin/file_util.rb +33 -28
- data/lib/fluent/plugin/file_wrapper.rb +120 -0
- data/lib/fluent/plugin/filter.rb +51 -0
- data/lib/fluent/plugin/filter_grep.rb +13 -40
- data/lib/fluent/plugin/filter_record_transformer.rb +22 -18
- data/lib/fluent/plugin/formatter.rb +93 -0
- data/lib/fluent/plugin/formatter_csv.rb +48 -0
- data/lib/fluent/plugin/formatter_hash.rb +32 -0
- data/lib/fluent/plugin/formatter_json.rb +47 -0
- data/lib/fluent/plugin/formatter_ltsv.rb +42 -0
- data/lib/fluent/plugin/formatter_msgpack.rb +32 -0
- data/lib/fluent/plugin/formatter_out_file.rb +45 -0
- data/lib/fluent/plugin/formatter_single_value.rb +34 -0
- data/lib/fluent/plugin/formatter_stdout.rb +39 -0
- data/lib/fluent/plugin/in_debug_agent.rb +4 -0
- data/lib/fluent/plugin/in_dummy.rb +22 -18
- data/lib/fluent/plugin/in_exec.rb +18 -8
- data/lib/fluent/plugin/in_forward.rb +36 -79
- data/lib/fluent/plugin/in_gc_stat.rb +4 -0
- data/lib/fluent/plugin/in_http.rb +21 -18
- data/lib/fluent/plugin/in_monitor_agent.rb +15 -48
- data/lib/fluent/plugin/in_object_space.rb +6 -1
- data/lib/fluent/plugin/in_stream.rb +7 -3
- data/lib/fluent/plugin/in_syslog.rb +46 -95
- data/lib/fluent/plugin/in_tail.rb +51 -595
- data/lib/fluent/plugin/in_tcp.rb +8 -1
- data/lib/fluent/plugin/in_udp.rb +8 -14
- data/lib/fluent/plugin/input.rb +33 -0
- data/lib/fluent/plugin/multi_output.rb +95 -0
- data/lib/fluent/plugin/out_buffered_null.rb +59 -0
- data/lib/fluent/plugin/out_copy.rb +11 -7
- data/lib/fluent/plugin/out_exec.rb +15 -11
- data/lib/fluent/plugin/out_exec_filter.rb +18 -10
- data/lib/fluent/plugin/out_file.rb +34 -5
- data/lib/fluent/plugin/out_forward.rb +19 -9
- data/lib/fluent/plugin/out_null.rb +0 -14
- data/lib/fluent/plugin/out_roundrobin.rb +11 -7
- data/lib/fluent/plugin/out_stdout.rb +5 -7
- data/lib/fluent/plugin/out_stream.rb +3 -1
- data/lib/fluent/plugin/output.rb +979 -0
- data/lib/fluent/plugin/owned_by_mixin.rb +42 -0
- data/lib/fluent/plugin/parser.rb +244 -0
- data/lib/fluent/plugin/parser_apache.rb +24 -0
- data/lib/fluent/plugin/parser_apache2.rb +84 -0
- data/lib/fluent/plugin/parser_apache_error.rb +21 -0
- data/lib/fluent/plugin/parser_csv.rb +31 -0
- data/lib/fluent/plugin/parser_json.rb +79 -0
- data/lib/fluent/plugin/parser_ltsv.rb +50 -0
- data/lib/fluent/plugin/parser_multiline.rb +102 -0
- data/lib/fluent/plugin/parser_nginx.rb +24 -0
- data/lib/fluent/plugin/parser_none.rb +36 -0
- data/lib/fluent/plugin/parser_syslog.rb +82 -0
- data/lib/fluent/plugin/parser_tsv.rb +37 -0
- data/lib/fluent/plugin/socket_util.rb +120 -114
- data/lib/fluent/plugin/storage.rb +84 -0
- data/lib/fluent/plugin/storage_local.rb +116 -0
- data/lib/fluent/plugin/string_util.rb +16 -13
- data/lib/fluent/plugin_helper.rb +39 -0
- data/lib/fluent/plugin_helper/child_process.rb +298 -0
- data/lib/fluent/plugin_helper/compat_parameters.rb +99 -0
- data/lib/fluent/plugin_helper/event_emitter.rb +80 -0
- data/lib/fluent/plugin_helper/event_loop.rb +118 -0
- data/lib/fluent/plugin_helper/retry_state.rb +177 -0
- data/lib/fluent/plugin_helper/storage.rb +308 -0
- data/lib/fluent/plugin_helper/thread.rb +147 -0
- data/lib/fluent/plugin_helper/timer.rb +85 -0
- data/lib/fluent/plugin_id.rb +63 -0
- data/lib/fluent/process.rb +21 -30
- data/lib/fluent/registry.rb +21 -9
- data/lib/fluent/root_agent.rb +115 -40
- data/lib/fluent/supervisor.rb +330 -320
- data/lib/fluent/system_config.rb +42 -18
- data/lib/fluent/test.rb +6 -1
- data/lib/fluent/test/base.rb +23 -3
- data/lib/fluent/test/driver/base.rb +247 -0
- data/lib/fluent/test/driver/event_feeder.rb +98 -0
- data/lib/fluent/test/driver/filter.rb +35 -0
- data/lib/fluent/test/driver/input.rb +31 -0
- data/lib/fluent/test/driver/output.rb +78 -0
- data/lib/fluent/test/driver/test_event_router.rb +45 -0
- data/lib/fluent/test/filter_test.rb +0 -1
- data/lib/fluent/test/formatter_test.rb +2 -1
- data/lib/fluent/test/input_test.rb +23 -17
- data/lib/fluent/test/output_test.rb +28 -39
- data/lib/fluent/test/parser_test.rb +1 -1
- data/lib/fluent/time.rb +104 -1
- data/lib/fluent/{status.rb → unique_id.rb} +15 -24
- data/lib/fluent/version.rb +1 -1
- data/lib/fluent/winsvc.rb +72 -0
- data/test/compat/test_calls_super.rb +164 -0
- data/test/config/test_config_parser.rb +83 -0
- data/test/config/test_configurable.rb +547 -274
- data/test/config/test_configure_proxy.rb +146 -29
- data/test/config/test_dsl.rb +3 -181
- data/test/config/test_element.rb +274 -0
- data/test/config/test_literal_parser.rb +1 -1
- data/test/config/test_section.rb +79 -7
- data/test/config/test_system_config.rb +21 -0
- data/test/config/test_types.rb +3 -26
- data/test/helper.rb +78 -8
- data/test/plugin/test_bare_output.rb +118 -0
- data/test/plugin/test_base.rb +75 -0
- data/test/plugin/test_buf_file.rb +420 -521
- data/test/plugin/test_buf_memory.rb +32 -194
- data/test/plugin/test_buffer.rb +981 -0
- data/test/plugin/test_buffer_chunk.rb +110 -0
- data/test/plugin/test_buffer_file_chunk.rb +770 -0
- data/test/plugin/test_buffer_memory_chunk.rb +265 -0
- data/test/plugin/test_filter.rb +255 -0
- data/test/plugin/test_filter_grep.rb +2 -73
- data/test/plugin/test_filter_record_transformer.rb +24 -68
- data/test/plugin/test_filter_stdout.rb +6 -6
- data/test/plugin/test_in_debug_agent.rb +2 -0
- data/test/plugin/test_in_dummy.rb +11 -17
- data/test/plugin/test_in_exec.rb +6 -25
- data/test/plugin/test_in_forward.rb +112 -151
- data/test/plugin/test_in_gc_stat.rb +2 -0
- data/test/plugin/test_in_http.rb +106 -157
- data/test/plugin/test_in_object_space.rb +21 -5
- data/test/plugin/test_in_stream.rb +14 -13
- data/test/plugin/test_in_syslog.rb +30 -275
- data/test/plugin/test_in_tail.rb +95 -234
- data/test/plugin/test_in_tcp.rb +14 -0
- data/test/plugin/test_in_udp.rb +21 -13
- data/test/plugin/test_input.rb +122 -0
- data/test/plugin/test_multi_output.rb +180 -0
- data/test/plugin/test_out_buffered_null.rb +79 -0
- data/test/plugin/test_out_copy.rb +15 -2
- data/test/plugin/test_out_exec.rb +75 -25
- data/test/plugin/test_out_exec_filter.rb +74 -8
- data/test/plugin/test_out_file.rb +61 -7
- data/test/plugin/test_out_forward.rb +92 -15
- data/test/plugin/test_out_roundrobin.rb +1 -0
- data/test/plugin/test_out_stdout.rb +22 -13
- data/test/plugin/test_out_stream.rb +18 -0
- data/test/plugin/test_output.rb +515 -0
- data/test/plugin/test_output_as_buffered.rb +1540 -0
- data/test/plugin/test_output_as_buffered_overflow.rb +247 -0
- data/test/plugin/test_output_as_buffered_retries.rb +808 -0
- data/test/plugin/test_output_as_buffered_secondary.rb +776 -0
- data/test/plugin/test_output_as_standard.rb +362 -0
- data/test/plugin/test_owned_by.rb +35 -0
- data/test/plugin/test_storage.rb +167 -0
- data/test/plugin/test_storage_local.rb +8 -0
- data/test/plugin_helper/test_child_process.rb +599 -0
- data/test/plugin_helper/test_compat_parameters.rb +175 -0
- data/test/plugin_helper/test_event_emitter.rb +51 -0
- data/test/plugin_helper/test_event_loop.rb +52 -0
- data/test/plugin_helper/test_retry_state.rb +399 -0
- data/test/plugin_helper/test_storage.rb +411 -0
- data/test/plugin_helper/test_thread.rb +164 -0
- data/test/plugin_helper/test_timer.rb +100 -0
- data/test/scripts/exec_script.rb +0 -6
- data/test/scripts/fluent/plugin/out_test.rb +3 -0
- data/test/test_config.rb +13 -4
- data/test/test_event.rb +24 -13
- data/test/test_event_router.rb +8 -7
- data/test/test_event_time.rb +187 -0
- data/test/test_formatter.rb +13 -51
- data/test/test_input.rb +1 -1
- data/test/test_log.rb +239 -16
- data/test/test_mixin.rb +1 -1
- data/test/test_output.rb +53 -66
- data/test/test_parser.rb +105 -323
- data/test/test_plugin_helper.rb +81 -0
- data/test/test_root_agent.rb +4 -52
- data/test/test_supervisor.rb +272 -0
- data/test/test_unique_id.rb +47 -0
- metadata +180 -54
- data/lib/fluent/buffer.rb +0 -365
- data/lib/fluent/plugin/filter_parser.rb +0 -107
- data/lib/fluent/plugin/in_status.rb +0 -76
- data/lib/fluent/test/helpers.rb +0 -86
- data/test/plugin/data/log/foo/bar2 +0 -0
- data/test/plugin/test_filter_parser.rb +0 -744
- data/test/plugin/test_in_status.rb +0 -38
- data/test/test_buffer.rb +0 -624
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative '../helper'
|
2
2
|
require 'fluent/test'
|
3
|
+
require 'fluent/plugin/out_forward'
|
3
4
|
|
4
5
|
class ForwardOutputTest < Test::Unit::TestCase
|
5
6
|
def setup
|
@@ -10,6 +11,7 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
10
11
|
TARGET_PORT = 13999
|
11
12
|
CONFIG = %[
|
12
13
|
send_timeout 51
|
14
|
+
heartbeat_type udp
|
13
15
|
<server>
|
14
16
|
name test
|
15
17
|
host #{TARGET_HOST}
|
@@ -39,21 +41,20 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
39
41
|
@exceptions << e
|
40
42
|
raise e
|
41
43
|
end
|
42
|
-
|
43
|
-
# Fluentd v0.12 BufferedOutputTestDriver calls this method.
|
44
|
-
# BufferedOutput#format_stream calls format method, but ForwardOutput#format is not defined.
|
45
|
-
# Because ObjectBufferedOutput#emit calls es.to_msgpack_stream directly.
|
46
|
-
def format_stream(tag, es)
|
47
|
-
es.to_msgpack_stream
|
48
|
-
end
|
49
44
|
}.configure(conf)
|
50
45
|
end
|
51
46
|
|
52
47
|
def test_configure
|
53
|
-
d = create_driver
|
48
|
+
d = create_driver(%[
|
49
|
+
<server>
|
50
|
+
name test
|
51
|
+
host #{TARGET_HOST}
|
52
|
+
port #{TARGET_PORT}
|
53
|
+
</server>
|
54
|
+
])
|
54
55
|
nodes = d.instance.nodes
|
55
|
-
assert_equal
|
56
|
-
assert_equal :
|
56
|
+
assert_equal 60, d.instance.send_timeout
|
57
|
+
assert_equal :tcp, d.instance.heartbeat_type
|
57
58
|
assert_equal 1, nodes.length
|
58
59
|
node = nodes.first
|
59
60
|
assert_equal "test", node.name
|
@@ -61,9 +62,9 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
61
62
|
assert_equal 13999, node.port
|
62
63
|
end
|
63
64
|
|
64
|
-
def
|
65
|
-
d = create_driver(CONFIG + "\nheartbeat_type
|
66
|
-
assert_equal :
|
65
|
+
def test_configure_udp_heartbeat
|
66
|
+
d = create_driver(CONFIG + "\nheartbeat_type udp")
|
67
|
+
assert_equal :udp, d.instance.heartbeat_type
|
67
68
|
end
|
68
69
|
|
69
70
|
def test_configure_none_heartbeat
|
@@ -119,6 +120,75 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
119
120
|
assert_equal 2, d.instance.ack_response_timeout
|
120
121
|
end
|
121
122
|
|
123
|
+
def test_send_with_time_as_integer
|
124
|
+
target_input_driver = create_target_input_driver
|
125
|
+
|
126
|
+
d = create_driver(CONFIG + %[flush_interval 1s])
|
127
|
+
|
128
|
+
time = Fluent::EventTime.parse("2011-01-02 13:14:15 UTC")
|
129
|
+
|
130
|
+
records = [
|
131
|
+
{"a" => 1},
|
132
|
+
{"a" => 2}
|
133
|
+
]
|
134
|
+
d.register_run_post_condition do
|
135
|
+
d.instance.responses.length == 1
|
136
|
+
end
|
137
|
+
|
138
|
+
target_input_driver.run do
|
139
|
+
d.run do
|
140
|
+
records.each do |record|
|
141
|
+
d.emit record, time
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
emits = target_input_driver.emits
|
147
|
+
assert_equal ['test', time, records[0]], emits[0]
|
148
|
+
assert_equal ['test', time, records[1]], emits[1]
|
149
|
+
assert(emits[0][1].is_a?(Integer))
|
150
|
+
assert(emits[1][1].is_a?(Integer))
|
151
|
+
|
152
|
+
assert_equal [nil], d.instance.responses # not attempt to receive responses, so nil is returned
|
153
|
+
assert_empty d.instance.exceptions
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_send_without_time_as_integer
|
157
|
+
target_input_driver = create_target_input_driver
|
158
|
+
|
159
|
+
d = create_driver(CONFIG + %[
|
160
|
+
flush_interval 1s
|
161
|
+
time_as_integer false
|
162
|
+
])
|
163
|
+
|
164
|
+
time = Fluent::EventTime.parse("2011-01-02 13:14:15 UTC")
|
165
|
+
|
166
|
+
records = [
|
167
|
+
{"a" => 1},
|
168
|
+
{"a" => 2}
|
169
|
+
]
|
170
|
+
d.register_run_post_condition do
|
171
|
+
d.instance.responses.length == 1
|
172
|
+
end
|
173
|
+
|
174
|
+
target_input_driver.run do
|
175
|
+
d.run do
|
176
|
+
records.each do |record|
|
177
|
+
d.emit record, time
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
emits = target_input_driver.emits
|
183
|
+
assert_equal ['test', time, records[0]], emits[0]
|
184
|
+
assert_equal ['test', time, records[1]], emits[1]
|
185
|
+
assert_equal_event_time(time, emits[0][1])
|
186
|
+
assert_equal_event_time(time, emits[1][1])
|
187
|
+
|
188
|
+
assert_equal [nil], d.instance.responses # not attempt to receive responses, so nil is returned
|
189
|
+
assert_empty d.instance.exceptions
|
190
|
+
end
|
191
|
+
|
122
192
|
def test_send_to_a_node_supporting_responses
|
123
193
|
target_input_driver = create_target_input_driver(true)
|
124
194
|
|
@@ -305,6 +375,7 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
305
375
|
def create_target_input_driver(do_respond=false, disconnect=false, conf=TARGET_CONFIG)
|
306
376
|
require 'fluent/plugin/in_forward'
|
307
377
|
|
378
|
+
# TODO: Support actual TCP heartbeat test
|
308
379
|
DummyEngineDriver.new(Fluent::ForwardInput) {
|
309
380
|
handler_class = Class.new(Fluent::ForwardInput::Handler) { |klass|
|
310
381
|
attr_reader :chunk_counter # for checking if received data is successfully deserialized
|
@@ -314,12 +385,14 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
314
385
|
@log = log
|
315
386
|
@chunk_counter = 0
|
316
387
|
@on_message = on_message
|
388
|
+
@source = nil
|
317
389
|
end
|
318
390
|
|
319
391
|
if do_respond
|
320
392
|
def write(data)
|
321
393
|
@sock.write data
|
322
|
-
rescue
|
394
|
+
rescue
|
395
|
+
@sock.close_write
|
323
396
|
@sock.close
|
324
397
|
end
|
325
398
|
else
|
@@ -338,7 +411,7 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
338
411
|
|
339
412
|
define_method(:start) do
|
340
413
|
@thread = Thread.new do
|
341
|
-
Socket.tcp_server_loop(@
|
414
|
+
Socket.tcp_server_loop(@bind, @port) do |sock, client_addrinfo|
|
342
415
|
begin
|
343
416
|
handler = handler_class.new(sock, @log, method(:on_message))
|
344
417
|
loop do
|
@@ -416,6 +489,10 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
416
489
|
@emit_streams ||= []
|
417
490
|
end
|
418
491
|
|
492
|
+
def clear!
|
493
|
+
@emit_streams = []
|
494
|
+
end
|
495
|
+
|
419
496
|
def emit_stream(tag, es)
|
420
497
|
@emit_streams << [tag, es.to_a]
|
421
498
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative '../helper'
|
2
|
-
require 'fluent/test'
|
2
|
+
require 'fluent/test/driver/output'
|
3
|
+
require 'fluent/plugin/out_stdout'
|
3
4
|
|
4
5
|
class StdoutOutputTest < Test::Unit::TestCase
|
5
6
|
def setup
|
@@ -10,7 +11,7 @@ class StdoutOutputTest < Test::Unit::TestCase
|
|
10
11
|
]
|
11
12
|
|
12
13
|
def create_driver(conf = CONFIG)
|
13
|
-
Fluent::Test::
|
14
|
+
Fluent::Test::Driver::Output.new(Fluent::Plugin::StdoutOutput).configure(conf)
|
14
15
|
end
|
15
16
|
|
16
17
|
def test_configure
|
@@ -33,28 +34,36 @@ class StdoutOutputTest < Test::Unit::TestCase
|
|
33
34
|
data('oj' => 'oj', 'yajl' => 'yajl')
|
34
35
|
def test_emit_json(data)
|
35
36
|
d = create_driver(CONFIG + "\noutput_type json\njson_parser #{data}")
|
36
|
-
time =
|
37
|
-
out = capture_log
|
38
|
-
|
37
|
+
time = event_time()
|
38
|
+
out = capture_log do
|
39
|
+
d.run(default_tag: 'test') do
|
40
|
+
d.feed(time, {'test' => 'test'})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
assert_equal "#{Time.at(time).localtime} test: {\"test\":\"test\"}\n", out
|
39
44
|
|
40
45
|
if data == 'yajl'
|
41
46
|
# NOTE: Float::NAN is not jsonable
|
42
|
-
assert_raise(Yajl::EncodeError) { d.
|
47
|
+
assert_raise(Yajl::EncodeError) { d.feed('test', time, {'test' => Float::NAN}) }
|
43
48
|
else
|
44
|
-
out = capture_log { d.
|
45
|
-
assert_equal "#{time.localtime} test: {\"test\":NaN}\n", out
|
49
|
+
out = capture_log { d.feed('test', time, {'test' => Float::NAN}) }
|
50
|
+
assert_equal "#{Time.at(time).localtime} test: {\"test\":NaN}\n", out
|
46
51
|
end
|
47
52
|
end
|
48
53
|
|
49
54
|
def test_emit_hash
|
50
55
|
d = create_driver(CONFIG + "\noutput_type hash")
|
51
|
-
time =
|
52
|
-
out = capture_log
|
53
|
-
|
56
|
+
time = event_time()
|
57
|
+
out = capture_log do
|
58
|
+
d.run(default_tag: 'test') do
|
59
|
+
d.feed(time, {'test' => 'test'})
|
60
|
+
end
|
61
|
+
end
|
62
|
+
assert_equal "#{Time.at(time).localtime} test: {\"test\"=>\"test\"}\n", out
|
54
63
|
|
55
64
|
# NOTE: Float::NAN is not jsonable, but hash string can output it.
|
56
|
-
out = capture_log { d.
|
57
|
-
assert_equal "#{time.localtime} test: {\"test\"=>NaN}\n", out
|
65
|
+
out = capture_log { d.feed('test', time, {'test' => Float::NAN}) }
|
66
|
+
assert_equal "#{Time.at(time).localtime} test: {\"test\"=>NaN}\n", out
|
58
67
|
end
|
59
68
|
|
60
69
|
private
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative '../helper'
|
2
2
|
require 'fluent/test'
|
3
|
+
require 'fluent/plugin/out_stream'
|
3
4
|
|
4
5
|
module StreamOutputTest
|
5
6
|
def setup
|
@@ -22,6 +23,23 @@ module StreamOutputTest
|
|
22
23
|
assert_equal(expect, result)
|
23
24
|
end
|
24
25
|
|
26
|
+
def test_write_event_time
|
27
|
+
d = create_driver
|
28
|
+
|
29
|
+
time = Fluent::EventTime.parse("2011-01-02 13:14:15 UTC")
|
30
|
+
d.emit({"a"=>1}, time)
|
31
|
+
d.emit({"a"=>2}, time)
|
32
|
+
|
33
|
+
expect = ["test",
|
34
|
+
Fluent::Engine.msgpack_factory.packer.write([time,{"a"=>1}]).to_s +
|
35
|
+
Fluent::Engine.msgpack_factory.packer.write([time,{"a"=>2}]).to_s
|
36
|
+
]
|
37
|
+
expect = Fluent::Engine.msgpack_factory.packer.write(expect).to_s
|
38
|
+
|
39
|
+
result = d.run
|
40
|
+
assert_equal(expect, result)
|
41
|
+
end
|
42
|
+
|
25
43
|
def create_driver(klass, conf)
|
26
44
|
Fluent::Test::BufferedOutputTestDriver.new(klass) do
|
27
45
|
def write(chunk)
|
@@ -0,0 +1,515 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
require 'fluent/plugin/output'
|
3
|
+
require 'fluent/plugin/buffer'
|
4
|
+
require 'fluent/event'
|
5
|
+
|
6
|
+
require 'json'
|
7
|
+
require 'time'
|
8
|
+
require 'timeout'
|
9
|
+
|
10
|
+
module FluentPluginOutputTest
|
11
|
+
class DummyBareOutput < Fluent::Plugin::Output
|
12
|
+
def register(name, &block)
|
13
|
+
instance_variable_set("@#{name}", block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
class DummySyncOutput < DummyBareOutput
|
17
|
+
def initialize
|
18
|
+
super
|
19
|
+
@process = nil
|
20
|
+
end
|
21
|
+
def process(tag, es)
|
22
|
+
@process ? @process.call(tag, es) : nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
class DummyAsyncOutput < DummyBareOutput
|
26
|
+
def initialize
|
27
|
+
super
|
28
|
+
@format = nil
|
29
|
+
@write = nil
|
30
|
+
end
|
31
|
+
def format(tag, time, record)
|
32
|
+
@format ? @format.call(tag, time, record) : [tag, time, record].to_json
|
33
|
+
end
|
34
|
+
def write(chunk)
|
35
|
+
@write ? @write.call(chunk) : nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
class DummyAsyncStandardOutput < DummyBareOutput
|
39
|
+
def initialize
|
40
|
+
super
|
41
|
+
@write = nil
|
42
|
+
end
|
43
|
+
def write(chunk)
|
44
|
+
@write ? @write.call(chunk) : nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
class DummyDelayedOutput < DummyBareOutput
|
48
|
+
def initialize
|
49
|
+
super
|
50
|
+
@format = nil
|
51
|
+
@try_write = nil
|
52
|
+
end
|
53
|
+
def format(tag, time, record)
|
54
|
+
@format ? @format.call(tag, time, record) : [tag, time, record].to_json
|
55
|
+
end
|
56
|
+
def try_write(chunk)
|
57
|
+
@try_write ? @try_write.call(chunk) : nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
class DummyDelayedStandardOutput < DummyBareOutput
|
61
|
+
def initialize
|
62
|
+
super
|
63
|
+
@try_write = nil
|
64
|
+
end
|
65
|
+
def try_write(chunk)
|
66
|
+
@try_write ? @try_write.call(chunk) : nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
class DummyFullFeatureOutput < DummyBareOutput
|
70
|
+
def initialize
|
71
|
+
super
|
72
|
+
@prefer_buffered_processing = nil
|
73
|
+
@prefer_delayed_commit = nil
|
74
|
+
@process = nil
|
75
|
+
@format = nil
|
76
|
+
@write = nil
|
77
|
+
@try_write = nil
|
78
|
+
end
|
79
|
+
def prefer_buffered_processing
|
80
|
+
@prefer_buffered_processing ? @prefer_buffered_processing.call : false
|
81
|
+
end
|
82
|
+
def prefer_delayed_commit
|
83
|
+
@prefer_delayed_commit ? @prefer_delayed_commit.call : false
|
84
|
+
end
|
85
|
+
def process(tag, es)
|
86
|
+
@process ? @process.call(tag, es) : nil
|
87
|
+
end
|
88
|
+
def format(tag, time, record)
|
89
|
+
@format ? @format.call(tag, time, record) : [tag, time, record].to_json
|
90
|
+
end
|
91
|
+
def write(chunk)
|
92
|
+
@write ? @write.call(chunk) : nil
|
93
|
+
end
|
94
|
+
def try_write(chunk)
|
95
|
+
@try_write ? @try_write.call(chunk) : nil
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class OutputTest < Test::Unit::TestCase
|
101
|
+
def create_output(type=:full)
|
102
|
+
case type
|
103
|
+
when :bare then FluentPluginOutputTest::DummyBareOutput.new
|
104
|
+
when :sync then FluentPluginOutputTest::DummySyncOutput.new
|
105
|
+
when :buffered then FluentPluginOutputTest::DummyAsyncOutput.new
|
106
|
+
when :standard then FluentPluginOutputTest::DummyAsyncStandardOutput.new
|
107
|
+
when :delayed then FluentPluginOutputTest::DummyDelayedOutput.new
|
108
|
+
when :sdelayed then FluentPluginOutputTest::DummyDelayedStandardOutput.new
|
109
|
+
when :full then FluentPluginOutputTest::DummyFullFeatureOutput.new
|
110
|
+
else
|
111
|
+
raise ArgumentError, "unknown type: #{type}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
def create_metadata(timekey: nil, tag: nil, variables: nil)
|
115
|
+
Fluent::Plugin::Buffer::Metadata.new(timekey, tag, variables)
|
116
|
+
end
|
117
|
+
def waiting(seconds)
|
118
|
+
begin
|
119
|
+
Timeout.timeout(seconds) do
|
120
|
+
yield
|
121
|
+
end
|
122
|
+
rescue Timeout::Error
|
123
|
+
STDERR.print(*@i.log.out.logs)
|
124
|
+
raise
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
sub_test_case 'basic output feature' do
|
129
|
+
setup do
|
130
|
+
@i = create_output(:full)
|
131
|
+
end
|
132
|
+
|
133
|
+
test '#implement? can return features for plugin instances' do
|
134
|
+
i1 = FluentPluginOutputTest::DummyBareOutput.new
|
135
|
+
assert !i1.implement?(:synchronous)
|
136
|
+
assert !i1.implement?(:buffered)
|
137
|
+
assert !i1.implement?(:delayed_commit)
|
138
|
+
assert !i1.implement?(:custom_format)
|
139
|
+
|
140
|
+
i2 = FluentPluginOutputTest::DummySyncOutput.new
|
141
|
+
assert i2.implement?(:synchronous)
|
142
|
+
assert !i2.implement?(:buffered)
|
143
|
+
assert !i2.implement?(:delayed_commit)
|
144
|
+
assert !i2.implement?(:custom_format)
|
145
|
+
|
146
|
+
i3 = FluentPluginOutputTest::DummyAsyncOutput.new
|
147
|
+
assert !i3.implement?(:synchronous)
|
148
|
+
assert i3.implement?(:buffered)
|
149
|
+
assert !i3.implement?(:delayed_commit)
|
150
|
+
assert i3.implement?(:custom_format)
|
151
|
+
|
152
|
+
i4 = FluentPluginOutputTest::DummyAsyncStandardOutput.new
|
153
|
+
assert !i4.implement?(:synchronous)
|
154
|
+
assert i4.implement?(:buffered)
|
155
|
+
assert !i4.implement?(:delayed_commit)
|
156
|
+
assert !i4.implement?(:custom_format)
|
157
|
+
|
158
|
+
i5 = FluentPluginOutputTest::DummyDelayedOutput.new
|
159
|
+
assert !i5.implement?(:synchronous)
|
160
|
+
assert !i5.implement?(:buffered)
|
161
|
+
assert i5.implement?(:delayed_commit)
|
162
|
+
assert i5.implement?(:custom_format)
|
163
|
+
|
164
|
+
i6 = FluentPluginOutputTest::DummyDelayedStandardOutput.new
|
165
|
+
assert !i6.implement?(:synchronous)
|
166
|
+
assert !i6.implement?(:buffered)
|
167
|
+
assert i6.implement?(:delayed_commit)
|
168
|
+
assert !i6.implement?(:custom_format)
|
169
|
+
|
170
|
+
i6 = FluentPluginOutputTest::DummyFullFeatureOutput.new
|
171
|
+
assert i6.implement?(:synchronous)
|
172
|
+
assert i6.implement?(:buffered)
|
173
|
+
assert i6.implement?(:delayed_commit)
|
174
|
+
assert i6.implement?(:custom_format)
|
175
|
+
end
|
176
|
+
|
177
|
+
test 'plugin lifecycle for configure/start/stop/before_shutdown/shutdown/after_shutdown/close/terminate' do
|
178
|
+
assert !@i.configured?
|
179
|
+
@i.configure(config_element())
|
180
|
+
assert @i.configured?
|
181
|
+
assert !@i.started?
|
182
|
+
@i.start
|
183
|
+
assert @i.started?
|
184
|
+
assert !@i.stopped?
|
185
|
+
@i.stop
|
186
|
+
assert @i.stopped?
|
187
|
+
assert !@i.before_shutdown?
|
188
|
+
@i.before_shutdown
|
189
|
+
assert @i.before_shutdown?
|
190
|
+
assert !@i.shutdown?
|
191
|
+
@i.shutdown
|
192
|
+
assert @i.shutdown?
|
193
|
+
assert !@i.after_shutdown?
|
194
|
+
@i.after_shutdown
|
195
|
+
assert @i.after_shutdown?
|
196
|
+
assert !@i.closed?
|
197
|
+
@i.close
|
198
|
+
assert @i.closed?
|
199
|
+
assert !@i.terminated?
|
200
|
+
@i.terminate
|
201
|
+
assert @i.terminated?
|
202
|
+
end
|
203
|
+
|
204
|
+
test '#extract_placeholders does nothing if chunk key is not specified' do
|
205
|
+
@i.configure(config_element('ROOT', '', {}, [config_element('buffer', '')]))
|
206
|
+
assert !@i.chunk_key_time
|
207
|
+
assert !@i.chunk_key_tag
|
208
|
+
assert_equal [], @i.chunk_keys
|
209
|
+
tmpl = "/mypath/%Y/%m/%d/${tag}/${tag[1]}/${tag[2]}/${key1}/${key2}/tail"
|
210
|
+
t = event_time('2016-04-11 20:30:00 +0900')
|
211
|
+
v = {key1: "value1", key2: "value2"}
|
212
|
+
m = create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
|
213
|
+
assert_equal tmpl, @i.extract_placeholders(tmpl, m)
|
214
|
+
end
|
215
|
+
|
216
|
+
test '#extract_placeholders can extract time if time key and range are configured' do
|
217
|
+
@i.configure(config_element('ROOT', '', {}, [config_element('buffer', 'time', {'timekey' => 60*30, 'timekey_zone' => "+0900"})]))
|
218
|
+
assert @i.chunk_key_time
|
219
|
+
assert !@i.chunk_key_tag
|
220
|
+
assert_equal [], @i.chunk_keys
|
221
|
+
tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[1]}/${tag[2]}/${key1}/${key2}/tail"
|
222
|
+
t = event_time('2016-04-11 20:30:00 +0900')
|
223
|
+
v = {key1: "value1", key2: "value2"}
|
224
|
+
m = create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
|
225
|
+
assert_equal "/mypath/2016/04/11/20-30/${tag}/${tag[1]}/${tag[2]}/${key1}/${key2}/tail", @i.extract_placeholders(tmpl, m)
|
226
|
+
end
|
227
|
+
|
228
|
+
test '#extract_placeholders can extract tag and parts of tag if tag is configured' do
|
229
|
+
@i.configure(config_element('ROOT', '', {}, [config_element('buffer', 'tag', {})]))
|
230
|
+
assert !@i.chunk_key_time
|
231
|
+
assert @i.chunk_key_tag
|
232
|
+
assert_equal [], @i.chunk_keys
|
233
|
+
tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[1]}/${tag[2]}/${key1}/${key2}/tail"
|
234
|
+
t = event_time('2016-04-11 20:30:00 +0900')
|
235
|
+
v = {key1: "value1", key2: "value2"}
|
236
|
+
m = create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
|
237
|
+
assert_equal "/mypath/%Y/%m/%d/%H-%M/fluentd.test.output/test/output/${key1}/${key2}/tail", @i.extract_placeholders(tmpl, m)
|
238
|
+
end
|
239
|
+
|
240
|
+
test '#extract_placeholders can extract variables if variables are configured' do
|
241
|
+
@i.configure(config_element('ROOT', '', {}, [config_element('buffer', 'key1,key2', {})]))
|
242
|
+
assert !@i.chunk_key_time
|
243
|
+
assert !@i.chunk_key_tag
|
244
|
+
assert_equal ['key1','key2'], @i.chunk_keys
|
245
|
+
tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[1]}/${tag[2]}/${key1}/${key2}/tail"
|
246
|
+
t = event_time('2016-04-11 20:30:00 +0900')
|
247
|
+
v = {key1: "value1", key2: "value2"}
|
248
|
+
m = create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
|
249
|
+
assert_equal "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[1]}/${tag[2]}/value1/value2/tail", @i.extract_placeholders(tmpl, m)
|
250
|
+
end
|
251
|
+
|
252
|
+
test '#extract_placeholders can extract all chunk keys if configured' do
|
253
|
+
@i.configure(config_element('ROOT', '', {}, [config_element('buffer', 'time,tag,key1,key2', {'timekey' => 60*30, 'timekey_zone' => "+0900"})]))
|
254
|
+
assert @i.chunk_key_time
|
255
|
+
assert @i.chunk_key_tag
|
256
|
+
assert_equal ['key1','key2'], @i.chunk_keys
|
257
|
+
tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[1]}/${tag[2]}/${key1}/${key2}/tail"
|
258
|
+
t = event_time('2016-04-11 20:30:00 +0900')
|
259
|
+
v = {key1: "value1", key2: "value2"}
|
260
|
+
m = create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
|
261
|
+
assert_equal "/mypath/2016/04/11/20-30/fluentd.test.output/test/output/value1/value2/tail", @i.extract_placeholders(tmpl, m)
|
262
|
+
end
|
263
|
+
|
264
|
+
test '#extract_placeholders removes out-of-range tag part and unknown variable placeholders' do
|
265
|
+
@i.configure(config_element('ROOT', '', {}, [config_element('buffer', 'time,tag,key1,key2', {'timekey' => 60*30, 'timekey_zone' => "+0900"})]))
|
266
|
+
assert @i.chunk_key_time
|
267
|
+
assert @i.chunk_key_tag
|
268
|
+
assert_equal ['key1','key2'], @i.chunk_keys
|
269
|
+
tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[3]}/${tag[4]}/${key3}/${key4}/tail"
|
270
|
+
t = event_time('2016-04-11 20:30:00 +0900')
|
271
|
+
v = {key1: "value1", key2: "value2"}
|
272
|
+
m = create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
|
273
|
+
assert_equal "/mypath/2016/04/11/20-30/fluentd.test.output/////tail", @i.extract_placeholders(tmpl, m)
|
274
|
+
end
|
275
|
+
|
276
|
+
test '#metadata returns object which contains tag/timekey/variables from records as specified in configuration' do
|
277
|
+
tag = 'test.output'
|
278
|
+
time = event_time('2016-04-12 15:31:23 -0700')
|
279
|
+
timekey = event_time('2016-04-12 15:00:00 -0700')
|
280
|
+
record = {"key1" => "value1", "num1" => 1, "message" => "my message"}
|
281
|
+
|
282
|
+
i1 = create_output(:buffered)
|
283
|
+
i1.configure(config_element('ROOT','',{},[config_element('buffer', '')]))
|
284
|
+
assert_equal create_metadata(), i1.metadata(tag, time, record)
|
285
|
+
|
286
|
+
i2 = create_output(:buffered)
|
287
|
+
i2.configure(config_element('ROOT','',{},[config_element('buffer', 'tag')]))
|
288
|
+
assert_equal create_metadata(tag: tag), i2.metadata(tag, time, record)
|
289
|
+
|
290
|
+
i3 = create_output(:buffered)
|
291
|
+
i3.configure(config_element('ROOT','',{},[config_element('buffer', 'time', {"timekey" => 3600, "timekey_zone" => "-0700"})]))
|
292
|
+
assert_equal create_metadata(timekey: timekey), i3.metadata(tag, time, record)
|
293
|
+
|
294
|
+
i4 = create_output(:buffered)
|
295
|
+
i4.configure(config_element('ROOT','',{},[config_element('buffer', 'key1', {})]))
|
296
|
+
assert_equal create_metadata(variables: {key1: "value1"}), i4.metadata(tag, time, record)
|
297
|
+
|
298
|
+
i5 = create_output(:buffered)
|
299
|
+
i5.configure(config_element('ROOT','',{},[config_element('buffer', 'key1,num1', {})]))
|
300
|
+
assert_equal create_metadata(variables: {key1: "value1", num1: 1}), i5.metadata(tag, time, record)
|
301
|
+
|
302
|
+
i6 = create_output(:buffered)
|
303
|
+
i6.configure(config_element('ROOT','',{},[config_element('buffer', 'tag,time', {"timekey" => 3600, "timekey_zone" => "-0700"})]))
|
304
|
+
assert_equal create_metadata(timekey: timekey, tag: tag), i6.metadata(tag, time, record)
|
305
|
+
|
306
|
+
i7 = create_output(:buffered)
|
307
|
+
i7.configure(config_element('ROOT','',{},[config_element('buffer', 'tag,num1', {"timekey" => 3600, "timekey_zone" => "-0700"})]))
|
308
|
+
assert_equal create_metadata(tag: tag, variables: {num1: 1}), i7.metadata(tag, time, record)
|
309
|
+
|
310
|
+
i8 = create_output(:buffered)
|
311
|
+
i8.configure(config_element('ROOT','',{},[config_element('buffer', 'time,tag,key1', {"timekey" => 3600, "timekey_zone" => "-0700"})]))
|
312
|
+
assert_equal create_metadata(timekey: timekey, tag: tag, variables: {key1: "value1"}), i8.metadata(tag, time, record)
|
313
|
+
end
|
314
|
+
|
315
|
+
test '#emit calls #process via #emit_sync for non-buffered output' do
|
316
|
+
i = create_output(:sync)
|
317
|
+
process_called = false
|
318
|
+
i.register(:process){|tag, es| process_called = true }
|
319
|
+
i.configure(config_element())
|
320
|
+
i.start
|
321
|
+
|
322
|
+
t = event_time()
|
323
|
+
i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
|
324
|
+
|
325
|
+
assert process_called
|
326
|
+
|
327
|
+
i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
|
328
|
+
end
|
329
|
+
|
330
|
+
test '#emit calls #format for buffered output' do
|
331
|
+
i = create_output(:buffered)
|
332
|
+
format_called_times = 0
|
333
|
+
i.register(:format){|tag, time, record| format_called_times += 1; '' }
|
334
|
+
i.configure(config_element())
|
335
|
+
i.start
|
336
|
+
|
337
|
+
t = event_time()
|
338
|
+
i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
|
339
|
+
|
340
|
+
assert_equal 2, format_called_times
|
341
|
+
|
342
|
+
i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
|
343
|
+
end
|
344
|
+
|
345
|
+
test '#prefer_buffered_processing (returns false) decides non-buffered without <buffer> section' do
|
346
|
+
i = create_output(:full)
|
347
|
+
|
348
|
+
process_called = false
|
349
|
+
format_called_times = 0
|
350
|
+
i.register(:process){|tag, es| process_called = true }
|
351
|
+
i.register(:format){|tag, time, record| format_called_times += 1; '' }
|
352
|
+
|
353
|
+
i.configure(config_element())
|
354
|
+
i.register(:prefer_buffered_processing){ false } # delayed decision is possible to change after (output's) configure
|
355
|
+
i.start
|
356
|
+
|
357
|
+
assert !i.prefer_buffered_processing
|
358
|
+
|
359
|
+
t = event_time()
|
360
|
+
i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
|
361
|
+
|
362
|
+
waiting(4){ Thread.pass until process_called }
|
363
|
+
|
364
|
+
assert process_called
|
365
|
+
assert_equal 0, format_called_times
|
366
|
+
|
367
|
+
i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
|
368
|
+
end
|
369
|
+
|
370
|
+
test '#prefer_buffered_processing (returns true) decides buffered without <buffer> section' do
|
371
|
+
i = create_output(:full)
|
372
|
+
|
373
|
+
process_called = false
|
374
|
+
format_called_times = 0
|
375
|
+
i.register(:process){|tag, es| process_called = true }
|
376
|
+
i.register(:format){|tag, time, record| format_called_times += 1; '' }
|
377
|
+
|
378
|
+
i.configure(config_element())
|
379
|
+
i.register(:prefer_buffered_processing){ true } # delayed decision is possible to change after (output's) configure
|
380
|
+
i.start
|
381
|
+
|
382
|
+
assert i.prefer_buffered_processing
|
383
|
+
|
384
|
+
t = event_time()
|
385
|
+
i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
|
386
|
+
|
387
|
+
assert !process_called
|
388
|
+
assert_equal 2, format_called_times
|
389
|
+
|
390
|
+
i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
|
391
|
+
end
|
392
|
+
|
393
|
+
test 'output plugin will call #write for normal buffered plugin to flush buffer chunks' do
|
394
|
+
i = create_output(:buffered)
|
395
|
+
write_called = false
|
396
|
+
i.register(:write){ |chunk| write_called = true }
|
397
|
+
|
398
|
+
i.configure(config_element('ROOT', '', {}, [config_element('buffer', '', {"flush_mode" => "immediate"})]))
|
399
|
+
i.start
|
400
|
+
|
401
|
+
t = event_time()
|
402
|
+
i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
|
403
|
+
i.force_flush
|
404
|
+
|
405
|
+
waiting(4){ Thread.pass until write_called }
|
406
|
+
|
407
|
+
assert write_called
|
408
|
+
|
409
|
+
i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
|
410
|
+
end
|
411
|
+
|
412
|
+
test 'output plugin will call #try_write for plugin supports delayed commit only to flush buffer chunks' do
|
413
|
+
i = create_output(:delayed)
|
414
|
+
try_write_called = false
|
415
|
+
i.register(:try_write){|chunk| try_write_called = true; commit_write(chunk.unique_id) }
|
416
|
+
|
417
|
+
i.configure(config_element('ROOT', '', {}, [config_element('buffer', '', {"flush_mode" => "immediate"})]))
|
418
|
+
i.start
|
419
|
+
|
420
|
+
t = event_time()
|
421
|
+
i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
|
422
|
+
i.force_flush
|
423
|
+
|
424
|
+
waiting(4){ Thread.pass until try_write_called }
|
425
|
+
|
426
|
+
assert try_write_called
|
427
|
+
|
428
|
+
i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
|
429
|
+
end
|
430
|
+
|
431
|
+
test '#prefer_delayed_commit (returns false) decides delayed commit is disabled if both are implemented' do
|
432
|
+
i = create_output(:full)
|
433
|
+
write_called = false
|
434
|
+
try_write_called = false
|
435
|
+
i.register(:write){ |chunk| write_called = true }
|
436
|
+
i.register(:try_write){|chunk| try_write_called = true; commit_write(chunk.unique_id) }
|
437
|
+
|
438
|
+
i.configure(config_element('ROOT', '', {}, [config_element('buffer', '', {"flush_mode" => "immediate"})]))
|
439
|
+
i.register(:prefer_delayed_commit){ false } # delayed decision is possible to change after (output's) configure
|
440
|
+
i.start
|
441
|
+
|
442
|
+
assert !i.prefer_delayed_commit
|
443
|
+
|
444
|
+
t = event_time()
|
445
|
+
i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
|
446
|
+
i.force_flush
|
447
|
+
|
448
|
+
waiting(4){ Thread.pass until write_called || try_write_called }
|
449
|
+
|
450
|
+
assert write_called
|
451
|
+
assert !try_write_called
|
452
|
+
|
453
|
+
i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
|
454
|
+
end
|
455
|
+
|
456
|
+
test '#prefer_delayed_commit (returns true) decides delayed commit is enabled if both are implemented' do
|
457
|
+
i = create_output(:full)
|
458
|
+
write_called = false
|
459
|
+
try_write_called = false
|
460
|
+
i.register(:write){ |chunk| write_called = true }
|
461
|
+
i.register(:try_write){|chunk| try_write_called = true; commit_write(chunk.unique_id) }
|
462
|
+
|
463
|
+
i.configure(config_element('ROOT', '', {}, [config_element('buffer', '', {"flush_mode" => "immediate"})]))
|
464
|
+
i.register(:prefer_delayed_commit){ true } # delayed decision is possible to change after (output's) configure
|
465
|
+
i.start
|
466
|
+
|
467
|
+
assert i.prefer_delayed_commit
|
468
|
+
|
469
|
+
t = event_time()
|
470
|
+
i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
|
471
|
+
i.force_flush
|
472
|
+
|
473
|
+
waiting(4){ Thread.pass until write_called || try_write_called }
|
474
|
+
|
475
|
+
assert !write_called
|
476
|
+
assert try_write_called
|
477
|
+
|
478
|
+
i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
sub_test_case 'sync output feature' do
|
483
|
+
setup do
|
484
|
+
@i = create_output(:sync)
|
485
|
+
end
|
486
|
+
|
487
|
+
test 'raises configuration error if <buffer> section is specified' do
|
488
|
+
assert_raise Fluent::ConfigError do
|
489
|
+
@i.configure(config_element('ROOT','',{},[config_element('buffer', '')]))
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
test 'raises configuration error if <secondary> section is specified' do
|
494
|
+
assert_raise Fluent::ConfigError do
|
495
|
+
@i.configure(config_element('ROOT','',{},[config_element('secondary','')]))
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
test '#process is called for each event streams' do
|
500
|
+
ary = []
|
501
|
+
@i.register(:process){|tag, es| ary << [tag, es] }
|
502
|
+
@i.configure(config_element())
|
503
|
+
@i.start
|
504
|
+
|
505
|
+
t = event_time()
|
506
|
+
es = Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ])
|
507
|
+
5.times do
|
508
|
+
@i.emit_events('tag', es)
|
509
|
+
end
|
510
|
+
assert_equal 5, ary.size
|
511
|
+
|
512
|
+
@i.stop; @i.before_shutdown; @i.shutdown; @i.after_shutdown; @i.close; @i.terminate
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|