fluentd 0.14.17-x64-mingw32 → 1.3.1-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.

Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +16 -5
  3. data/ADOPTERS.md +5 -0
  4. data/{ChangeLog → CHANGELOG.md} +495 -6
  5. data/CONTRIBUTING.md +5 -2
  6. data/GOVERNANCE.md +55 -0
  7. data/LICENSE +202 -0
  8. data/MAINTAINERS.md +7 -5
  9. data/README.md +17 -10
  10. data/bin/fluent-ca-generate +6 -0
  11. data/example/counter.conf +18 -0
  12. data/example/secondary_file.conf +3 -2
  13. data/fluentd.gemspec +3 -3
  14. data/lib/fluent/agent.rb +1 -1
  15. data/lib/fluent/command/binlog_reader.rb +11 -2
  16. data/lib/fluent/command/ca_generate.rb +181 -0
  17. data/lib/fluent/command/cat.rb +28 -15
  18. data/lib/fluent/command/debug.rb +4 -4
  19. data/lib/fluent/command/fluentd.rb +2 -2
  20. data/lib/fluent/command/plugin_config_formatter.rb +24 -2
  21. data/lib/fluent/command/plugin_generator.rb +26 -8
  22. data/lib/fluent/config/configure_proxy.rb +7 -1
  23. data/lib/fluent/config/dsl.rb +8 -5
  24. data/lib/fluent/config/element.rb +5 -0
  25. data/lib/fluent/config/literal_parser.rb +7 -1
  26. data/lib/fluent/config/types.rb +28 -2
  27. data/lib/fluent/config/v1_parser.rb +1 -2
  28. data/lib/fluent/configurable.rb +1 -0
  29. data/lib/fluent/counter.rb +23 -0
  30. data/lib/fluent/counter/base_socket.rb +46 -0
  31. data/lib/fluent/counter/client.rb +297 -0
  32. data/lib/fluent/counter/error.rb +86 -0
  33. data/lib/fluent/counter/mutex_hash.rb +163 -0
  34. data/lib/fluent/counter/server.rb +273 -0
  35. data/lib/fluent/counter/store.rb +205 -0
  36. data/lib/fluent/counter/validator.rb +145 -0
  37. data/lib/fluent/env.rb +1 -0
  38. data/lib/fluent/event_router.rb +1 -1
  39. data/lib/fluent/log.rb +119 -29
  40. data/lib/fluent/plugin/base.rb +12 -0
  41. data/lib/fluent/plugin/buf_file.rb +20 -16
  42. data/lib/fluent/plugin/buffer.rb +130 -32
  43. data/lib/fluent/plugin/buffer/file_chunk.rb +23 -4
  44. data/lib/fluent/plugin/compressable.rb +1 -1
  45. data/lib/fluent/plugin/filter_grep.rb +135 -21
  46. data/lib/fluent/plugin/filter_parser.rb +13 -2
  47. data/lib/fluent/plugin/filter_record_transformer.rb +16 -14
  48. data/lib/fluent/plugin/formatter_stdout.rb +3 -2
  49. data/lib/fluent/plugin/formatter_tsv.rb +5 -1
  50. data/lib/fluent/plugin/in_debug_agent.rb +8 -1
  51. data/lib/fluent/plugin/in_forward.rb +1 -1
  52. data/lib/fluent/plugin/in_http.rb +84 -3
  53. data/lib/fluent/plugin/in_monitor_agent.rb +7 -1
  54. data/lib/fluent/plugin/in_syslog.rb +31 -10
  55. data/lib/fluent/plugin/in_tail.rb +142 -53
  56. data/lib/fluent/plugin/in_tcp.rb +5 -6
  57. data/lib/fluent/plugin/in_udp.rb +6 -2
  58. data/lib/fluent/plugin/in_unix.rb +1 -1
  59. data/lib/fluent/plugin/multi_output.rb +1 -0
  60. data/lib/fluent/plugin/out_copy.rb +25 -2
  61. data/lib/fluent/plugin/out_file.rb +26 -7
  62. data/lib/fluent/plugin/out_forward.rb +81 -42
  63. data/lib/fluent/plugin/out_secondary_file.rb +2 -2
  64. data/lib/fluent/plugin/out_stdout.rb +0 -1
  65. data/lib/fluent/plugin/out_stream.rb +1 -1
  66. data/lib/fluent/plugin/output.rb +221 -57
  67. data/lib/fluent/plugin/parser_apache.rb +1 -1
  68. data/lib/fluent/plugin/parser_apache2.rb +5 -1
  69. data/lib/fluent/plugin/parser_apache_error.rb +1 -1
  70. data/lib/fluent/plugin/parser_json.rb +10 -3
  71. data/lib/fluent/plugin/parser_ltsv.rb +7 -0
  72. data/lib/fluent/plugin/parser_multiline.rb +2 -1
  73. data/lib/fluent/plugin/parser_nginx.rb +1 -1
  74. data/lib/fluent/plugin/parser_none.rb +1 -0
  75. data/lib/fluent/plugin/parser_regexp.rb +15 -14
  76. data/lib/fluent/plugin/parser_syslog.rb +9 -5
  77. data/lib/fluent/plugin_helper.rb +2 -0
  78. data/lib/fluent/plugin_helper/cert_option.rb +28 -9
  79. data/lib/fluent/plugin_helper/compat_parameters.rb +3 -1
  80. data/lib/fluent/plugin_helper/counter.rb +51 -0
  81. data/lib/fluent/plugin_helper/event_loop.rb +9 -0
  82. data/lib/fluent/plugin_helper/record_accessor.rb +210 -0
  83. data/lib/fluent/plugin_helper/retry_state.rb +15 -7
  84. data/lib/fluent/plugin_helper/server.rb +87 -25
  85. data/lib/fluent/plugin_helper/socket_option.rb +5 -2
  86. data/lib/fluent/plugin_helper/timer.rb +8 -7
  87. data/lib/fluent/root_agent.rb +18 -9
  88. data/lib/fluent/supervisor.rb +63 -23
  89. data/lib/fluent/system_config.rb +30 -2
  90. data/lib/fluent/test/helpers.rb +1 -1
  91. data/lib/fluent/time.rb +15 -7
  92. data/lib/fluent/timezone.rb +26 -2
  93. data/lib/fluent/version.rb +1 -1
  94. data/templates/new_gem/README.md.erb +2 -2
  95. data/templates/new_gem/lib/fluent/plugin/filter.rb.erb +1 -1
  96. data/templates/new_gem/lib/fluent/plugin/input.rb.erb +1 -1
  97. data/templates/new_gem/lib/fluent/plugin/output.rb.erb +1 -1
  98. data/templates/new_gem/lib/fluent/plugin/parser.rb.erb +4 -4
  99. data/test/command/test_ca_generate.rb +70 -0
  100. data/test/command/test_fluentd.rb +2 -2
  101. data/test/command/test_plugin_config_formatter.rb +8 -7
  102. data/test/command/test_plugin_generator.rb +65 -39
  103. data/test/config/test_config_parser.rb +7 -2
  104. data/test/config/test_configurable.rb +7 -2
  105. data/test/config/test_configure_proxy.rb +41 -3
  106. data/test/config/test_dsl.rb +10 -10
  107. data/test/config/test_element.rb +10 -0
  108. data/test/config/test_literal_parser.rb +8 -0
  109. data/test/config/test_plugin_configuration.rb +56 -0
  110. data/test/config/test_system_config.rb +19 -1
  111. data/test/config/test_types.rb +37 -0
  112. data/test/counter/test_client.rb +559 -0
  113. data/test/counter/test_error.rb +44 -0
  114. data/test/counter/test_mutex_hash.rb +179 -0
  115. data/test/counter/test_server.rb +589 -0
  116. data/test/counter/test_store.rb +258 -0
  117. data/test/counter/test_validator.rb +137 -0
  118. data/test/plugin/test_buf_file.rb +124 -0
  119. data/test/plugin/test_buffer.rb +3 -2
  120. data/test/plugin/test_filter_grep.rb +580 -2
  121. data/test/plugin/test_filter_parser.rb +33 -2
  122. data/test/plugin/test_filter_record_transformer.rb +22 -1
  123. data/test/plugin/test_formatter_ltsv.rb +3 -0
  124. data/test/plugin/test_formatter_tsv.rb +68 -0
  125. data/test/plugin/test_in_debug_agent.rb +21 -0
  126. data/test/plugin/test_in_exec.rb +3 -5
  127. data/test/plugin/test_in_http.rb +178 -0
  128. data/test/plugin/test_in_monitor_agent.rb +1 -1
  129. data/test/plugin/test_in_syslog.rb +64 -0
  130. data/test/plugin/test_in_tail.rb +116 -6
  131. data/test/plugin/test_in_tcp.rb +21 -0
  132. data/test/plugin/test_in_udp.rb +78 -0
  133. data/test/plugin/test_metadata.rb +89 -0
  134. data/test/plugin/test_out_copy.rb +31 -0
  135. data/test/plugin/test_out_file.rb +108 -2
  136. data/test/plugin/test_out_forward.rb +195 -2
  137. data/test/plugin/test_out_secondary_file.rb +14 -0
  138. data/test/plugin/test_output.rb +159 -45
  139. data/test/plugin/test_output_as_buffered.rb +19 -0
  140. data/test/plugin/test_output_as_buffered_backup.rb +307 -0
  141. data/test/plugin/test_output_as_buffered_retries.rb +70 -0
  142. data/test/plugin/test_output_as_buffered_secondary.rb +1 -1
  143. data/test/plugin/test_parser_apache2.rb +1 -0
  144. data/test/plugin/test_parser_labeled_tsv.rb +17 -0
  145. data/test/plugin/test_parser_nginx.rb +40 -0
  146. data/test/plugin/test_parser_regexp.rb +6 -7
  147. data/test/plugin/test_parser_syslog.rb +155 -5
  148. data/test/plugin_helper/test_child_process.rb +4 -4
  149. data/test/plugin_helper/test_compat_parameters.rb +22 -0
  150. data/test/plugin_helper/test_record_accessor.rb +197 -0
  151. data/test/plugin_helper/test_retry_state.rb +20 -0
  152. data/test/plugin_helper/test_server.rb +30 -2
  153. data/test/test_config.rb +3 -3
  154. data/test/test_configdsl.rb +2 -2
  155. data/test/test_log.rb +51 -1
  156. data/test/test_root_agent.rb +33 -0
  157. data/test/test_supervisor.rb +105 -0
  158. metadata +68 -8
  159. data/COPYING +0 -14
@@ -219,6 +219,24 @@ class BufferedOutputTest < Test::Unit::TestCase
219
219
  Timecop.return
220
220
  end
221
221
 
222
+ test 'queued_chunks_limit_size is same as flush_thread_count by default' do
223
+ hash = {'flush_thread_count' => 4}
224
+ i = create_output
225
+ i.register(:prefer_buffered_processing) { true }
226
+ i.configure(config_element('ROOT', '', {}, [config_element('buffer','tag',hash)]))
227
+
228
+ assert_equal 4, i.buffer.queued_chunks_limit_size
229
+ end
230
+
231
+ test 'prefer queued_chunks_limit_size parameter than flush_thread_count' do
232
+ hash = {'flush_thread_count' => 4, 'queued_chunks_limit_size' => 2}
233
+ i = create_output
234
+ i.register(:prefer_buffered_processing) { true }
235
+ i.configure(config_element('ROOT', '', {}, [config_element('buffer','tag',hash)]))
236
+
237
+ assert_equal 2, i.buffer.queued_chunks_limit_size
238
+ end
239
+
222
240
  sub_test_case 'chunk feature in #write for output plugins' do
223
241
  setup do
224
242
  @stored_global_logger = $log
@@ -1064,6 +1082,7 @@ class BufferedOutputTest < Test::Unit::TestCase
1064
1082
  'flush_thread_count' => 1,
1065
1083
  'flush_thread_burst_interval' => 0.1,
1066
1084
  'chunk_limit_size' => 1024,
1085
+ 'queued_chunks_limit_size' => 100
1067
1086
  }
1068
1087
  @i = create_output(:buffered)
1069
1088
  @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
@@ -0,0 +1,307 @@
1
+ require_relative '../helper'
2
+ require 'fluent/plugin/output'
3
+ require 'fluent/plugin/buffer'
4
+ require 'fluent/event'
5
+ require 'fluent/error'
6
+
7
+ require 'json'
8
+ require 'time'
9
+ require 'timeout'
10
+ require 'timecop'
11
+
12
+
13
+ class BufferedOutputBackupTest < Test::Unit::TestCase
14
+ class BareOutput < Fluent::Plugin::Output
15
+ def register(name, &block)
16
+ instance_variable_set("@#{name}", block)
17
+ end
18
+ end
19
+ class DummyOutput < BareOutput
20
+ def initialize
21
+ super
22
+ @process = nil
23
+ @format = nil
24
+ @write = nil
25
+ @try_write = nil
26
+ end
27
+ def prefer_buffered_processing
28
+ true
29
+ end
30
+ def prefer_delayed_commit
31
+ false
32
+ end
33
+ def process(tag, es)
34
+ @process ? @process.call(tag, es) : nil
35
+ end
36
+ def format(tag, time, record)
37
+ [tag, time.to_i, record].to_json + "\n"
38
+ end
39
+ def write(chunk)
40
+ @write ? @write.call(chunk) : nil
41
+ end
42
+ def try_write(chunk)
43
+ @try_write ? @try_write.call(chunk) : nil
44
+ end
45
+ end
46
+ class DummyOutputForSecondary < BareOutput
47
+ def initialize
48
+ super
49
+ @process = nil
50
+ @format = nil
51
+ @write = nil
52
+ @try_write = nil
53
+ end
54
+ def prefer_buffered_processing
55
+ true
56
+ end
57
+ def prefer_delayed_commit
58
+ false
59
+ end
60
+ def process(tag, es)
61
+ @process ? @process.call(tag, es) : nil
62
+ end
63
+ def format(tag, time, record)
64
+ [tag, time.to_i, record].to_json + "\n"
65
+ end
66
+ def write(chunk)
67
+ @write ? @write.call(chunk) : nil
68
+ end
69
+ def try_write(chunk)
70
+ @try_write ? @try_write.call(chunk) : nil
71
+ end
72
+ end
73
+ class DummyAsyncOutputForSecondary < BareOutput
74
+ def initialize
75
+ super
76
+ @process = nil
77
+ @format = nil
78
+ @write = nil
79
+ @try_write = nil
80
+ end
81
+ def prefer_buffered_processing
82
+ true
83
+ end
84
+ def prefer_delayed_commit
85
+ true
86
+ end
87
+ def process(tag, es)
88
+ @process ? @process.call(tag, es) : nil
89
+ end
90
+ def format(tag, time, record)
91
+ [tag, time.to_i, record].to_json + "\n"
92
+ end
93
+ def write(chunk)
94
+ @write ? @write.call(chunk) : nil
95
+ end
96
+ def try_write(chunk)
97
+ @try_write ? @try_write.call(chunk) : nil
98
+ end
99
+ end
100
+
101
+ TMP_DIR = File.expand_path(File.dirname(__FILE__) + "/../tmp/bu#{ENV['TEST_ENV_NUMBER']}")
102
+
103
+ def create_output
104
+ DummyOutput.new
105
+ end
106
+ def create_metadata(timekey: nil, tag: nil, variables: nil)
107
+ Fluent::Plugin::Buffer::Metadata.new(timekey, tag, variables)
108
+ end
109
+ def waiting(seconds)
110
+ begin
111
+ Timeout.timeout(seconds) do
112
+ yield
113
+ end
114
+ rescue Timeout::Error
115
+ STDERR.print(*@i.log.out.logs)
116
+ raise
117
+ end
118
+ end
119
+
120
+ def dummy_event_stream
121
+ Fluent::ArrayEventStream.new([
122
+ [ event_time('2016-04-13 18:33:00'), {"name" => "moris", "age" => 36, "message" => "data1"} ],
123
+ [ event_time('2016-04-13 18:33:13'), {"name" => "moris", "age" => 36, "message" => "data2"} ],
124
+ [ event_time('2016-04-13 18:33:32'), {"name" => "moris", "age" => 36, "message" => "data3"} ],
125
+ ])
126
+ end
127
+
128
+ setup do
129
+ @i = create_output
130
+ FileUtils.rm_rf(TMP_DIR)
131
+ FileUtils.mkdir_p(TMP_DIR)
132
+
133
+ Fluent::Plugin.register_output('backup_output', DummyOutput)
134
+ Fluent::Plugin.register_output('backup_output2', DummyOutputForSecondary)
135
+ Fluent::Plugin.register_output('backup_async_output', DummyAsyncOutputForSecondary)
136
+ end
137
+
138
+ teardown do
139
+ if @i
140
+ @i.stop unless @i.stopped?
141
+ @i.before_shutdown unless @i.before_shutdown?
142
+ @i.shutdown unless @i.shutdown?
143
+ @i.after_shutdown unless @i.after_shutdown?
144
+ @i.close unless @i.closed?
145
+ @i.terminate unless @i.terminated?
146
+ end
147
+ Timecop.return
148
+ end
149
+
150
+ sub_test_case 'buffered output for broken chunks' do
151
+ def flush_chunks
152
+ @i.start
153
+ @i.after_start
154
+
155
+ @i.interrupt_flushes
156
+
157
+ now = Time.parse('2016-04-13 18:33:30 -0700')
158
+ Timecop.freeze(now)
159
+ @i.emit_events("test.tag.1", dummy_event_stream())
160
+ now = Time.parse('2016-04-13 18:33:32 -0700')
161
+ Timecop.freeze(now)
162
+
163
+ @i.enqueue_thread_wait
164
+ @i.flush_thread_wakeup
165
+ waiting(4) { Thread.pass until @i.write_count > 0 }
166
+
167
+ assert { @i.write_count > 0 }
168
+ Timecop.freeze(now)
169
+ @i.flush_thread_wakeup
170
+ end
171
+
172
+ def wait_flush(target_file)
173
+ waiting(5) {
174
+ target_dir = File.join(File.dirname(target_file), "*")
175
+ while Dir.glob(target_dir).size.zero?
176
+ end
177
+ }
178
+ end
179
+
180
+ test 'backup chunk without secondary' do
181
+ Fluent::SystemConfig.overwrite_system_config('root_dir' => TMP_DIR) do
182
+ id = 'backup_test'
183
+ hash = {
184
+ 'flush_interval' => 1,
185
+ 'flush_thread_burst_interval' => 0.1,
186
+ }
187
+ chunk_id = nil
188
+ @i.configure(config_element('ROOT', '', {'@id' => id}, [config_element('buffer', 'tag', hash)]))
189
+ @i.register(:write) { |chunk|
190
+ chunk_id = chunk.unique_id;
191
+ raise Fluent::UnrecoverableError, "yay, your #write must fail"
192
+ }
193
+
194
+ flush_chunks
195
+
196
+ target = "#{TMP_DIR}/backup/worker0/#{id}/#{@i.dump_unique_id_hex(chunk_id)}.log"
197
+ wait_flush(target)
198
+ assert_true File.exist?(target)
199
+ logs = @i.log.out.logs
200
+ assert { logs.any? { |l| l.include?("got unrecoverable error in primary and no secondary") } }
201
+ end
202
+ end
203
+
204
+ test 'backup chunk with same type secondary' do
205
+ Fluent::SystemConfig.overwrite_system_config('root_dir' => TMP_DIR) do
206
+ id = 'backup_test_with_same_secondary'
207
+ hash = {
208
+ 'flush_interval' => 1,
209
+ 'flush_thread_burst_interval' => 0.1,
210
+ }
211
+ chunk_id = nil
212
+ secconf = config_element('secondary','',{'@type' => 'backup_output'})
213
+ @i.configure(config_element('ROOT', '', {'@id' => id}, [config_element('buffer', 'tag', hash), secconf]))
214
+ @i.register(:write) { |chunk|
215
+ chunk_id = chunk.unique_id;
216
+ raise Fluent::UnrecoverableError, "yay, your #write must fail"
217
+ }
218
+
219
+ flush_chunks
220
+
221
+ target = "#{TMP_DIR}/backup/worker0/#{id}/#{@i.dump_unique_id_hex(chunk_id)}.log"
222
+ wait_flush(target)
223
+ assert_true File.exist?(target)
224
+ logs = @i.log.out.logs
225
+ assert { logs.any? { |l| l.include?("got unrecoverable error in primary and secondary type is same as primary") } }
226
+ end
227
+ end
228
+
229
+ test 'backup chunk with different type secondary' do
230
+ Fluent::SystemConfig.overwrite_system_config('root_dir' => TMP_DIR) do
231
+ id = 'backup_test_with_diff_secondary'
232
+ hash = {
233
+ 'flush_interval' => 1,
234
+ 'flush_thread_burst_interval' => 0.1,
235
+ }
236
+ chunk_id = nil
237
+ secconf = config_element('secondary','',{'@type' => 'backup_output2'})
238
+ @i.configure(config_element('ROOT', '', {'@id' => id}, [config_element('buffer', 'tag', hash), secconf]))
239
+ @i.register(:write) { |chunk|
240
+ chunk_id = chunk.unique_id;
241
+ raise Fluent::UnrecoverableError, "yay, your #write must fail"
242
+ }
243
+ @i.secondary.register(:write) { |chunk|
244
+ raise Fluent::UnrecoverableError, "yay, your secondary #write must fail"
245
+ }
246
+
247
+ flush_chunks
248
+
249
+ target = "#{TMP_DIR}/backup/worker0/#{id}/#{@i.dump_unique_id_hex(chunk_id)}.log"
250
+ wait_flush(target)
251
+ assert_true File.exist?(target)
252
+ logs = @i.log.out.logs
253
+ assert { logs.any? { |l| l.include?("got unrecoverable error in primary. Skip retry and flush chunk to secondary") } }
254
+ assert { logs.any? { |l| l.include?("got an error in secondary for unrecoverable error") } }
255
+ end
256
+ end
257
+
258
+ test 'backup chunk with async secondary' do
259
+ Fluent::SystemConfig.overwrite_system_config('root_dir' => TMP_DIR) do
260
+ id = 'backup_test_with_diff_secondary'
261
+ hash = {
262
+ 'flush_interval' => 1,
263
+ 'flush_thread_burst_interval' => 0.1,
264
+ }
265
+ chunk_id = nil
266
+ secconf = config_element('secondary','',{'@type' => 'backup_async_output'})
267
+ @i.configure(config_element('ROOT', '', {'@id' => id}, [config_element('buffer', 'tag', hash), secconf]))
268
+ @i.register(:write) { |chunk|
269
+ chunk_id = chunk.unique_id;
270
+ raise Fluent::UnrecoverableError, "yay, your #write must fail"
271
+ }
272
+
273
+ flush_chunks
274
+
275
+ target = "#{TMP_DIR}/backup/worker0/#{id}/#{@i.dump_unique_id_hex(chunk_id)}.log"
276
+ wait_flush(target)
277
+ assert_true File.exist?(target)
278
+ logs = @i.log.out.logs
279
+ assert { logs.any? { |l| l.include?("got unrecoverable error in primary and secondary is async output") } }
280
+ end
281
+ end
282
+
283
+ test 'chunk is thrown away when disable_chunk_backup is true' do
284
+ Fluent::SystemConfig.overwrite_system_config('root_dir' => TMP_DIR) do
285
+ id = 'backup_test'
286
+ hash = {
287
+ 'flush_interval' => 1,
288
+ 'flush_thread_burst_interval' => 0.1,
289
+ 'disable_chunk_backup' => true
290
+ }
291
+ chunk_id = nil
292
+ @i.configure(config_element('ROOT', '', {'@id' => id}, [config_element('buffer', 'tag', hash)]))
293
+ @i.register(:write) { |chunk|
294
+ chunk_id = chunk.unique_id;
295
+ raise Fluent::UnrecoverableError, "yay, your #write must fail"
296
+ }
297
+
298
+ flush_chunks
299
+
300
+ target = "#{TMP_DIR}/backup/worker0/#{id}/#{@i.dump_unique_id_hex(chunk_id)}.log"
301
+ assert_false File.exist?(target)
302
+ logs = @i.log.out.logs
303
+ assert { logs.any? { |l| l.include?("disable_chunk_backup is true") } }
304
+ end
305
+ end
306
+ end
307
+ end
@@ -123,6 +123,7 @@ class BufferedOutputRetryTest < Test::Unit::TestCase
123
123
  'flush_interval' => 1,
124
124
  'flush_thread_burst_interval' => 0.1,
125
125
  'retry_randomize' => false,
126
+ 'queued_chunks_limit_size' => 100
126
127
  }
127
128
  @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
128
129
  @i.register(:prefer_buffered_processing){ true }
@@ -252,6 +253,7 @@ class BufferedOutputRetryTest < Test::Unit::TestCase
252
253
  'flush_thread_burst_interval' => 0.1,
253
254
  'retry_randomize' => false,
254
255
  'retry_timeout' => 3600,
256
+ 'queued_chunks_limit_size' => 100
255
257
  }
256
258
  @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
257
259
  @i.register(:prefer_buffered_processing){ true }
@@ -342,6 +344,7 @@ class BufferedOutputRetryTest < Test::Unit::TestCase
342
344
  'flush_thread_burst_interval' => 0.1,
343
345
  'retry_randomize' => false,
344
346
  'retry_max_times' => 10,
347
+ 'queued_chunks_limit_size' => 100
345
348
  }
346
349
  @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
347
350
  @i.register(:prefer_buffered_processing){ true }
@@ -412,6 +415,68 @@ class BufferedOutputRetryTest < Test::Unit::TestCase
412
415
  assert{ @i.buffer.stage.size == 1 }
413
416
  assert{ chunks.all?{|c| c.empty? } }
414
417
  end
418
+
419
+ test 'output plugin limits queued chunks via queued_chunks_limit_size' do
420
+ chunk_key = 'tag'
421
+ hash = {
422
+ 'flush_interval' => 1,
423
+ 'flush_thread_burst_interval' => 0.1,
424
+ 'retry_randomize' => false,
425
+ 'retry_max_times' => 7,
426
+ 'queued_chunks_limit_size' => 2,
427
+ }
428
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
429
+ @i.register(:prefer_buffered_processing) { true }
430
+ @i.register(:format) { |tag,time,record| [tag,time.to_i,record].to_json + "\n" }
431
+ @i.register(:write) { |chunk| raise "yay, your #write must fail" }
432
+ @i.start
433
+ @i.after_start
434
+
435
+ @i.interrupt_flushes
436
+
437
+ now = Time.parse('2016-04-13 18:33:30 -0700')
438
+ Timecop.freeze(now)
439
+
440
+ @i.emit_events("test.tag.1", dummy_event_stream())
441
+
442
+ now = Time.parse('2016-04-13 18:33:31 -0700')
443
+ Timecop.freeze(now)
444
+
445
+ @i.emit_events("test.tag.2", dummy_event_stream())
446
+
447
+ @i.enqueue_thread_wait
448
+ @i.flush_thread_wakeup
449
+ waiting(4) { Thread.pass until @i.write_count > 0 && @i.num_errors > 0 }
450
+
451
+ assert { @i.buffer.queue.size > 0 }
452
+ assert { @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
453
+
454
+ assert { @i.write_count > 0 }
455
+ assert { @i.num_errors > 0 }
456
+
457
+ prev_write_count = @i.write_count
458
+ prev_num_errors = @i.num_errors
459
+
460
+ chunks = @i.buffer.queue.dup
461
+
462
+ 20.times do |i| # large times enough
463
+ now = @i.next_flush_time
464
+
465
+ Timecop.freeze(now)
466
+ @i.enqueue_thread_wait
467
+ @i.flush_thread_wakeup
468
+ waiting(4) { Thread.pass until @i.write_count > prev_write_count && @i.num_errors > prev_num_errors }
469
+
470
+ @i.emit_events("test.tag.1", dummy_event_stream())
471
+ assert { @i.buffer.queue.size <= 2 }
472
+ assert { @i.buffer.stage.size == 1 } # all new data is stored into staged chunk
473
+
474
+ break if @i.buffer.queue.size == 0
475
+
476
+ prev_write_count = @i.write_count
477
+ prev_num_errors = @i.num_errors
478
+ end
479
+ end
415
480
  end
416
481
 
417
482
  sub_test_case 'bufferd output for retries with periodical retry' do
@@ -423,6 +488,7 @@ class BufferedOutputRetryTest < Test::Unit::TestCase
423
488
  'retry_type' => :periodic,
424
489
  'retry_wait' => 3,
425
490
  'retry_randomize' => false,
491
+ 'queued_chunks_limit_size' => 100
426
492
  }
427
493
  @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
428
494
  @i.register(:prefer_buffered_processing){ true }
@@ -469,6 +535,7 @@ class BufferedOutputRetryTest < Test::Unit::TestCase
469
535
  'retry_wait' => 30,
470
536
  'retry_randomize' => false,
471
537
  'retry_timeout' => 120,
538
+ 'queued_chunks_limit_size' => 100
472
539
  }
473
540
  @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
474
541
  @i.register(:prefer_buffered_processing){ true }
@@ -564,6 +631,7 @@ class BufferedOutputRetryTest < Test::Unit::TestCase
564
631
  'retry_wait' => 3,
565
632
  'retry_randomize' => false,
566
633
  'retry_max_times' => 10,
634
+ 'queued_chunks_limit_size' => 100
567
635
  }
568
636
  @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
569
637
  @i.register(:prefer_buffered_processing){ true }
@@ -662,6 +730,7 @@ class BufferedOutputRetryTest < Test::Unit::TestCase
662
730
  'retry_randomize' => false,
663
731
  'retry_timeout' => 3600,
664
732
  'retry_max_times' => 10,
733
+ 'queued_chunks_limit_size' => 100
665
734
  }
666
735
  @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
667
736
  @i.register(:prefer_buffered_processing){ true }
@@ -733,6 +802,7 @@ class BufferedOutputRetryTest < Test::Unit::TestCase
733
802
  'retry_wait' => 30,
734
803
  'retry_timeout' => 360,
735
804
  'retry_max_times' => 10,
805
+ 'queued_chunks_limit_size' => 100
736
806
  }
737
807
  @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
738
808
  @i.register(:prefer_buffered_processing){ true }