fluentd 0.14.11-x64-mingw32 → 0.14.12-x64-mingw32
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 +1 -5
- data/ChangeLog +54 -2
- data/example/in_dummy_blocks.conf +17 -0
- data/example/in_forward_tls.conf +14 -0
- data/example/in_forward_workers.conf +21 -0
- data/example/logevents.conf +25 -0
- data/example/out_forward_heartbeat_none.conf +16 -0
- data/example/out_forward_tls.conf +18 -0
- data/example/suppress_config_dump.conf +7 -0
- data/lib/fluent/agent.rb +3 -32
- data/lib/fluent/clock.rb +62 -0
- data/lib/fluent/command/fluentd.rb +12 -0
- data/lib/fluent/compat/input.rb +10 -1
- data/lib/fluent/compat/output.rb +40 -1
- data/lib/fluent/config/configure_proxy.rb +30 -7
- data/lib/fluent/config/section.rb +4 -0
- data/lib/fluent/config/types.rb +2 -2
- data/lib/fluent/configurable.rb +31 -5
- data/lib/fluent/engine.rb +61 -12
- data/lib/fluent/event_router.rb +6 -0
- data/lib/fluent/load.rb +0 -1
- data/lib/fluent/log.rb +118 -42
- data/lib/fluent/match.rb +37 -0
- data/lib/fluent/plugin.rb +25 -3
- data/lib/fluent/plugin/base.rb +4 -0
- data/lib/fluent/plugin/buf_file.rb +38 -14
- data/lib/fluent/plugin/buffer.rb +20 -20
- data/lib/fluent/plugin/buffer/file_chunk.rb +2 -2
- data/lib/fluent/plugin/compressable.rb +1 -0
- data/lib/fluent/plugin/filter_record_transformer.rb +3 -6
- data/lib/fluent/plugin/formatter_csv.rb +4 -1
- data/lib/fluent/plugin/formatter_hash.rb +5 -1
- data/lib/fluent/plugin/formatter_json.rb +10 -0
- data/lib/fluent/plugin/formatter_ltsv.rb +2 -1
- data/lib/fluent/plugin/in_dummy.rb +4 -0
- data/lib/fluent/plugin/in_exec.rb +4 -0
- data/lib/fluent/plugin/in_forward.rb +11 -3
- data/lib/fluent/plugin/in_gc_stat.rb +4 -0
- data/lib/fluent/plugin/in_http.rb +4 -0
- data/lib/fluent/plugin/in_monitor_agent.rb +29 -2
- data/lib/fluent/plugin/in_object_space.rb +4 -1
- data/lib/fluent/plugin/in_syslog.rb +4 -0
- data/lib/fluent/plugin/in_tail.rb +193 -116
- data/lib/fluent/plugin/in_tcp.rb +5 -1
- data/lib/fluent/plugin/in_udp.rb +4 -0
- data/lib/fluent/plugin/input.rb +4 -0
- data/lib/fluent/plugin/out_copy.rb +4 -0
- data/lib/fluent/plugin/out_exec.rb +4 -0
- data/lib/fluent/plugin/out_exec_filter.rb +4 -0
- data/lib/fluent/plugin/out_file.rb +70 -30
- data/lib/fluent/plugin/out_forward.rb +132 -28
- data/lib/fluent/plugin/out_null.rb +10 -0
- data/lib/fluent/plugin/out_relabel.rb +4 -0
- data/lib/fluent/plugin/out_roundrobin.rb +4 -0
- data/lib/fluent/plugin/out_secondary_file.rb +5 -0
- data/lib/fluent/plugin/out_stdout.rb +5 -0
- data/lib/fluent/plugin/output.rb +18 -9
- data/lib/fluent/plugin/storage_local.rb +25 -2
- data/lib/fluent/plugin_helper/cert_option.rb +159 -0
- data/lib/fluent/plugin_helper/child_process.rb +6 -6
- data/lib/fluent/plugin_helper/compat_parameters.rb +1 -1
- data/lib/fluent/plugin_helper/event_loop.rb +29 -4
- data/lib/fluent/plugin_helper/inject.rb +14 -1
- data/lib/fluent/plugin_helper/server.rb +275 -31
- data/lib/fluent/plugin_helper/socket.rb +144 -4
- data/lib/fluent/plugin_helper/socket_option.rb +2 -17
- data/lib/fluent/plugin_helper/storage.rb +7 -1
- data/lib/fluent/plugin_helper/thread.rb +16 -4
- data/lib/fluent/registry.rb +26 -9
- data/lib/fluent/root_agent.rb +7 -3
- data/lib/fluent/supervisor.rb +37 -15
- data/lib/fluent/system_config.rb +37 -10
- data/lib/fluent/test.rb +2 -0
- data/lib/fluent/test/driver/base.rb +24 -26
- data/lib/fluent/test/helpers.rb +21 -0
- data/lib/fluent/version.rb +1 -1
- data/test/command/test_fluentd.rb +274 -4
- data/test/config/test_configurable.rb +154 -0
- data/test/config/test_configure_proxy.rb +180 -1
- data/test/config/test_system_config.rb +10 -0
- data/test/config/test_types.rb +1 -0
- data/test/plugin/test_base.rb +4 -0
- data/test/plugin/test_buf_file.rb +241 -9
- data/test/plugin/test_buffer.rb +11 -11
- data/test/plugin/test_buffer_file_chunk.rb +6 -6
- data/test/plugin/test_compressable.rb +3 -0
- data/test/plugin/test_filter.rb +4 -0
- data/test/plugin/test_filter_record_transformer.rb +20 -0
- data/test/plugin/test_formatter_csv.rb +9 -0
- data/test/plugin/test_formatter_hash.rb +35 -0
- data/test/plugin/test_formatter_json.rb +8 -0
- data/test/plugin/test_formatter_ltsv.rb +7 -0
- data/test/plugin/test_in_dummy.rb +7 -3
- data/test/plugin/test_in_monitor_agent.rb +43 -5
- data/test/plugin/test_in_tail.rb +97 -4
- data/test/plugin/test_input.rb +4 -0
- data/test/plugin/test_out_file.rb +46 -7
- data/test/plugin/test_out_forward.rb +59 -7
- data/test/plugin/test_output.rb +10 -4
- data/test/plugin/test_output_as_buffered.rb +37 -25
- data/test/plugin/test_output_as_buffered_compress.rb +1 -1
- data/test/plugin/test_output_as_buffered_retries.rb +6 -6
- data/test/plugin/test_output_as_buffered_secondary.rb +91 -31
- data/test/plugin/test_storage_local.rb +40 -1
- data/test/plugin_helper/test_child_process.rb +29 -28
- data/test/plugin_helper/test_compat_parameters.rb +1 -1
- data/test/plugin_helper/test_inject.rb +27 -9
- data/test/plugin_helper/test_server.rb +822 -50
- data/test/plugin_helper/test_storage.rb +11 -0
- data/test/plugin_helper/test_timer.rb +1 -0
- data/test/test_clock.rb +164 -0
- data/test/test_log.rb +146 -15
- data/test/test_plugin.rb +251 -0
- data/test/test_supervisor.rb +65 -57
- data/test/test_test_drivers.rb +2 -2
- metadata +18 -7
- data/lib/fluent/process.rb +0 -504
- data/test/test_process.rb +0 -48
@@ -104,6 +104,26 @@ class RecordTransformerFilterTest < Test::Unit::TestCase
|
|
104
104
|
filtered.each_with_index do |(time, _record), i|
|
105
105
|
assert_equal(times[i].to_i, time)
|
106
106
|
assert(time.is_a?(Fluent::EventTime))
|
107
|
+
assert_true(_record.has_key?('message'))
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
test 'renew_time_key and remove_keys' do
|
112
|
+
config = %[
|
113
|
+
renew_time_key event_time_key
|
114
|
+
remove_keys event_time_key
|
115
|
+
auto_typecast true
|
116
|
+
<record>
|
117
|
+
event_time_key ${record["message"]}
|
118
|
+
</record>
|
119
|
+
]
|
120
|
+
times = [Time.local(2, 2, 3, 4, 5, 2010, nil, nil, nil, nil), Time.local(3, 2, 3, 4, 5, 2010, nil, nil, nil, nil)]
|
121
|
+
msgs = times.map { |t| t.to_f.to_s }
|
122
|
+
filtered = filter(config, msgs)
|
123
|
+
filtered.each_with_index do |(time, _record), i|
|
124
|
+
assert_equal(times[i].to_i, time)
|
125
|
+
assert(time.is_a?(Fluent::EventTime))
|
126
|
+
assert_false(_record.has_key?('event_time_key'))
|
107
127
|
end
|
108
128
|
end
|
109
129
|
|
@@ -54,6 +54,15 @@ class CsvFormatterTest < ::Test::Unit::TestCase
|
|
54
54
|
assert_equal("\"awesome\",\"awesome2\"\n", formatted)
|
55
55
|
end
|
56
56
|
|
57
|
+
def test_format_without_newline
|
58
|
+
d = create_driver("fields" => "message,message2", "add_newline" => false)
|
59
|
+
formatted = d.instance.format(tag, @time, {
|
60
|
+
'message' => 'awesome',
|
61
|
+
'message2' => 'awesome2'
|
62
|
+
})
|
63
|
+
assert_equal("\"awesome\",\"awesome2\"", formatted)
|
64
|
+
end
|
65
|
+
|
57
66
|
def test_format_with_customized_delimiters
|
58
67
|
d = create_driver("fields" => "message,message2",
|
59
68
|
"delimiter" => "\t")
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
require 'fluent/test/driver/formatter'
|
3
|
+
require 'fluent/plugin/formatter_hash'
|
4
|
+
|
5
|
+
class HashFormatterTest < ::Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@time = event_time
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_driver(conf = "")
|
11
|
+
Fluent::Test::Driver::Formatter.new(Fluent::Plugin::HashFormatter).configure(conf)
|
12
|
+
end
|
13
|
+
|
14
|
+
def tag
|
15
|
+
"tag"
|
16
|
+
end
|
17
|
+
|
18
|
+
def record
|
19
|
+
{'message' => 'awesome', 'greeting' => 'hello'}
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_format
|
23
|
+
d = create_driver({})
|
24
|
+
formatted = d.instance.format(tag, @time, record)
|
25
|
+
|
26
|
+
assert_equal(%Q!{"message"=>"awesome", "greeting"=>"hello"}\n!, formatted.encode(Encoding::UTF_8))
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_format_without_newline
|
30
|
+
d = create_driver('add_newline' => false)
|
31
|
+
formatted = d.instance.format(tag, @time, record)
|
32
|
+
|
33
|
+
assert_equal(%Q!{"message"=>"awesome", "greeting"=>"hello"}!, formatted.encode(Encoding::UTF_8))
|
34
|
+
end
|
35
|
+
end
|
@@ -33,6 +33,14 @@ class JsonFormatterTest < ::Test::Unit::TestCase
|
|
33
33
|
assert_equal("#{JSON.generate(record)}\n", formatted)
|
34
34
|
end
|
35
35
|
|
36
|
+
data('oj' => 'oj', 'yajl' => 'yajl')
|
37
|
+
def test_format_without_nl(data)
|
38
|
+
d = create_driver('json_parser' => data, 'add_newline' => false)
|
39
|
+
formatted = d.instance.format(tag, @time, record)
|
40
|
+
|
41
|
+
assert_equal(JSON.generate(record), formatted)
|
42
|
+
end
|
43
|
+
|
36
44
|
data('oj' => 'oj', 'yajl' => 'yajl')
|
37
45
|
def test_format_with_symbolic_record(data)
|
38
46
|
d = create_driver('json_parser' => data)
|
@@ -40,6 +40,13 @@ class LabeledTSVFormatterTest < ::Test::Unit::TestCase
|
|
40
40
|
assert_equal("message:awesome\tgreeting:hello\n", formatted)
|
41
41
|
end
|
42
42
|
|
43
|
+
def test_format_without_newline
|
44
|
+
d = create_driver('add_newline' => false)
|
45
|
+
formatted = d.instance.format(tag, @time, record)
|
46
|
+
|
47
|
+
assert_equal("message:awesome\tgreeting:hello", formatted)
|
48
|
+
end
|
49
|
+
|
43
50
|
def test_format_with_customized_delimiters
|
44
51
|
d = create_driver(
|
45
52
|
'delimiter' => ',',
|
@@ -112,10 +112,12 @@ class DummyTest < Test::Unit::TestCase
|
|
112
112
|
d1.instance.emit(4)
|
113
113
|
end
|
114
114
|
|
115
|
-
|
115
|
+
events = d1.events.sort{|a,b| a[2]['id'] <=> b[2]['id'] }
|
116
|
+
|
117
|
+
first_id1 = events.first[2]['id']
|
116
118
|
assert_equal 0, first_id1
|
117
119
|
|
118
|
-
last_id1 =
|
120
|
+
last_id1 = events.last[2]['id']
|
119
121
|
assert { last_id1 > 0 }
|
120
122
|
|
121
123
|
assert !File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-01.json'))
|
@@ -125,7 +127,9 @@ class DummyTest < Test::Unit::TestCase
|
|
125
127
|
d2.instance.emit(4)
|
126
128
|
end
|
127
129
|
|
128
|
-
|
130
|
+
events = d2.events.sort{|a,b| a[2]['id'] <=> b[2]['id'] }
|
131
|
+
|
132
|
+
first_id2 = events.first[2]['id']
|
129
133
|
assert_equal 0, first_id2
|
130
134
|
|
131
135
|
assert !File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-01.json'))
|
@@ -350,6 +350,39 @@ plugin_id:test_filter\tplugin_category:filter\ttype:test_filter\toutput_plugin:f
|
|
350
350
|
assert_equal(expected_null_response, null_response)
|
351
351
|
end
|
352
352
|
|
353
|
+
test "/api/plugins.json with 'with_ivars'. response contains specified instance variables of each plugin" do
|
354
|
+
d = create_driver("
|
355
|
+
@type monitor_agent
|
356
|
+
bind '127.0.0.1'
|
357
|
+
port #{@port}
|
358
|
+
tag monitor
|
359
|
+
")
|
360
|
+
d.instance.start
|
361
|
+
expected_test_in_response = {
|
362
|
+
"output_plugin" => false,
|
363
|
+
"plugin_category" => "input",
|
364
|
+
"plugin_id" => "test_in",
|
365
|
+
"retry_count" => nil,
|
366
|
+
"type" => "test_in",
|
367
|
+
"instance_variables" => {"id" => "test_in"}
|
368
|
+
}
|
369
|
+
expected_null_response = {
|
370
|
+
"buffer_queue_length" => 0,
|
371
|
+
"buffer_total_queued_size" => 0,
|
372
|
+
"output_plugin" => true,
|
373
|
+
"plugin_category" => "output",
|
374
|
+
"plugin_id" => "null",
|
375
|
+
"retry_count" => 0,
|
376
|
+
"type" => "null",
|
377
|
+
"instance_variables" => {"id" => "null", "num_errors" => 0}
|
378
|
+
}
|
379
|
+
response = JSON.parse(get("http://127.0.0.1:#{@port}/api/plugins.json?with_config=no&with_retry=no&with_ivars=id,num_errors"))
|
380
|
+
test_in_response = response["plugins"][0]
|
381
|
+
null_response = response["plugins"][5]
|
382
|
+
assert_equal(expected_test_in_response, test_in_response)
|
383
|
+
assert_equal(expected_null_response, null_response)
|
384
|
+
end
|
385
|
+
|
353
386
|
test "/api/config" do
|
354
387
|
d = create_driver("
|
355
388
|
@type monitor_agent
|
@@ -427,11 +460,7 @@ plugin_id:test_filter\tplugin_category:filter\ttype:test_filter\toutput_plugin:f
|
|
427
460
|
"output_plugin" => true,
|
428
461
|
"plugin_category" => "output",
|
429
462
|
"plugin_id" => "test_out_fail_write",
|
430
|
-
"retry_count" => 2,
|
431
463
|
"type" => "test_out_fail_write",
|
432
|
-
"retry" => {
|
433
|
-
"steps" => 1
|
434
|
-
}
|
435
464
|
}
|
436
465
|
output = @ra.outputs[0]
|
437
466
|
output.start
|
@@ -440,12 +469,21 @@ plugin_id:test_filter\tplugin_category:filter\ttype:test_filter\toutput_plugin:f
|
|
440
469
|
# flush few times to check steps
|
441
470
|
2.times do
|
442
471
|
output.force_flush
|
472
|
+
# output.force_flush calls #submit_flush_all, but #submit_flush_all skips to call #submit_flush_once when @retry exists.
|
473
|
+
# So that forced flush in retry state should be done by calling #submit_flush_once directly.
|
474
|
+
output.submit_flush_once
|
475
|
+
sleep 0.1 until output.buffer.queued?
|
443
476
|
end
|
444
477
|
response = JSON.parse(get("http://127.0.0.1:#{@port}/api/plugins.json"))
|
445
478
|
test_out_fail_write_response = response["plugins"][1]
|
446
479
|
# remove dynamic keys
|
447
|
-
|
480
|
+
response_retry_count = test_out_fail_write_response.delete("retry_count")
|
481
|
+
response_retry = test_out_fail_write_response.delete("retry")
|
448
482
|
assert_equal(expected_test_out_fail_write_response, test_out_fail_write_response)
|
483
|
+
assert{ response_retry.has_key?("steps") }
|
484
|
+
# it's very hard to check exact retry count (because retries are called by output flush thread scheduling)
|
485
|
+
assert{ response_retry_count >= 1 && response_retry["steps"] >= 0 }
|
486
|
+
assert{ response_retry_count == response_retry["steps"] + 1 }
|
449
487
|
end
|
450
488
|
end
|
451
489
|
end
|
data/test/plugin/test_in_tail.rb
CHANGED
@@ -37,6 +37,7 @@ class TailInputTest < Test::Unit::TestCase
|
|
37
37
|
COMMON_CONFIG = CONFIG + config_element("", "", { "pos_file" => "#{TMP_DIR}/tail.pos" })
|
38
38
|
CONFIG_READ_FROM_HEAD = config_element("", "", { "read_from_head" => true })
|
39
39
|
CONFIG_ENABLE_WATCH_TIMER = config_element("", "", { "enable_watch_timer" => false })
|
40
|
+
CONFIG_OPEN_ON_EVERY_UPDATE = config_element("", "", { "open_on_every_update" => true })
|
40
41
|
SINGLE_LINE_CONFIG = config_element("", "", { "format" => "/(?<message>.*)/" })
|
41
42
|
PARSE_SINGLE_LINE_CONFIG = config_element("", "", {}, [config_element("parse", "", { "@type" => "/(?<message>.*)/" })])
|
42
43
|
MULTILINE_CONFIG = config_element(
|
@@ -135,8 +136,7 @@ class TailInputTest < Test::Unit::TestCase
|
|
135
136
|
|
136
137
|
d.run(expect_emits: 1) do
|
137
138
|
File.open("#{TMP_DIR}/tail.txt", "ab") {|f|
|
138
|
-
f.puts "test3"
|
139
|
-
f.puts "test4"
|
139
|
+
f.puts "test3\ntest4"
|
140
140
|
}
|
141
141
|
end
|
142
142
|
|
@@ -149,6 +149,28 @@ class TailInputTest < Test::Unit::TestCase
|
|
149
149
|
assert_equal(1, d.emit_count)
|
150
150
|
end
|
151
151
|
|
152
|
+
def test_emit_with_emit_unmatched_lines_true
|
153
|
+
config = config_element("", "", { "format" => "/^(?<message>test.*)/", "emit_unmatched_lines" => true })
|
154
|
+
File.open("#{TMP_DIR}/tail.txt", "wb") { |f| }
|
155
|
+
|
156
|
+
d = create_driver(config)
|
157
|
+
d.run(expect_emits: 1) do
|
158
|
+
File.open("#{TMP_DIR}/tail.txt", "ab") {|f|
|
159
|
+
f.puts "test line 1"
|
160
|
+
f.puts "test line 2"
|
161
|
+
f.puts "bad line 1"
|
162
|
+
f.puts "test line 3"
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
events = d.events
|
167
|
+
assert_equal(4, events.length)
|
168
|
+
assert_equal({"message" => "test line 1"}, events[0][2])
|
169
|
+
assert_equal({"message" => "test line 2"}, events[1][2])
|
170
|
+
assert_equal({"unmatched_line" => "bad line 1"}, events[2][2])
|
171
|
+
assert_equal({"message" => "test line 3"}, events[3][2])
|
172
|
+
end
|
173
|
+
|
152
174
|
data('flat 1' => [:flat, 1, 2],
|
153
175
|
'flat 10' => [:flat, 10, 1],
|
154
176
|
'parse 1' => [:parse, 1, 2],
|
@@ -315,6 +337,20 @@ class TailInputTest < Test::Unit::TestCase
|
|
315
337
|
assert_equal({"message" => "test6"}, events[5][2])
|
316
338
|
end
|
317
339
|
|
340
|
+
data(flat: CONFIG_OPEN_ON_EVERY_UPDATE + CONFIG_READ_FROM_HEAD + SINGLE_LINE_CONFIG,
|
341
|
+
parse: CONFIG_OPEN_ON_EVERY_UPDATE + CONFIG_READ_FROM_HEAD + PARSE_SINGLE_LINE_CONFIG)
|
342
|
+
def test_rotate_file_with_open_on_every_update(data)
|
343
|
+
config = data
|
344
|
+
events = sub_test_rotate_file(config, expect_records: 6)
|
345
|
+
assert_equal(6, events.length)
|
346
|
+
assert_equal({"message" => "test1"}, events[0][2])
|
347
|
+
assert_equal({"message" => "test2"}, events[1][2])
|
348
|
+
assert_equal({"message" => "test3"}, events[2][2])
|
349
|
+
assert_equal({"message" => "test4"}, events[3][2])
|
350
|
+
assert_equal({"message" => "test5"}, events[4][2])
|
351
|
+
assert_equal({"message" => "test6"}, events[5][2])
|
352
|
+
end
|
353
|
+
|
318
354
|
data(flat: SINGLE_LINE_CONFIG,
|
319
355
|
parse: PARSE_SINGLE_LINE_CONFIG)
|
320
356
|
def test_rotate_file_with_write_old(data)
|
@@ -331,6 +367,8 @@ class TailInputTest < Test::Unit::TestCase
|
|
331
367
|
f.puts "test6"
|
332
368
|
}
|
333
369
|
}
|
370
|
+
# This test sometimes fails and it shows a potential bug of in_tail
|
371
|
+
# https://github.com/fluent/fluentd/issues/1434
|
334
372
|
assert_equal(6, events.length)
|
335
373
|
assert_equal({"message" => "test3"}, events[0][2])
|
336
374
|
assert_equal({"message" => "test4"}, events[1][2])
|
@@ -487,6 +525,30 @@ class TailInputTest < Test::Unit::TestCase
|
|
487
525
|
assert_equal(Encoding::UTF_8, events[0][2]['message'].encoding)
|
488
526
|
end
|
489
527
|
|
528
|
+
def test_from_encoding_utf16
|
529
|
+
conf = config_element(
|
530
|
+
"", "", {
|
531
|
+
"format" => "/(?<message>.*)/",
|
532
|
+
"read_from_head" => "true",
|
533
|
+
"from_encoding" => "utf-16le",
|
534
|
+
"encoding" => "utf-8"
|
535
|
+
})
|
536
|
+
d = create_driver(conf)
|
537
|
+
utf16_message = "\u306F\u308D\u30FC\u308F\u30FC\u308B\u3069\n".encode(Encoding::UTF_16LE)
|
538
|
+
utf8_message = utf16_message.encode(Encoding::UTF_8).strip
|
539
|
+
|
540
|
+
d.run(expect_emits: 1) do
|
541
|
+
File.open("#{TMP_DIR}/tail.txt", "w:utf-16le") { |f|
|
542
|
+
f.write utf16_message
|
543
|
+
}
|
544
|
+
end
|
545
|
+
|
546
|
+
events = d.events
|
547
|
+
assert_equal(utf8_message, events[0][2]['message'])
|
548
|
+
assert_equal(Encoding::UTF_8, events[0][2]['message'].encoding)
|
549
|
+
end
|
550
|
+
|
551
|
+
|
490
552
|
sub_test_case "multiline" do
|
491
553
|
data(flat: MULTILINE_CONFIG,
|
492
554
|
parse: PARSE_MULTILINE_CONFIG)
|
@@ -516,6 +578,35 @@ class TailInputTest < Test::Unit::TestCase
|
|
516
578
|
assert_equal({"message1" => "test8"}, events[3][2])
|
517
579
|
end
|
518
580
|
|
581
|
+
data(flat: MULTILINE_CONFIG,
|
582
|
+
parse: PARSE_MULTILINE_CONFIG)
|
583
|
+
def test_multiline_with_emit_unmatched_lines_true(data)
|
584
|
+
config = data + config_element("", "", { "emit_unmatched_lines" => true })
|
585
|
+
File.open("#{TMP_DIR}/tail.txt", "wb") { |f| }
|
586
|
+
|
587
|
+
d = create_driver(config)
|
588
|
+
d.run(expect_emits: 1) do
|
589
|
+
File.open("#{TMP_DIR}/tail.txt", "ab") { |f|
|
590
|
+
f.puts "f test1"
|
591
|
+
f.puts "s test2"
|
592
|
+
f.puts "f test3"
|
593
|
+
f.puts "f test4"
|
594
|
+
f.puts "s test5"
|
595
|
+
f.puts "s test6"
|
596
|
+
f.puts "f test7"
|
597
|
+
f.puts "s test8"
|
598
|
+
}
|
599
|
+
end
|
600
|
+
|
601
|
+
events = d.events
|
602
|
+
assert_equal(5, events.length)
|
603
|
+
assert_equal({"unmatched_line" => "f test1"}, events[0][2])
|
604
|
+
assert_equal({"message1" => "test2", "message2" => "test3", "message3" => "test4"}, events[1][2])
|
605
|
+
assert_equal({"message1" => "test5"}, events[2][2])
|
606
|
+
assert_equal({"message1" => "test6", "message2" => "test7"}, events[3][2])
|
607
|
+
assert_equal({"message1" => "test8"}, events[4][2])
|
608
|
+
end
|
609
|
+
|
519
610
|
data(flat: MULTILINE_CONFIG,
|
520
611
|
parse: PARSE_MULTILINE_CONFIG)
|
521
612
|
def test_multiline_with_flush_interval(data)
|
@@ -769,7 +860,7 @@ class TailInputTest < Test::Unit::TestCase
|
|
769
860
|
Timecop.freeze(2010, 1, 2, 3, 4, 5) do
|
770
861
|
flexstub(Fluent::Plugin::TailInput::TailWatcher) do |watcherclass|
|
771
862
|
EX_PATHS.each do |path|
|
772
|
-
watcherclass.should_receive(:new).with(path, EX_RORATE_WAIT, Fluent::Plugin::TailInput::FilePositionEntry, any, true, true, 1000, any, any, any).once.and_return do
|
863
|
+
watcherclass.should_receive(:new).with(path, EX_RORATE_WAIT, Fluent::Plugin::TailInput::FilePositionEntry, any, true, true, 1000, any, any, any, any, any, any).once.and_return do
|
773
864
|
flexmock('TailWatcher') { |watcher|
|
774
865
|
watcher.should_receive(:attach).once
|
775
866
|
watcher.should_receive(:unwatched=).zero_or_more_times
|
@@ -787,7 +878,7 @@ class TailInputTest < Test::Unit::TestCase
|
|
787
878
|
|
788
879
|
Timecop.freeze(2010, 1, 2, 3, 4, 6) do
|
789
880
|
flexstub(Fluent::Plugin::TailInput::TailWatcher) do |watcherclass|
|
790
|
-
watcherclass.should_receive(:new).with('test/plugin/data/2010/01/20100102-030406.log', EX_RORATE_WAIT, Fluent::Plugin::TailInput::FilePositionEntry, any, true, true, 1000, any, any, any).once.and_return do
|
881
|
+
watcherclass.should_receive(:new).with('test/plugin/data/2010/01/20100102-030406.log', EX_RORATE_WAIT, Fluent::Plugin::TailInput::FilePositionEntry, any, true, true, 1000, any, any, any, any, any, any).once.and_return do
|
791
882
|
flexmock('TailWatcher') do |watcher|
|
792
883
|
watcher.should_receive(:attach).once
|
793
884
|
watcher.should_receive(:unwatched=).zero_or_more_times
|
@@ -898,6 +989,8 @@ class TailInputTest < Test::Unit::TestCase
|
|
898
989
|
f.puts "test4"
|
899
990
|
}
|
900
991
|
end
|
992
|
+
# This test sometimes fails and it shows a potential bug of in_tail
|
993
|
+
# https://github.com/fluent/fluentd/issues/1434
|
901
994
|
events = d.events
|
902
995
|
assert_equal(2, events.length)
|
903
996
|
assert_equal({"message" => "test3"}, events[0][2])
|
data/test/plugin/test_input.rb
CHANGED
@@ -22,8 +22,8 @@ class FileOutputTest < Test::Unit::TestCase
|
|
22
22
|
utc
|
23
23
|
]
|
24
24
|
|
25
|
-
def create_driver(conf = CONFIG)
|
26
|
-
Fluent::Test::Driver::Output.new(Fluent::Plugin::FileOutput).configure(conf)
|
25
|
+
def create_driver(conf = CONFIG, opts = {})
|
26
|
+
Fluent::Test::Driver::Output.new(Fluent::Plugin::FileOutput, opts: opts).configure(conf)
|
27
27
|
end
|
28
28
|
|
29
29
|
sub_test_case 'configuration' do
|
@@ -37,7 +37,29 @@ class FileOutputTest < Test::Unit::TestCase
|
|
37
37
|
assert_equal :gzip, d.instance.instance_eval{ @compress_method }
|
38
38
|
end
|
39
39
|
|
40
|
+
test 'using root_dir for buffer path' do
|
41
|
+
system_conf_opts = {'root_dir' => File.join(TMP_DIR, 'testrootdir')}
|
42
|
+
buf_conf = config_element('buffer', '', {'flush_interval' => '1s'})
|
43
|
+
conf = config_element('match', '**', {'@id' => 'myout', 'path' => 'test_path', 'append' => 'true'}, [buf_conf])
|
44
|
+
d = create_driver(conf, system_conf_opts)
|
45
|
+
|
46
|
+
assert_equal 'test_path', d.instance.path
|
47
|
+
assert d.instance.append
|
48
|
+
|
49
|
+
assert d.instance.buffer.respond_to?(:path) # file buffer
|
50
|
+
assert_equal 1, d.instance.buffer_config.flush_interval
|
51
|
+
|
52
|
+
assert_equal File.join(TMP_DIR, 'testrootdir', 'worker0', 'myout'), d.instance.plugin_root_dir
|
53
|
+
|
54
|
+
buffer_path_under_root_dir = File.join(TMP_DIR, 'testrootdir', 'worker0', 'myout', 'buffer', 'buffer.*.log')
|
55
|
+
assert_equal buffer_path_under_root_dir, d.instance.buffer.path
|
56
|
+
end
|
57
|
+
|
40
58
|
test 'path should be writable' do
|
59
|
+
assert_raise(Fluent::ConfigError.new("'path' parameter is required")) do
|
60
|
+
create_driver ""
|
61
|
+
end
|
62
|
+
|
41
63
|
assert_nothing_raised do
|
42
64
|
create_driver %[path #{TMP_DIR}/test_path]
|
43
65
|
end
|
@@ -718,7 +740,7 @@ class FileOutputTest < Test::Unit::TestCase
|
|
718
740
|
end
|
719
741
|
|
720
742
|
test 'raise error to show it is a bug when path including * specified without timekey' do
|
721
|
-
assert_raise "BUG: configuration error must be raised for path including '*' without timekey" do
|
743
|
+
assert_raise RuntimeError.new("BUG: configuration error must be raised for path including '*' without timekey") do
|
722
744
|
@i.generate_path_template('/path/to/file.*.log', nil, false, nil)
|
723
745
|
end
|
724
746
|
end
|
@@ -808,8 +830,10 @@ class FileOutputTest < Test::Unit::TestCase
|
|
808
830
|
end
|
809
831
|
|
810
832
|
test 'raise error if argument path does not include index placeholder' do
|
811
|
-
assert_raise "BUG: index placeholder not found in path: #{@tmp}/myfile" do
|
812
|
-
@i.find_filepath_available("#{@tmp}/myfile")
|
833
|
+
assert_raise RuntimeError.new("BUG: index placeholder not found in path: #{@tmp}/myfile") do
|
834
|
+
@i.find_filepath_available("#{@tmp}/myfile") do |path|
|
835
|
+
# ...
|
836
|
+
end
|
813
837
|
end
|
814
838
|
end
|
815
839
|
|
@@ -821,14 +845,29 @@ class FileOutputTest < Test::Unit::TestCase
|
|
821
845
|
)
|
822
846
|
test 'returns filepath with _0 at first' do |data|
|
823
847
|
expected, argument = data
|
824
|
-
|
848
|
+
@i.find_filepath_available(File.join(@tmp, argument)) do |path|
|
849
|
+
assert_equal File.join(@tmp, expected), path
|
850
|
+
end
|
825
851
|
end
|
826
852
|
|
827
853
|
test 'returns filepath with index which does not exist yet' do
|
854
|
+
5.times do |i|
|
855
|
+
File.open(File.join(@tmp, "exist_#{i}.log"), 'a'){|f| } # open(create) and close
|
856
|
+
end
|
857
|
+
@i.find_filepath_available(File.join(@tmp, "exist_**.log")) do |path|
|
858
|
+
assert_equal File.join(@tmp, "exist_5.log"), path
|
859
|
+
end
|
860
|
+
end
|
861
|
+
|
862
|
+
test 'creates lock directory when with_lock is true to exclude operations of other worker process' do
|
828
863
|
5.times do |i|
|
829
864
|
File.open(File.join(@tmp, "exist_#{i}.log"), 'a')
|
830
865
|
end
|
831
|
-
|
866
|
+
Dir.mkdir(File.join(@tmp, "exist_5.log.lock"))
|
867
|
+
@i.find_filepath_available(File.join(@tmp, "exist_**.log"), with_lock: true) do |path|
|
868
|
+
assert Dir.exist?(File.join(@tmp, "exist_6.log.lock"))
|
869
|
+
assert_equal File.join(@tmp, "exist_6.log"), path
|
870
|
+
end
|
832
871
|
end
|
833
872
|
end
|
834
873
|
end
|