fluentd 0.14.2 → 0.14.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +77 -1131
  3. data/Rakefile +15 -0
  4. data/appveyor.yml +2 -2
  5. data/example/in_forward.conf +3 -0
  6. data/example/in_forward_client.conf +37 -0
  7. data/example/in_forward_shared_key.conf +15 -0
  8. data/example/in_forward_users.conf +24 -0
  9. data/example/multi_filters.conf +61 -0
  10. data/example/out_forward.conf +13 -13
  11. data/example/out_forward_client.conf +109 -0
  12. data/example/out_forward_shared_key.conf +36 -0
  13. data/example/out_forward_users.conf +65 -0
  14. data/example/{out_buffered_null.conf → out_null.conf} +10 -6
  15. data/example/secondary_file.conf +41 -0
  16. data/fluentd.gemspec +19 -16
  17. data/lib/fluent/agent.rb +5 -0
  18. data/lib/fluent/command/debug.rb +4 -4
  19. data/lib/fluent/compat/handle_tag_and_time_mixin.rb +2 -0
  20. data/lib/fluent/compat/output.rb +5 -2
  21. data/lib/fluent/config/configure_proxy.rb +26 -5
  22. data/lib/fluent/config/error.rb +3 -0
  23. data/lib/fluent/config/section.rb +15 -0
  24. data/lib/fluent/event_router.rb +77 -4
  25. data/lib/fluent/plugin/base.rb +12 -3
  26. data/lib/fluent/plugin/buffer.rb +5 -1
  27. data/lib/fluent/plugin/filter.rb +48 -6
  28. data/lib/fluent/plugin/filter_record_transformer.rb +3 -1
  29. data/lib/fluent/plugin/filter_stdout.rb +0 -4
  30. data/lib/fluent/plugin/in_debug_agent.rb +5 -5
  31. data/lib/fluent/plugin/in_dummy.rb +9 -1
  32. data/lib/fluent/plugin/in_forward.rb +330 -62
  33. data/lib/fluent/plugin/in_monitor_agent.rb +31 -77
  34. data/lib/fluent/plugin/in_tail.rb +76 -92
  35. data/lib/fluent/plugin/multi_output.rb +4 -0
  36. data/lib/fluent/plugin/out_forward.rb +328 -222
  37. data/lib/fluent/plugin/out_null.rb +37 -0
  38. data/lib/fluent/plugin/out_secondary_file.rb +128 -0
  39. data/lib/fluent/plugin/out_stdout.rb +38 -2
  40. data/lib/fluent/plugin/output.rb +29 -6
  41. data/lib/fluent/plugin/storage_local.rb +16 -0
  42. data/lib/fluent/plugin_helper/timer.rb +6 -1
  43. data/lib/fluent/root_agent.rb +4 -1
  44. data/lib/fluent/supervisor.rb +62 -9
  45. data/lib/fluent/test/base.rb +3 -0
  46. data/lib/fluent/test/driver/base.rb +5 -0
  47. data/lib/fluent/test/formatter_test.rb +2 -0
  48. data/lib/fluent/test/parser_test.rb +2 -0
  49. data/lib/fluent/test/startup_shutdown.rb +33 -0
  50. data/lib/fluent/version.rb +1 -1
  51. data/lib/fluent/winsvc.rb +1 -2
  52. data/test/compat/test_calls_super.rb +2 -0
  53. data/test/config/test_configurable.rb +88 -0
  54. data/test/config/test_types.rb +7 -3
  55. data/test/plugin/test_filter.rb +121 -23
  56. data/test/plugin/test_filter_record_transformer.rb +22 -6
  57. data/test/plugin/test_in_debug_agent.rb +2 -2
  58. data/test/plugin/test_in_forward.rb +920 -407
  59. data/test/plugin/test_in_monitor_agent.rb +333 -0
  60. data/test/plugin/test_in_tail.rb +686 -595
  61. data/test/plugin/test_out_forward.rb +150 -207
  62. data/test/plugin/test_out_null.rb +85 -9
  63. data/test/plugin/test_out_secondary_file.rb +432 -0
  64. data/test/plugin/test_out_stdout.rb +143 -45
  65. data/test/plugin/test_output.rb +53 -0
  66. data/test/plugin/test_output_as_buffered.rb +13 -0
  67. data/test/plugin/test_output_as_buffered_overflow.rb +3 -0
  68. data/test/plugin/test_output_as_buffered_retries.rb +11 -0
  69. data/test/plugin/test_output_as_buffered_secondary.rb +12 -0
  70. data/test/plugin/test_output_as_standard.rb +12 -0
  71. data/test/plugin_helper/test_compat_parameters.rb +2 -0
  72. data/test/plugin_helper/test_timer.rb +31 -0
  73. data/test/test_event_router.rb +87 -0
  74. data/test/test_filter.rb +48 -6
  75. data/test/test_log.rb +5 -2
  76. data/test/test_output.rb +41 -1
  77. data/test/test_plugin_classes.rb +17 -9
  78. data/test/test_root_agent.rb +188 -0
  79. metadata +62 -68
  80. data/lib/fluent/plugin/out_buffered_null.rb +0 -59
  81. data/lib/fluent/plugin/out_buffered_stdout.rb +0 -70
  82. data/test/plugin/test_out_buffered_null.rb +0 -79
  83. data/test/plugin/test_out_buffered_stdout.rb +0 -122
@@ -0,0 +1,432 @@
1
+ require_relative '../helper'
2
+ require 'time'
3
+ require 'fileutils'
4
+ require 'fluent/event'
5
+ require 'fluent/unique_id'
6
+ require 'fluent/plugin/buffer'
7
+ require 'fluent/plugin/out_secondary_file'
8
+ require 'fluent/plugin/buffer/memory_chunk'
9
+ require 'fluent/test/driver/output'
10
+
11
+ class FileOutputSecondaryTest < Test::Unit::TestCase
12
+ include Fluent::UniqueId::Mixin
13
+
14
+ def setup
15
+ Fluent::Test.setup
16
+ FileUtils.rm_rf(TMP_DIR)
17
+ FileUtils.mkdir_p(TMP_DIR)
18
+ end
19
+
20
+ TMP_DIR = File.expand_path(File.dirname(__FILE__) + "/../tmp/out_secondary_file#{ENV['TEST_ENV_NUMBER']}")
21
+
22
+ CONFIG = %[
23
+ directory #{TMP_DIR}
24
+ basename out_file_test
25
+ compress gzip
26
+ ]
27
+
28
+ class DummyOutput < Fluent::Plugin::Output
29
+ def write(chunk); end
30
+ end
31
+
32
+ def create_primary(buffer_cofig = config_element('buffer'))
33
+ DummyOutput.new.configure(config_element('ROOT','',{}, [buffer_cofig]))
34
+ end
35
+
36
+ def create_driver(conf = CONFIG, primary = create_primary)
37
+ c = Fluent::Test::Driver::Output.new(Fluent::Plugin::SecondaryFileOutput)
38
+ c.instance.acts_as_secondary(primary)
39
+ c.configure(conf)
40
+ end
41
+
42
+ sub_test_case 'configture' do
43
+ test 'default configuration' do
44
+ d = create_driver %[directory #{TMP_DIR}]
45
+ assert_equal 'dump.bin', d.instance.basename
46
+ assert_equal TMP_DIR, d.instance.directory
47
+ assert_equal :text, d.instance.compress
48
+ assert_equal false, d.instance.append
49
+ end
50
+
51
+ test 'should be configurable' do
52
+ d = create_driver %[
53
+ directory #{TMP_DIR}
54
+ basename out_file_test
55
+ compress gzip
56
+ append true
57
+ ]
58
+ assert_equal 'out_file_test', d.instance.basename
59
+ assert_equal TMP_DIR, d.instance.directory
60
+ assert_equal :gzip, d.instance.compress
61
+ assert_equal true, d.instance.append
62
+ end
63
+
64
+ test 'should only use in secondary' do
65
+ c = Fluent::Test::Driver::Output.new(Fluent::Plugin::SecondaryFileOutput)
66
+ assert_raise Fluent::ConfigError.new("This plugin can only be used in the <secondary> section") do
67
+ c.configure(CONFIG)
68
+ end
69
+ end
70
+
71
+ test 'basename should not include `/`' do
72
+ assert_raise Fluent::ConfigError.new("basename should not include `/`") do
73
+ create_driver %[
74
+ directory #{TMP_DIR}
75
+ basename out/file
76
+ ]
77
+ end
78
+ end
79
+
80
+ test 'directory should be writable' do
81
+ assert_nothing_raised do
82
+ create_driver %[directory #{TMP_DIR}/test_dir/foo/bar/]
83
+ end
84
+
85
+ assert_nothing_raised do
86
+ FileUtils.mkdir_p("#{TMP_DIR}/test_dir")
87
+ File.chmod(0777, "#{TMP_DIR}/test_dir")
88
+ create_driver %[directory #{TMP_DIR}/test_dir/foo/bar/]
89
+ end
90
+
91
+ assert_raise Fluent::ConfigError.new("out_secondary_file: `#{TMP_DIR}/test_dir/foo/bar/` should be writable") do
92
+ FileUtils.mkdir_p("#{TMP_DIR}/test_dir")
93
+ File.chmod(0555, "#{TMP_DIR}/test_dir")
94
+ create_driver %[directory #{TMP_DIR}/test_dir/foo/bar/]
95
+ end
96
+ end
97
+
98
+ test 'should be passed directory' do
99
+ assert_raise Fluent::ConfigError do
100
+ create_driver %[]
101
+ end
102
+
103
+ assert_nothing_raised do
104
+ create_driver %[directory #{TMP_DIR}/test_dir/foo/bar/]
105
+ end
106
+ end
107
+ end
108
+
109
+ def check_gzipped_result(path, expect)
110
+ # Zlib::GzipReader has a bug of concatenated file: https://bugs.ruby-lang.org/issues/9790
111
+ # Following code from https://www.ruby-forum.com/topic/971591#979520
112
+ result = ""
113
+ File.open(path, "rb") { |io|
114
+ loop do
115
+ gzr = Zlib::GzipReader.new(io)
116
+ result << gzr.read
117
+ unused = gzr.unused
118
+ gzr.finish
119
+ break if unused.nil?
120
+ io.pos -= unused.length
121
+ end
122
+ }
123
+
124
+ assert_equal expect, result
125
+ end
126
+
127
+ def create_chunk(primary, metadata, es)
128
+ primary.buffer.generate_chunk(metadata).tap do |c|
129
+ c.concat(es.to_msgpack_stream, es.size) # to_msgpack_stream is standard_format
130
+ c.commit
131
+ end
132
+ end
133
+
134
+ sub_test_case 'write' do
135
+ setup do
136
+ @record = { 'key' => 'value' }
137
+ @time = event_time
138
+ @es = Fluent::OneEventStream.new(@time, @record)
139
+ @primary = create_primary
140
+ metadata = @primary.buffer.new_metadata
141
+ @chunk = create_chunk(@primary, metadata, @es)
142
+ end
143
+
144
+ test 'should output compressed file when compress option is gzip' do
145
+ d = create_driver(CONFIG, @primary)
146
+ path = d.instance.write(@chunk)
147
+
148
+ assert_equal "#{TMP_DIR}/out_file_test.0.gz", path
149
+ check_gzipped_result(path, @es.to_msgpack_stream.force_encoding('ASCII-8BIT'))
150
+ end
151
+
152
+ test 'should output plain text when compress option is default(text)' do
153
+ d = create_driver(%[
154
+ directory #{TMP_DIR}/
155
+ basename out_file_test
156
+ ], @primary)
157
+
158
+ path = d.instance.write(@chunk)
159
+
160
+ assert_equal "#{TMP_DIR}/out_file_test.0", path
161
+ assert_equal File.read(path), @es.to_msgpack_stream.force_encoding('ASCII-8BIT')
162
+ end
163
+
164
+ test 'path should be incremental when append option is false' do
165
+ d = create_driver(CONFIG, @primary)
166
+ packed_value = @es.to_msgpack_stream.force_encoding('ASCII-8BIT')
167
+
168
+ 5.times do |i|
169
+ path = d.instance.write(@chunk)
170
+ assert_equal "#{TMP_DIR}/out_file_test.#{i}.gz", path
171
+ check_gzipped_result(path, packed_value)
172
+ end
173
+ end
174
+
175
+ test 'path should be unchanged when append option is true' do
176
+ d = create_driver(CONFIG + %[append true], @primary)
177
+ packed_value = @es.to_msgpack_stream.force_encoding('ASCII-8BIT')
178
+
179
+ [*1..5].each do |i|
180
+ path = d.instance.write(@chunk)
181
+ assert_equal "#{TMP_DIR}/out_file_test.gz", path
182
+ check_gzipped_result(path, packed_value * i)
183
+ end
184
+ end
185
+ end
186
+
187
+ sub_test_case 'Syntax of placeholders' do
188
+ data(
189
+ tag: '${tag}',
190
+ tag_index: '${tag[0]}',
191
+ tag_index1: '${tag[10]}',
192
+ variable: '${key1}',
193
+ variable2: '${key@value}',
194
+ variable3: '${key_value}',
195
+ variable4: '${key.value}',
196
+ variable5: '${key-value}',
197
+ variable6: '${KEYVALUE}',
198
+ variable7: '${tags}',
199
+ variable8: '${tag${key}', # matched ${key}
200
+ )
201
+ test 'matches with a valid placeholder' do |path|
202
+ assert Fluent::Plugin::SecondaryFileOutput::PLACEHOLDER_REGEX.match(path)
203
+ end
204
+
205
+ data(
206
+ invalid_tag: 'tag',
207
+ invalid_tag2: '{tag}',
208
+ invalid_tag3: '${tag',
209
+ invalid_tag4: '${tag0]}',
210
+ invalid_tag5: '${tag[]]}',
211
+ invalid_variable: '${key[0]}',
212
+ invalid_variable2: '${key{key2}}',
213
+ )
214
+ test "doesn't match with an invalid placeholder" do |path|
215
+ assert !Fluent::Plugin::SecondaryFileOutput::PLACEHOLDER_REGEX.match(path)
216
+ end
217
+ end
218
+
219
+ sub_test_case 'path' do
220
+ setup do
221
+ @record = { 'key' => 'value' }
222
+ @time = event_time
223
+ @es = Fluent::OneEventStream.new(@time, @record)
224
+ primary = create_primary
225
+ m = primary.buffer.new_metadata
226
+ @c = create_chunk(primary, m, @es)
227
+ end
228
+
229
+ test 'normal path when compress option is gzip' do
230
+ d = create_driver
231
+ path = d.instance.write(@c)
232
+ assert_equal "#{TMP_DIR}/out_file_test.0.gz", path
233
+ end
234
+
235
+ test 'normal path when compress option is default' do
236
+ d = create_driver %[
237
+ directory #{TMP_DIR}
238
+ basename out_file_test
239
+ ]
240
+ path = d.instance.write(@c)
241
+ assert_equal "#{TMP_DIR}/out_file_test.0", path
242
+ end
243
+
244
+ test 'normal path when append option is true' do
245
+ d = create_driver %[
246
+ directory #{TMP_DIR}
247
+ append true
248
+ ]
249
+ path = d.instance.write(@c)
250
+ assert_equal "#{TMP_DIR}/dump.bin", path
251
+ end
252
+
253
+ data(
254
+ invalid_tag: [/tag/, '${tag}'],
255
+ invalid_tag0: [/tag\[0\]/, '${tag[0]}'],
256
+ invalid_variable: [/dummy/, '${dummy}'],
257
+ invalid_timeformat: [/time/, '%Y%m%d'],
258
+ )
259
+ test 'raise an error when basename includes incompatible placeholder' do |(expected_message, invalid_basename)|
260
+ c = Fluent::Test::Driver::Output.new(Fluent::Plugin::SecondaryFileOutput)
261
+ c.instance.acts_as_secondary(DummyOutput.new)
262
+
263
+ assert_raise_message(expected_message) do
264
+ c.configure %[
265
+ directory #{TMP_DIR}/
266
+ basename #{invalid_basename}
267
+ compress gzip
268
+ ]
269
+ end
270
+ end
271
+
272
+ data(
273
+ invalid_tag: [/tag/, '${tag}'],
274
+ invalid_tag0: [/tag\[0\]/, '${tag[0]}'],
275
+ invalid_variable: [/dummy/, '${dummy}'],
276
+ invalid_timeformat: [/time/, '%Y%m%d'],
277
+ )
278
+ test 'raise an error when directory includes incompatible placeholder' do |(expected_message, invalid_directory)|
279
+ c = Fluent::Test::Driver::Output.new(Fluent::Plugin::SecondaryFileOutput)
280
+ c.instance.acts_as_secondary(DummyOutput.new)
281
+
282
+ assert_raise_message(expected_message) do
283
+ c.configure %[
284
+ directory #{invalid_directory}/
285
+ compress gzip
286
+ ]
287
+ end
288
+ end
289
+
290
+ test 'basename includes tag' do
291
+ primary = create_primary(config_element('buffer', 'tag'))
292
+
293
+ d = create_driver(%[
294
+ directory #{TMP_DIR}/
295
+ basename cool_${tag}
296
+ compress gzip
297
+ ], primary)
298
+
299
+ m = primary.buffer.new_metadata(tag: 'test.dummy')
300
+ c = create_chunk(primary, m, @es)
301
+
302
+ path = d.instance.write(c)
303
+ assert_equal "#{TMP_DIR}/cool_test.dummy.0.gz", path
304
+ end
305
+
306
+ test 'basename includes /tag[\d+]/' do
307
+ primary = create_primary(config_element('buffer', 'tag'))
308
+
309
+ d = create_driver(%[
310
+ directory #{TMP_DIR}/
311
+ basename cool_${tag[0]}_${tag[1]}
312
+ compress gzip
313
+ ], primary)
314
+
315
+ m = primary.buffer.new_metadata(tag: 'test.dummy')
316
+ c = create_chunk(primary, m, @es)
317
+
318
+ path = d.instance.write(c)
319
+ assert_equal "#{TMP_DIR}/cool_test_dummy.0.gz", path
320
+ end
321
+
322
+ test 'basename includes time format' do
323
+ primary = create_primary(
324
+ config_element('buffer', 'time', { 'timekey_zone' => '+0900', 'timekey' => 1 })
325
+ )
326
+
327
+ d = create_driver(%[
328
+ directory #{TMP_DIR}/
329
+ basename cool_%Y%m%d%H
330
+ compress gzip
331
+ ], primary)
332
+
333
+ m = primary.buffer.new_metadata(timekey: event_time("2011-01-02 13:14:15 UTC"))
334
+ c = create_chunk(primary, m, @es)
335
+
336
+ path = d.instance.write(c)
337
+ assert_equal "#{TMP_DIR}/cool_2011010222.0.gz", path
338
+ end
339
+
340
+ test 'basename includes time format with timekey_use_utc option' do
341
+ primary = create_primary(
342
+ config_element('buffer', 'time', { 'timekey_zone' => '+0900', 'timekey' => 1, 'timekey_use_utc' => true })
343
+ )
344
+
345
+ d = create_driver(%[
346
+ directory #{TMP_DIR}/
347
+ basename cool_%Y%m%d%H
348
+ compress gzip
349
+ ], primary)
350
+
351
+ m = primary.buffer.new_metadata(timekey: event_time("2011-01-02 13:14:15 UTC"))
352
+ c = create_chunk(primary, m, @es)
353
+
354
+ path = d.instance.write(c)
355
+ assert_equal "#{TMP_DIR}/cool_2011010213.0.gz", path
356
+ end
357
+
358
+ test 'basename includes variable' do
359
+ primary = create_primary(config_element('buffer', 'test1'))
360
+
361
+ d = create_driver(%[
362
+ directory #{TMP_DIR}/
363
+ basename cool_${test1}
364
+ compress gzip
365
+ ], primary)
366
+
367
+ m = primary.buffer.new_metadata(variables: { "test1".to_sym => "dummy" })
368
+ c = create_chunk(primary, m, @es)
369
+
370
+ path = d.instance.write(c)
371
+ assert_equal "#{TMP_DIR}/cool_dummy.0.gz", path
372
+ end
373
+
374
+ test 'basename includes unnecessary variable' do
375
+ primary = create_primary(config_element('buffer', 'test1'))
376
+ c = Fluent::Test::Driver::Output.new(Fluent::Plugin::SecondaryFileOutput)
377
+ c.instance.acts_as_secondary(primary)
378
+
379
+ assert_raise_message(/test2/) do
380
+ c.configure %[
381
+ directory #{TMP_DIR}/
382
+ basename ${test1}_${test2}
383
+ compress gzip
384
+ ]
385
+ end
386
+ end
387
+
388
+ test 'basename includes tag, time format, and variables' do
389
+ primary = create_primary(
390
+ config_element('buffer', 'time,tag,test1', { 'timekey_zone' => '+0000', 'timekey' => 1 })
391
+ )
392
+
393
+ d = create_driver(%[
394
+ directory #{TMP_DIR}/
395
+ basename cool_%Y%m%d%H_${tag}_${test1}
396
+ compress gzip
397
+ ], primary)
398
+
399
+ m = primary.buffer.new_metadata(
400
+ timekey: event_time("2011-01-02 13:14:15 UTC"),
401
+ tag: 'test.tag',
402
+ variables: { "test1".to_sym => "dummy" }
403
+ )
404
+
405
+ c = create_chunk(primary, m, @es)
406
+
407
+ path = d.instance.write(c)
408
+ assert_equal "#{TMP_DIR}/cool_2011010213_test.tag_dummy.0.gz", path
409
+ end
410
+
411
+ test 'directory includes tag, time format, and variables' do
412
+ primary = create_primary(
413
+ config_element('buffer', 'time,tag,test1', { 'timekey_zone' => '+0000', 'timekey' => 1 })
414
+ )
415
+
416
+ d = create_driver(%[
417
+ directory #{TMP_DIR}/%Y%m%d%H/${tag}/${test1}
418
+ compress gzip
419
+ ], primary)
420
+
421
+ m = primary.buffer.new_metadata(
422
+ timekey: event_time("2011-01-02 13:14:15 UTC"),
423
+ tag: 'test.tag',
424
+ variables: { "test1".to_sym => "dummy" }
425
+ )
426
+ c = create_chunk(primary, m, @es)
427
+
428
+ path = d.instance.write(c)
429
+ assert_equal "#{TMP_DIR}/2011010213/test.tag/dummy/dump.bin.0.gz", path
430
+ end
431
+ end
432
+ end
@@ -14,70 +14,168 @@ class StdoutOutputTest < Test::Unit::TestCase
14
14
  Fluent::Test::Driver::Output.new(Fluent::Plugin::StdoutOutput).configure(conf)
15
15
  end
16
16
 
17
- def test_configure
18
- d = create_driver
19
- assert_equal [], d.instance.formatter_configs
20
- end
17
+ sub_test_case 'non-buffered' do
18
+ test 'configure' do
19
+ d = create_driver
20
+ assert_equal [], d.instance.formatter_configs
21
+ end
21
22
 
22
- def test_configure_output_type
23
- d = create_driver(CONFIG + "\noutput_type json")
24
- assert_equal 'json', d.instance.formatter_configs.first[:@type]
23
+ test 'configure output_type' do
24
+ d = create_driver(CONFIG + "\noutput_type json")
25
+ assert_equal 'json', d.instance.formatter_configs.first[:@type]
25
26
 
26
- d = create_driver(CONFIG + "\noutput_type hash")
27
- assert_equal 'hash', d.instance.formatter_configs.first[:@type]
27
+ d = create_driver(CONFIG + "\noutput_type hash")
28
+ assert_equal 'hash', d.instance.formatter_configs.first[:@type]
28
29
 
29
- assert_raise(Fluent::ConfigError) do
30
- d = create_driver(CONFIG + "\noutput_type foo")
30
+ assert_raise(Fluent::ConfigError) do
31
+ d = create_driver(CONFIG + "\noutput_type foo")
32
+ end
31
33
  end
32
- end
33
34
 
34
- def test_emit_in_default
35
- d = create_driver
36
- time = event_time()
37
- out = capture_log do
38
- d.run(default_tag: 'test') do
39
- d.feed(time, {'test' => 'test1'})
35
+ test 'emit with default configuration' do
36
+ d = create_driver
37
+ time = event_time()
38
+ out = capture_log do
39
+ d.run(default_tag: 'test') do
40
+ d.feed(time, {'test' => 'test1'})
41
+ end
40
42
  end
43
+ assert_equal "#{Time.at(time).localtime} test: {\"test\":\"test1\"}\n", out
41
44
  end
42
- assert_equal "#{Time.at(time).localtime} test: {\"test\":\"test1\"}\n", out
43
- end
44
45
 
45
- data('oj' => 'oj', 'yajl' => 'yajl')
46
- def test_emit_json(data)
47
- d = create_driver(CONFIG + "\noutput_type json\njson_parser #{data}")
48
- time = event_time()
49
- out = capture_log do
50
- d.run(default_tag: 'test') do
51
- d.feed(time, {'test' => 'test1'})
46
+ data('oj' => 'oj', 'yajl' => 'yajl')
47
+ test 'emit in json format' do |data|
48
+ d = create_driver(CONFIG + "\noutput_type json\njson_parser #{data}")
49
+ time = event_time()
50
+ out = capture_log do
51
+ d.run(default_tag: 'test') do
52
+ d.feed(time, {'test' => 'test1'})
53
+ end
54
+ end
55
+ assert_equal "#{Time.at(time).localtime} test: {\"test\":\"test1\"}\n", out
56
+
57
+ if data == 'yajl'
58
+ # NOTE: Float::NAN is not jsonable
59
+ assert_raise(Yajl::EncodeError) { d.feed('test', time, {'test' => Float::NAN}) }
60
+ else
61
+ out = capture_log { d.feed('test', time, {'test' => Float::NAN}) }
62
+ assert_equal "#{Time.at(time).localtime} test: {\"test\":NaN}\n", out
52
63
  end
53
64
  end
54
- assert_equal "#{Time.at(time).localtime} test: {\"test\":\"test1\"}\n", out
55
65
 
56
- if data == 'yajl'
57
- # NOTE: Float::NAN is not jsonable
58
- assert_raise(Yajl::EncodeError) { d.feed('test', time, {'test' => Float::NAN}) }
59
- else
66
+ test 'emit in hash format' do
67
+ d = create_driver(CONFIG + "\noutput_type hash")
68
+ time = event_time()
69
+ out = capture_log do
70
+ d.run(default_tag: 'test') do
71
+ d.feed(time, {'test' => 'test2'})
72
+ end
73
+ end
74
+ assert_equal "#{Time.at(time).localtime} test: {\"test\"=>\"test2\"}\n", out
75
+
76
+ # NOTE: Float::NAN is not jsonable, but hash string can output it.
60
77
  out = capture_log { d.feed('test', time, {'test' => Float::NAN}) }
61
- assert_equal "#{Time.at(time).localtime} test: {\"test\":NaN}\n", out
78
+ assert_equal "#{Time.at(time).localtime} test: {\"test\"=>NaN}\n", out
62
79
  end
63
80
  end
64
81
 
65
- def test_emit_hash
66
- d = create_driver(CONFIG + "\noutput_type hash")
67
- time = event_time()
68
- out = capture_log do
69
- d.run(default_tag: 'test') do
70
- d.feed(time, {'test' => 'test2'})
82
+ sub_test_case 'buffered' do
83
+ test 'configure' do
84
+ d = create_driver(config_element("ROOT", "", {}, [config_element("buffer")]))
85
+ assert_equal [], d.instance.formatter_configs
86
+ assert_equal 10 * 1024, d.instance.buffer_config.chunk_limit_size
87
+ assert d.instance.buffer_config.flush_at_shutdown
88
+ assert_equal ['tag'], d.instance.buffer_config.chunk_keys
89
+ assert d.instance.chunk_key_tag
90
+ assert !d.instance.chunk_key_time
91
+ assert_equal [], d.instance.chunk_keys
92
+ end
93
+
94
+ test 'configure with output_type' do
95
+ d = create_driver(config_element("ROOT", "", {"output_type" => "json"}, [config_element("buffer")]))
96
+ assert_equal 'json', d.instance.formatter_configs.first[:@type]
97
+
98
+ d = create_driver(config_element("ROOT", "", {"output_type" => "hash"}, [config_element("buffer")]))
99
+ assert_equal 'hash', d.instance.formatter_configs.first[:@type]
100
+
101
+ assert_raise(Fluent::ConfigError) do
102
+ create_driver(config_element("ROOT", "", {"output_type" => "foo"}, [config_element("buffer")]))
71
103
  end
72
104
  end
73
- assert_equal "#{Time.at(time).localtime} test: {\"test\"=>\"test2\"}\n", out
74
105
 
75
- # NOTE: Float::NAN is not jsonable, but hash string can output it.
76
- out = capture_log { d.feed('test', time, {'test' => Float::NAN}) }
77
- assert_equal "#{Time.at(time).localtime} test: {\"test\"=>NaN}\n", out
78
- end
106
+ sub_test_case "emit with default config" do
107
+ test '#write(synchronous)' do
108
+ d = create_driver(config_element("ROOT", "", {}, [config_element("buffer")]))
109
+ time = event_time()
110
+
111
+ out = capture_log do
112
+ d.run(default_tag: 'test', flush: true) do
113
+ d.feed(time, {'test' => 'test'})
114
+ end
115
+ end
116
+ assert_equal "#{Time.at(time).localtime} test: {\"test\":\"test\"}\n", out
117
+ end
118
+ end
79
119
 
80
- private
120
+ sub_test_case "emit json" do
121
+ data('oj' => 'oj', 'yajl' => 'yajl')
122
+ test '#write(synchronous)' do |data|
123
+ d = create_driver(config_element("ROOT", "", {"output_type" => "json", "json_parser" => data}, [config_element("buffer")]))
124
+ time = event_time()
125
+
126
+ out = capture_log do
127
+ d.run(default_tag: 'test', flush: true) do
128
+ d.feed(time, {'test' => 'test'})
129
+ end
130
+ end
131
+ assert_equal "#{Time.at(time).localtime} test: {\"test\":\"test\"}\n", out
132
+ end
133
+
134
+ data('oj' => 'oj', 'yajl' => 'yajl')
135
+ test '#try_write(asynchronous)' do |data|
136
+ d = create_driver(config_element("ROOT", "", {"output_type" => "json", "json_parser" => data}, [config_element("buffer")]))
137
+ time = event_time()
138
+ d.instance.delayed = true
139
+
140
+ out = capture_log do
141
+ d.run(default_tag: 'test', flush: true, shutdown: false) do
142
+ d.feed(time, {'test' => 'test'})
143
+ end
144
+ end
145
+
146
+ assert_equal "#{Time.at(time).localtime} test: {\"test\":\"test\"}\n", out
147
+ end
148
+ end
149
+
150
+ sub_test_case 'emit hash' do
151
+ test '#write(synchronous)' do
152
+ d = create_driver(config_element("ROOT", "", {"output_type" => "hash"}, [config_element("buffer")]))
153
+ time = event_time()
154
+
155
+ out = capture_log do
156
+ d.run(default_tag: 'test', flush: true) do
157
+ d.feed(time, {'test' => 'test'})
158
+ end
159
+ end
160
+
161
+ assert_equal "#{Time.at(time).localtime} test: {\"test\"=>\"test\"}\n", out
162
+ end
163
+
164
+ test '#try_write(asynchronous)' do
165
+ d = create_driver(config_element("ROOT", "", {"output_type" => "hash"}, [config_element("buffer")]))
166
+ time = event_time()
167
+ d.instance.delayed = true
168
+
169
+ out = capture_log do
170
+ d.run(default_tag: 'test', flush: true, shutdown: false) do
171
+ d.feed(time, {'test' => 'test'})
172
+ end
173
+ end
174
+
175
+ assert_equal "#{Time.at(time).localtime} test: {\"test\"=>\"test\"}\n", out
176
+ end
177
+ end
178
+ end
81
179
 
82
180
  # Capture the log output of the block given
83
181
  def capture_log(&block)