fluent-plugin-es-mohit 1.9.3

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.
@@ -0,0 +1,1138 @@
1
+ require 'helper'
2
+ require 'date'
3
+
4
+ class ElasticsearchOutput < Test::Unit::TestCase
5
+ attr_accessor :index_cmds, :index_command_counts
6
+
7
+ def setup
8
+ Fluent::Test.setup
9
+ require 'fluent/plugin/out_elasticsearch'
10
+ @driver = nil
11
+ log = Fluent::Engine.log
12
+ log.out.logs.slice!(0, log.out.logs.length)
13
+ end
14
+
15
+ def driver(tag='test', conf='')
16
+ @driver ||= Fluent::Test::BufferedOutputTestDriver.new(Fluent::ElasticsearchOutput, tag).configure(conf)
17
+ end
18
+
19
+ def sample_record
20
+ {'age' => 26, 'request_id' => '42', 'parent_id' => 'parent', 'routing_id' => 'routing'}
21
+ end
22
+
23
+ def stub_elastic_ping(url="http://localhost:9200")
24
+ stub_request(:head, url).to_return(:status => 200, :body => "", :headers => {})
25
+ end
26
+
27
+ def stub_elastic(url="http://localhost:9200/_bulk")
28
+ stub_request(:post, url).with do |req|
29
+ @index_cmds = req.body.split("\n").map {|r| JSON.parse(r) }
30
+ end
31
+ end
32
+
33
+ def stub_elastic_unavailable(url="http://localhost:9200/_bulk")
34
+ stub_request(:post, url).to_return(:status => [503, "Service Unavailable"])
35
+ end
36
+
37
+ def stub_elastic_with_store_index_command_counts(url="http://localhost:9200/_bulk")
38
+ if @index_command_counts == nil
39
+ @index_command_counts = {}
40
+ @index_command_counts.default = 0
41
+ end
42
+
43
+ stub_request(:post, url).with do |req|
44
+ index_cmds = req.body.split("\n").map {|r| JSON.parse(r) }
45
+ @index_command_counts[url] += index_cmds.size
46
+ end
47
+ end
48
+
49
+ def test_configure
50
+ config = %{
51
+ host logs.google.com
52
+ port 777
53
+ scheme https
54
+ path /es/
55
+ user john
56
+ password doe
57
+ }
58
+ instance = driver('test', config).instance
59
+
60
+ assert_equal 'logs.google.com', instance.host
61
+ assert_equal 777, instance.port
62
+ assert_equal 'https', instance.scheme
63
+ assert_equal '/es/', instance.path
64
+ assert_equal 'john', instance.user
65
+ assert_equal 'doe', instance.password
66
+ end
67
+
68
+ def test_template_already_present
69
+ config = %{
70
+ host logs.google.com
71
+ port 777
72
+ scheme https
73
+ path /es/
74
+ user john
75
+ password doe
76
+ template_name logstash
77
+ template_file /abc123
78
+ }
79
+
80
+ # connection start
81
+ stub_request(:head, "https://john:doe@logs.google.com:777/es//").
82
+ to_return(:status => 200, :body => "", :headers => {})
83
+ # check if template exists
84
+ stub_request(:get, "https://john:doe@logs.google.com:777/es//_template/logstash").
85
+ to_return(:status => 200, :body => "", :headers => {})
86
+
87
+ driver('test', config)
88
+ end
89
+
90
+ def test_template_create
91
+ cwd = File.dirname(__FILE__)
92
+ template_file = File.join(cwd, 'test_template.json')
93
+
94
+ config = %{
95
+ host logs.google.com
96
+ port 777
97
+ scheme https
98
+ path /es/
99
+ user john
100
+ password doe
101
+ template_name logstash
102
+ template_file #{template_file}
103
+ }
104
+
105
+ # connection start
106
+ stub_request(:head, "https://john:doe@logs.google.com:777/es//").
107
+ to_return(:status => 200, :body => "", :headers => {})
108
+ # check if template exists
109
+ stub_request(:get, "https://john:doe@logs.google.com:777/es//_template/logstash").
110
+ to_return(:status => 404, :body => "", :headers => {})
111
+ # creation
112
+ stub_request(:put, "https://john:doe@logs.google.com:777/es//_template/logstash").
113
+ to_return(:status => 200, :body => "", :headers => {})
114
+
115
+ driver('test', config)
116
+ end
117
+
118
+
119
+ def test_template_create_invalid_filename
120
+ config = %{
121
+ host logs.google.com
122
+ port 777
123
+ scheme https
124
+ path /es/
125
+ user john
126
+ password doe
127
+ template_name logstash
128
+ template_file /abc123
129
+ }
130
+
131
+ # connection start
132
+ stub_request(:head, "https://john:doe@logs.google.com:777/es//").
133
+ to_return(:status => 200, :body => "", :headers => {})
134
+ # check if template exists
135
+ stub_request(:get, "https://john:doe@logs.google.com:777/es//_template/logstash").
136
+ to_return(:status => 404, :body => "", :headers => {})
137
+
138
+ assert_raise(RuntimeError) {
139
+ driver('test', config)
140
+ }
141
+ end
142
+
143
+ def test_templates_create
144
+ cwd = File.dirname(__FILE__)
145
+ template_file = File.join(cwd, 'test_template.json')
146
+ config = %{
147
+ host logs.google.com
148
+ port 777
149
+ scheme https
150
+ path /es/
151
+ user john
152
+ password doe
153
+ templates {"logstash1":"#{template_file}", "logstash2":"#{template_file}","logstash3":"#{template_file}" }
154
+ }
155
+
156
+ stub_request(:head, "https://john:doe@logs.google.com:777/es//").
157
+ to_return(:status => 200, :body => "", :headers => {})
158
+ # check if template exists
159
+ stub_request(:get, "https://john:doe@logs.google.com:777/es//_template/logstash1").
160
+ to_return(:status => 404, :body => "", :headers => {})
161
+ stub_request(:get, "https://john:doe@logs.google.com:777/es//_template/logstash2").
162
+ to_return(:status => 404, :body => "", :headers => {})
163
+
164
+ stub_request(:get, "https://john:doe@logs.google.com:777/es//_template/logstash3").
165
+ to_return(:status => 200, :body => "", :headers => {}) #exists
166
+
167
+ stub_request(:put, "https://john:doe@logs.google.com:777/es//_template/logstash1").
168
+ to_return(:status => 200, :body => "", :headers => {})
169
+ stub_request(:put, "https://john:doe@logs.google.com:777/es//_template/logstash2").
170
+ to_return(:status => 200, :body => "", :headers => {})
171
+ stub_request(:put, "https://john:doe@logs.google.com:777/es//_template/logstash3").
172
+ to_return(:status => 200, :body => "", :headers => {})
173
+
174
+ driver('test', config)
175
+
176
+ assert_requested( :put, "https://john:doe@logs.google.com:777/es//_template/logstash1", times: 1)
177
+ assert_requested( :put, "https://john:doe@logs.google.com:777/es//_template/logstash2", times: 1)
178
+ assert_not_requested(:put, "https://john:doe@logs.google.com:777/es//_template/logstash3") #exists
179
+ end
180
+
181
+ def test_templates_not_used
182
+ cwd = File.dirname(__FILE__)
183
+ template_file = File.join(cwd, 'test_template.json')
184
+
185
+ config = %{
186
+ host logs.google.com
187
+ port 777
188
+ scheme https
189
+ path /es/
190
+ user john
191
+ password doe
192
+ template_name logstash
193
+ template_file #{template_file}
194
+ templates {"logstash1":"#{template_file}", "logstash2":"#{template_file}" }
195
+ }
196
+ # connection start
197
+ stub_request(:head, "https://john:doe@logs.google.com:777/es//").
198
+ to_return(:status => 200, :body => "", :headers => {})
199
+ # check if template exists
200
+ stub_request(:get, "https://john:doe@logs.google.com:777/es//_template/logstash").
201
+ to_return(:status => 404, :body => "", :headers => {})
202
+ stub_request(:get, "https://john:doe@logs.google.com:777/es//_template/logstash1").
203
+ to_return(:status => 404, :body => "", :headers => {})
204
+ stub_request(:get, "https://john:doe@logs.google.com:777/es//_template/logstash2").
205
+ to_return(:status => 404, :body => "", :headers => {})
206
+ #creation
207
+ stub_request(:put, "https://john:doe@logs.google.com:777/es//_template/logstash").
208
+ to_return(:status => 200, :body => "", :headers => {})
209
+ stub_request(:put, "https://john:doe@logs.google.com:777/es//_template/logstash1").
210
+ to_return(:status => 200, :body => "", :headers => {})
211
+ stub_request(:put, "https://john:doe@logs.google.com:777/es//_template/logstash2").
212
+ to_return(:status => 200, :body => "", :headers => {})
213
+
214
+ driver('test', config)
215
+
216
+ assert_requested(:put, "https://john:doe@logs.google.com:777/es//_template/logstash", times: 1)
217
+
218
+ assert_not_requested(:put, "https://john:doe@logs.google.com:777/es//_template/logstash1")
219
+ assert_not_requested(:put, "https://john:doe@logs.google.com:777/es//_template/logstash2")
220
+ end
221
+
222
+ def test_templates_can_be_partially_created_if_error_occurs
223
+ cwd = File.dirname(__FILE__)
224
+ template_file = File.join(cwd, 'test_template.json')
225
+ config = %{
226
+ host logs.google.com
227
+ port 777
228
+ scheme https
229
+ path /es/
230
+ user john
231
+ password doe
232
+ templates {"logstash1":"#{template_file}", "logstash2":"/abc" }
233
+ }
234
+ stub_request(:head, "https://john:doe@logs.google.com:777/es//").
235
+ to_return(:status => 200, :body => "", :headers => {})
236
+ # check if template exists
237
+ stub_request(:get, "https://john:doe@logs.google.com:777/es//_template/logstash1").
238
+ to_return(:status => 404, :body => "", :headers => {})
239
+ stub_request(:get, "https://john:doe@logs.google.com:777/es//_template/logstash2").
240
+ to_return(:status => 404, :body => "", :headers => {})
241
+
242
+ stub_request(:put, "https://john:doe@logs.google.com:777/es//_template/logstash1").
243
+ to_return(:status => 200, :body => "", :headers => {})
244
+ stub_request(:put, "https://john:doe@logs.google.com:777/es//_template/logstash2").
245
+ to_return(:status => 200, :body => "", :headers => {})
246
+
247
+ assert_raise(RuntimeError) {
248
+ driver('test', config)
249
+ }
250
+
251
+ assert_requested(:put, "https://john:doe@logs.google.com:777/es//_template/logstash1", times: 1)
252
+ assert_not_requested(:put, "https://john:doe@logs.google.com:777/es//_template/logstash2")
253
+ end
254
+
255
+ def test_legacy_hosts_list
256
+ config = %{
257
+ hosts host1:50,host2:100,host3
258
+ scheme https
259
+ path /es/
260
+ port 123
261
+ }
262
+ instance = driver('test', config).instance
263
+
264
+ assert_equal 3, instance.get_connection_options[:hosts].length
265
+ host1, host2, host3 = instance.get_connection_options[:hosts]
266
+
267
+ assert_equal 'host1', host1[:host]
268
+ assert_equal 50, host1[:port]
269
+ assert_equal 'https', host1[:scheme]
270
+ assert_equal '/es/', host2[:path]
271
+ assert_equal 'host3', host3[:host]
272
+ assert_equal 123, host3[:port]
273
+ assert_equal 'https', host3[:scheme]
274
+ assert_equal '/es/', host3[:path]
275
+ end
276
+
277
+ def test_hosts_list
278
+ config = %{
279
+ hosts https://john:password@host1:443/elastic/,http://host2
280
+ path /default_path
281
+ user default_user
282
+ password default_password
283
+ }
284
+ instance = driver('test', config).instance
285
+
286
+ assert_equal 2, instance.get_connection_options[:hosts].length
287
+ host1, host2 = instance.get_connection_options[:hosts]
288
+
289
+ assert_equal 'host1', host1[:host]
290
+ assert_equal 443, host1[:port]
291
+ assert_equal 'https', host1[:scheme]
292
+ assert_equal 'john', host1[:user]
293
+ assert_equal 'password', host1[:password]
294
+ assert_equal '/elastic/', host1[:path]
295
+
296
+ assert_equal 'host2', host2[:host]
297
+ assert_equal 'http', host2[:scheme]
298
+ assert_equal 'default_user', host2[:user]
299
+ assert_equal 'default_password', host2[:password]
300
+ assert_equal '/default_path', host2[:path]
301
+ end
302
+
303
+ def test_single_host_params_and_defaults
304
+ config = %{
305
+ host logs.google.com
306
+ user john
307
+ password doe
308
+ }
309
+ instance = driver('test', config).instance
310
+
311
+ assert_equal 1, instance.get_connection_options[:hosts].length
312
+ host1 = instance.get_connection_options[:hosts][0]
313
+
314
+ assert_equal 'logs.google.com', host1[:host]
315
+ assert_equal 9200, host1[:port]
316
+ assert_equal 'http', host1[:scheme]
317
+ assert_equal 'john', host1[:user]
318
+ assert_equal 'doe', host1[:password]
319
+ assert_equal nil, host1[:path]
320
+ end
321
+
322
+ def test_writes_to_default_index
323
+ stub_elastic_ping
324
+ stub_elastic
325
+ driver.emit(sample_record)
326
+ driver.run
327
+ assert_equal('fluentd', index_cmds.first['index']['_index'])
328
+ end
329
+
330
+ def test_writes_to_default_type
331
+ stub_elastic_ping
332
+ stub_elastic
333
+ driver.emit(sample_record)
334
+ driver.run
335
+ assert_equal('fluentd', index_cmds.first['index']['_type'])
336
+ end
337
+
338
+ def test_writes_to_speficied_index
339
+ driver.configure("index_name myindex\n")
340
+ stub_elastic_ping
341
+ stub_elastic
342
+ driver.emit(sample_record)
343
+ driver.run
344
+ assert_equal('myindex', index_cmds.first['index']['_index'])
345
+ end
346
+
347
+ def test_writes_to_speficied_index_uppercase
348
+ driver.configure("index_name MyIndex\n")
349
+ stub_elastic_ping
350
+ stub_elastic
351
+ driver.emit(sample_record)
352
+ driver.run
353
+ # Allthough index_name has upper-case characters,
354
+ # it should be set as lower-case when sent to elasticsearch.
355
+ assert_equal('myindex', index_cmds.first['index']['_index'])
356
+ end
357
+
358
+ def test_writes_to_target_index_key
359
+ driver.configure("target_index_key @target_index\n")
360
+ stub_elastic_ping
361
+ stub_elastic
362
+ record = sample_record.clone
363
+ driver.emit(sample_record.merge('@target_index' => 'local-override'))
364
+ driver.run
365
+ assert_equal('local-override', index_cmds.first['index']['_index'])
366
+ assert_nil(index_cmds[1]['@target_index'])
367
+ end
368
+
369
+ def test_writes_to_target_index_key_logstash
370
+ driver.configure("target_index_key @target_index
371
+ logstash_format true")
372
+ time = Time.parse Date.today.to_s
373
+ stub_elastic_ping
374
+ stub_elastic
375
+ driver.emit(sample_record.merge('@target_index' => 'local-override'), time.to_i)
376
+ driver.run
377
+ assert_equal('local-override', index_cmds.first['index']['_index'])
378
+ end
379
+
380
+ def test_writes_to_target_index_key_logstash_uppercase
381
+ driver.configure("target_index_key @target_index
382
+ logstash_format true")
383
+ time = Time.parse Date.today.to_s
384
+ stub_elastic_ping
385
+ stub_elastic
386
+ driver.emit(sample_record.merge('@target_index' => 'Local-Override'), time.to_i)
387
+ driver.run
388
+ # Allthough @target_index has upper-case characters,
389
+ # it should be set as lower-case when sent to elasticsearch.
390
+ assert_equal('local-override', index_cmds.first['index']['_index'])
391
+ end
392
+
393
+ def test_writes_to_target_index_key_fallack
394
+ driver.configure("target_index_key @target_index\n")
395
+ stub_elastic_ping
396
+ stub_elastic
397
+ driver.emit(sample_record)
398
+ driver.run
399
+ assert_equal('fluentd', index_cmds.first['index']['_index'])
400
+ end
401
+
402
+ def test_writes_to_target_index_key_fallack_logstash
403
+ driver.configure("target_index_key @target_index\n
404
+ logstash_format true")
405
+ time = Time.parse Date.today.to_s
406
+ logstash_index = "logstash-#{time.getutc.strftime("%Y.%m.%d")}"
407
+ stub_elastic_ping
408
+ stub_elastic
409
+ driver.emit(sample_record, time.to_i)
410
+ driver.run
411
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
412
+ end
413
+
414
+ def test_writes_to_speficied_type
415
+ driver.configure("type_name mytype\n")
416
+ stub_elastic_ping
417
+ stub_elastic
418
+ driver.emit(sample_record)
419
+ driver.run
420
+ assert_equal('mytype', index_cmds.first['index']['_type'])
421
+ end
422
+
423
+ def test_writes_to_target_type_key
424
+ driver.configure("target_type_key @target_type\n")
425
+ stub_elastic_ping
426
+ stub_elastic
427
+ record = sample_record.clone
428
+ driver.emit(sample_record.merge('@target_type' => 'local-override'))
429
+ driver.run
430
+ assert_equal('local-override', index_cmds.first['index']['_type'])
431
+ assert_nil(index_cmds[1]['@target_type'])
432
+ end
433
+
434
+ def test_writes_to_target_type_key_fallack_to_default
435
+ driver.configure("target_type_key @target_type\n")
436
+ stub_elastic_ping
437
+ stub_elastic
438
+ driver.emit(sample_record)
439
+ driver.run
440
+ assert_equal('fluentd', index_cmds.first['index']['_type'])
441
+ end
442
+
443
+ def test_writes_to_target_type_key_fallack_to_type_name
444
+ driver.configure("target_type_key @target_type
445
+ type_name mytype")
446
+ stub_elastic_ping
447
+ stub_elastic
448
+ driver.emit(sample_record)
449
+ driver.run
450
+ assert_equal('mytype', index_cmds.first['index']['_type'])
451
+ end
452
+
453
+ def test_writes_to_target_type_key_nested
454
+ driver.configure("target_type_key kubernetes.labels.log_type\n")
455
+ stub_elastic_ping
456
+ stub_elastic
457
+ driver.emit(sample_record.merge('kubernetes' => {
458
+ 'labels' => {
459
+ 'log_type' => 'local-override'
460
+ }
461
+ }))
462
+ driver.run
463
+ assert_equal('local-override', index_cmds.first['index']['_type'])
464
+ assert_nil(index_cmds[1]['kubernetes']['labels']['log_type'])
465
+ end
466
+
467
+ def test_writes_to_target_type_key_fallack_to_default_nested
468
+ driver.configure("target_type_key kubernetes.labels.log_type\n")
469
+ stub_elastic_ping
470
+ stub_elastic
471
+ driver.emit(sample_record.merge('kubernetes' => {
472
+ 'labels' => {
473
+ 'other_labels' => 'test'
474
+ }
475
+ }))
476
+ driver.run
477
+ assert_equal('fluentd', index_cmds.first['index']['_type'])
478
+ end
479
+
480
+ def test_writes_to_speficied_host
481
+ driver.configure("host 192.168.33.50\n")
482
+ stub_elastic_ping("http://192.168.33.50:9200")
483
+ elastic_request = stub_elastic("http://192.168.33.50:9200/_bulk")
484
+ driver.emit(sample_record)
485
+ driver.run
486
+ assert_requested(elastic_request)
487
+ end
488
+
489
+ def test_writes_to_speficied_port
490
+ driver.configure("port 9201\n")
491
+ stub_elastic_ping("http://localhost:9201")
492
+ elastic_request = stub_elastic("http://localhost:9201/_bulk")
493
+ driver.emit(sample_record)
494
+ driver.run
495
+ assert_requested(elastic_request)
496
+ end
497
+
498
+ def test_writes_to_multi_hosts
499
+ hosts = [['192.168.33.50', 9201], ['192.168.33.51', 9201], ['192.168.33.52', 9201]]
500
+ hosts_string = hosts.map {|x| "#{x[0]}:#{x[1]}"}.compact.join(',')
501
+
502
+ driver.configure("hosts #{hosts_string}")
503
+
504
+ hosts.each do |host_info|
505
+ host, port = host_info
506
+ stub_elastic_ping("http://#{host}:#{port}")
507
+ stub_elastic_with_store_index_command_counts("http://#{host}:#{port}/_bulk")
508
+ end
509
+
510
+ 1000.times do
511
+ driver.emit(sample_record.merge('age'=>rand(100)))
512
+ end
513
+
514
+ driver.run
515
+
516
+ # @note: we cannot make multi chunks with options (flush_interval, buffer_chunk_limit)
517
+ # it's Fluentd test driver's constraint
518
+ # so @index_command_counts.size is always 1
519
+
520
+ assert(@index_command_counts.size > 0, "not working with hosts options")
521
+
522
+ total = 0
523
+ @index_command_counts.each do |url, count|
524
+ total += count
525
+ end
526
+ assert_equal(2000, total)
527
+ end
528
+
529
+ def test_nested_record_with_flattening_on
530
+ driver.configure("flatten_hashes true
531
+ flatten_hashes_separator |")
532
+
533
+ original_hash = {"foo" => {"bar" => "baz"}, "people" => [
534
+ {"age" => "25", "height" => "1ft"},
535
+ {"age" => "30", "height" => "2ft"}
536
+ ]}
537
+
538
+ expected_output = {"foo|bar"=>"baz", "people" => [
539
+ {"age" => "25", "height" => "1ft"},
540
+ {"age" => "30", "height" => "2ft"}
541
+ ]}
542
+
543
+ stub_elastic_ping
544
+ stub_elastic
545
+ driver.emit(original_hash)
546
+ driver.run
547
+ assert_equal expected_output, index_cmds[1]
548
+ end
549
+
550
+ def test_nested_record_with_flattening_off
551
+ # flattening off by default
552
+
553
+ original_hash = {"foo" => {"bar" => "baz"}}
554
+ expected_output = {"foo" => {"bar" => "baz"}}
555
+
556
+ stub_elastic_ping
557
+ stub_elastic
558
+ driver.emit(original_hash)
559
+ driver.run
560
+ assert_equal expected_output, index_cmds[1]
561
+ end
562
+
563
+ def test_makes_bulk_request
564
+ stub_elastic_ping
565
+ stub_elastic
566
+ driver.emit(sample_record)
567
+ driver.emit(sample_record.merge('age' => 27))
568
+ driver.run
569
+ assert_equal(4, index_cmds.count)
570
+ end
571
+
572
+ def test_all_records_are_preserved_in_bulk
573
+ stub_elastic_ping
574
+ stub_elastic
575
+ driver.emit(sample_record)
576
+ driver.emit(sample_record.merge('age' => 27))
577
+ driver.run
578
+ assert_equal(26, index_cmds[1]['age'])
579
+ assert_equal(27, index_cmds[3]['age'])
580
+ end
581
+
582
+ def test_writes_to_logstash_index
583
+ driver.configure("logstash_format true\n")
584
+ #
585
+ # This is 1 second past midnight in BST, so the UTC index should be the day before
586
+ dt = DateTime.new(2015, 6, 1, 0, 0, 1, "+01:00")
587
+ logstash_index = "logstash-2015.05.31"
588
+ stub_elastic_ping
589
+ stub_elastic
590
+ driver.emit(sample_record, dt.to_time.to_i)
591
+ driver.run
592
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
593
+ end
594
+
595
+ def test_writes_to_logstash_non_utc_index
596
+ driver.configure("logstash_format true
597
+ utc_index false")
598
+ # When using `utc_index false` the index time will be the local day of
599
+ # ingestion time
600
+ time = Date.today.to_time
601
+ index = "logstash-#{time.strftime("%Y.%m.%d")}"
602
+ stub_elastic_ping
603
+ stub_elastic
604
+ driver.emit(sample_record, time.to_i)
605
+ driver.run
606
+ assert_equal(index, index_cmds.first['index']['_index'])
607
+ end
608
+
609
+ def test_writes_to_logstash_index_with_specified_prefix
610
+ driver.configure("logstash_format true
611
+ logstash_prefix myprefix")
612
+ time = Time.parse Date.today.to_s
613
+ logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m.%d")}"
614
+ stub_elastic_ping
615
+ stub_elastic
616
+ driver.emit(sample_record, time.to_i)
617
+ driver.run
618
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
619
+ end
620
+
621
+ def test_writes_to_logstash_index_with_specified_prefix_uppercase
622
+ driver.configure("logstash_format true
623
+ logstash_prefix MyPrefix")
624
+ time = Time.parse Date.today.to_s
625
+ logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m.%d")}"
626
+ stub_elastic_ping
627
+ stub_elastic
628
+ driver.emit(sample_record, time.to_i)
629
+ driver.run
630
+ # Allthough logstash_prefix has upper-case characters,
631
+ # it should be set as lower-case when sent to elasticsearch.
632
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
633
+ end
634
+
635
+ def test_writes_to_logstash_index_with_specified_dateformat
636
+ driver.configure("logstash_format true
637
+ logstash_dateformat %Y.%m")
638
+ time = Time.parse Date.today.to_s
639
+ logstash_index = "logstash-#{time.getutc.strftime("%Y.%m")}"
640
+ stub_elastic_ping
641
+ stub_elastic
642
+ driver.emit(sample_record, time.to_i)
643
+ driver.run
644
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
645
+ end
646
+
647
+ def test_writes_to_logstash_index_with_specified_prefix_and_dateformat
648
+ driver.configure("logstash_format true
649
+ logstash_prefix myprefix
650
+ logstash_dateformat %Y.%m")
651
+ time = Time.parse Date.today.to_s
652
+ logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m")}"
653
+ stub_elastic_ping
654
+ stub_elastic
655
+ driver.emit(sample_record, time.to_i)
656
+ driver.run
657
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
658
+ end
659
+
660
+ def test_doesnt_add_logstash_timestamp_by_default
661
+ stub_elastic_ping
662
+ stub_elastic
663
+ driver.emit(sample_record)
664
+ driver.run
665
+ assert_nil(index_cmds[1]['@timestamp'])
666
+ end
667
+
668
+ def test_adds_logstash_timestamp_when_configured
669
+ driver.configure("logstash_format true\n")
670
+ stub_elastic_ping
671
+ stub_elastic
672
+ ts = DateTime.now.to_s
673
+ driver.emit(sample_record)
674
+ driver.run
675
+ assert(index_cmds[1].has_key? '@timestamp')
676
+ assert_equal(index_cmds[1]['@timestamp'], ts)
677
+ end
678
+
679
+ def test_uses_custom_timestamp_when_included_in_record
680
+ driver.configure("logstash_format true\n")
681
+ stub_elastic_ping
682
+ stub_elastic
683
+ ts = DateTime.new(2001,2,3).to_s
684
+ driver.emit(sample_record.merge!('@timestamp' => ts))
685
+ driver.run
686
+ assert(index_cmds[1].has_key? '@timestamp')
687
+ assert_equal(index_cmds[1]['@timestamp'], ts)
688
+ end
689
+
690
+ def test_uses_custom_time_key
691
+ driver.configure("logstash_format true
692
+ time_key vtm\n")
693
+ stub_elastic_ping
694
+ stub_elastic
695
+ ts = DateTime.new(2001,2,3).to_s
696
+ driver.emit(sample_record.merge!('vtm' => ts))
697
+ driver.run
698
+ assert(index_cmds[1].has_key? '@timestamp')
699
+ assert_equal(index_cmds[1]['@timestamp'], ts)
700
+ end
701
+
702
+ def test_uses_custom_time_key_exclude_timekey
703
+ driver.configure("logstash_format true
704
+ time_key vtm
705
+ time_key_exclude_timestamp true\n")
706
+ stub_elastic_ping
707
+ stub_elastic
708
+ ts = DateTime.new(2001,2,3).to_s
709
+ driver.emit(sample_record.merge!('vtm' => ts))
710
+ driver.run
711
+ assert(!index_cmds[1].key?('@timestamp'), '@timestamp should be messing')
712
+ end
713
+
714
+ def test_uses_custom_time_key_format
715
+ driver.configure("logstash_format true
716
+ time_key_format %Y-%m-%dT%H:%M:%S.%N%z\n")
717
+ stub_elastic_ping
718
+ stub_elastic
719
+ ts = "2001-02-03T13:14:01.673+02:00"
720
+ driver.emit(sample_record.merge!('@timestamp' => ts))
721
+ driver.run
722
+ assert_equal("logstash-2001.02.03", index_cmds[0]['index']['_index'])
723
+ assert(index_cmds[1].has_key? '@timestamp')
724
+ assert_equal(index_cmds[1]['@timestamp'], ts)
725
+ end
726
+
727
+ data(:default => nil,
728
+ :custom_tag => 'es_plugin.output.time.error')
729
+ def test_uses_custom_time_key_format_logs_an_error(tag_for_error)
730
+ tag_config = tag_for_error ? "time_parse_error_tag #{tag_for_error}" : ''
731
+ tag_for_error = 'Fluent::ElasticsearchOutput::TimeParser.error' if tag_for_error.nil?
732
+ driver.configure("logstash_format true
733
+ time_key_format %Y-%m-%dT%H:%M:%S.%N%z\n#{tag_config}\n")
734
+ stub_elastic_ping
735
+ stub_elastic
736
+
737
+ ts = "2001/02/03 13:14:01,673+02:00"
738
+ index = "logstash-#{Date.today.strftime("%Y.%m.%d")}"
739
+
740
+ driver.emit(sample_record.merge!('@timestamp' => ts))
741
+ driver.run
742
+
743
+ log = driver.instance.router.emit_error_handler.log
744
+ errors = log.out.logs.grep /tag="#{tag_for_error}"/
745
+ assert_equal(1, errors.length, "Error was logged for timestamp parse failure")
746
+
747
+ assert_equal(index, index_cmds[0]['index']['_index'])
748
+ assert(index_cmds[1].has_key? '@timestamp')
749
+ assert_equal(index_cmds[1]['@timestamp'], ts)
750
+ end
751
+
752
+
753
+ def test_uses_custom_time_key_format_obscure_format
754
+ driver.configure("logstash_format true
755
+ time_key_format %a %b %d %H:%M:%S %Z %Y\n")
756
+ stub_elastic_ping
757
+ stub_elastic
758
+ ts = "Thu Nov 29 14:33:20 GMT 2001"
759
+ driver.emit(sample_record.merge!('@timestamp' => ts))
760
+ driver.run
761
+ assert_equal("logstash-2001.11.29", index_cmds[0]['index']['_index'])
762
+ assert(index_cmds[1].has_key? '@timestamp')
763
+ assert_equal(index_cmds[1]['@timestamp'], ts)
764
+ end
765
+
766
+ def test_doesnt_add_tag_key_by_default
767
+ stub_elastic_ping
768
+ stub_elastic
769
+ driver.emit(sample_record)
770
+ driver.run
771
+ assert_nil(index_cmds[1]['tag'])
772
+ end
773
+
774
+ def test_adds_tag_key_when_configured
775
+ driver('mytag').configure("include_tag_key true\n")
776
+ stub_elastic_ping
777
+ stub_elastic
778
+ driver.emit(sample_record)
779
+ driver.run
780
+ assert(index_cmds[1].has_key?('tag'))
781
+ assert_equal(index_cmds[1]['tag'], 'mytag')
782
+ end
783
+
784
+ def test_adds_id_key_when_configured
785
+ driver.configure("id_key request_id\n")
786
+ stub_elastic_ping
787
+ stub_elastic
788
+ driver.emit(sample_record)
789
+ driver.run
790
+ assert_equal(index_cmds[0]['index']['_id'], '42')
791
+ end
792
+
793
+ def test_doesnt_add_id_key_if_missing_when_configured
794
+ driver.configure("id_key another_request_id\n")
795
+ stub_elastic_ping
796
+ stub_elastic
797
+ driver.emit(sample_record)
798
+ driver.run
799
+ assert(!index_cmds[0]['index'].has_key?('_id'))
800
+ end
801
+
802
+ def test_adds_id_key_when_not_configured
803
+ stub_elastic_ping
804
+ stub_elastic
805
+ driver.emit(sample_record)
806
+ driver.run
807
+ assert(!index_cmds[0]['index'].has_key?('_id'))
808
+ end
809
+
810
+ def test_adds_parent_key_when_configured
811
+ driver.configure("parent_key parent_id\n")
812
+ stub_elastic_ping
813
+ stub_elastic
814
+ driver.emit(sample_record)
815
+ driver.run
816
+ assert_equal(index_cmds[0]['index']['_parent'], 'parent')
817
+ end
818
+
819
+ def test_doesnt_add_parent_key_if_missing_when_configured
820
+ driver.configure("parent_key another_parent_id\n")
821
+ stub_elastic_ping
822
+ stub_elastic
823
+ driver.emit(sample_record)
824
+ driver.run
825
+ assert(!index_cmds[0]['index'].has_key?('_parent'))
826
+ end
827
+
828
+ def test_adds_parent_key_when_not_configured
829
+ stub_elastic_ping
830
+ stub_elastic
831
+ driver.emit(sample_record)
832
+ driver.run
833
+ assert(!index_cmds[0]['index'].has_key?('_parent'))
834
+ end
835
+
836
+ def test_adds_routing_key_when_configured
837
+ driver.configure("routing_key routing_id\n")
838
+ stub_elastic_ping
839
+ stub_elastic
840
+ driver.emit(sample_record)
841
+ driver.run
842
+ assert_equal(index_cmds[0]['index']['_routing'], 'routing')
843
+ end
844
+
845
+ def test_doesnt_add_routing_key_if_missing_when_configured
846
+ driver.configure("routing_key another_routing_id\n")
847
+ stub_elastic_ping
848
+ stub_elastic
849
+ driver.emit(sample_record)
850
+ driver.run
851
+ assert(!index_cmds[0]['index'].has_key?('_routing'))
852
+ end
853
+
854
+ def test_adds_routing_key_when_not_configured
855
+ stub_elastic_ping
856
+ stub_elastic
857
+ driver.emit(sample_record)
858
+ driver.run
859
+ assert(!index_cmds[0]['index'].has_key?('_routing'))
860
+ end
861
+
862
+ def test_remove_one_key
863
+ driver.configure("remove_keys key1\n")
864
+ stub_elastic_ping
865
+ stub_elastic
866
+ driver.emit(sample_record.merge('key1' => 'v1', 'key2' => 'v2'))
867
+ driver.run
868
+ assert(!index_cmds[1].has_key?('key1'))
869
+ assert(index_cmds[1].has_key?('key2'))
870
+ end
871
+
872
+ def test_remove_multi_keys
873
+ driver.configure("remove_keys key1, key2\n")
874
+ stub_elastic_ping
875
+ stub_elastic
876
+ driver.emit(sample_record.merge('key1' => 'v1', 'key2' => 'v2'))
877
+ driver.run
878
+ assert(!index_cmds[1].has_key?('key1'))
879
+ assert(!index_cmds[1].has_key?('key2'))
880
+ end
881
+
882
+ def test_request_error
883
+ stub_elastic_ping
884
+ stub_elastic_unavailable
885
+ driver.emit(sample_record)
886
+ assert_raise(Elasticsearch::Transport::Transport::Errors::ServiceUnavailable) {
887
+ driver.run
888
+ }
889
+ end
890
+
891
+ def test_garbage_record_error
892
+ stub_elastic_ping
893
+ stub_elastic
894
+ driver.emit("some garbage string")
895
+ driver.run
896
+ end
897
+
898
+ def test_connection_failed_retry
899
+ connection_resets = 0
900
+
901
+ stub_elastic_ping(url="http://localhost:9200").with do |req|
902
+ connection_resets += 1
903
+ end
904
+
905
+ stub_request(:post, "http://localhost:9200/_bulk").with do |req|
906
+ raise Faraday::ConnectionFailed, "Test message"
907
+ end
908
+
909
+ driver.emit(sample_record)
910
+
911
+ assert_raise(Fluent::ElasticsearchOutput::ConnectionFailure) {
912
+ driver.run
913
+ }
914
+ assert_equal(connection_resets, 3)
915
+ end
916
+
917
+ def test_reconnect_on_error_enabled
918
+ connection_resets = 0
919
+
920
+ stub_elastic_ping(url="http://localhost:9200").with do |req|
921
+ connection_resets += 1
922
+ end
923
+
924
+ stub_request(:post, "http://localhost:9200/_bulk").with do |req|
925
+ raise ZeroDivisionError, "any not host_unreachable_exceptions exception"
926
+ end
927
+
928
+ driver.configure("reconnect_on_error true\n")
929
+ driver.emit(sample_record)
930
+
931
+ assert_raise(ZeroDivisionError) {
932
+ driver.run
933
+ }
934
+
935
+ assert_raise(ZeroDivisionError) {
936
+ driver.run
937
+ }
938
+ assert_equal(connection_resets, 2)
939
+ end
940
+
941
+ def test_reconnect_on_error_disabled
942
+ connection_resets = 0
943
+
944
+ stub_elastic_ping(url="http://localhost:9200").with do |req|
945
+ connection_resets += 1
946
+ end
947
+
948
+ stub_request(:post, "http://localhost:9200/_bulk").with do |req|
949
+ raise ZeroDivisionError, "any not host_unreachable_exceptions exception"
950
+ end
951
+
952
+ driver.configure("reconnect_on_error false\n")
953
+ driver.emit(sample_record)
954
+
955
+ assert_raise(ZeroDivisionError) {
956
+ driver.run
957
+ }
958
+
959
+ assert_raise(ZeroDivisionError) {
960
+ driver.run
961
+ }
962
+ assert_equal(connection_resets, 1)
963
+ end
964
+
965
+ def test_update_should_not_write_if_theres_no_id
966
+ driver.configure("write_operation update\n")
967
+ stub_elastic_ping
968
+ stub_elastic
969
+ driver.emit(sample_record)
970
+ driver.run
971
+ assert_nil(index_cmds)
972
+ end
973
+
974
+ def test_upsert_should_not_write_if_theres_no_id
975
+ driver.configure("write_operation upsert\n")
976
+ stub_elastic_ping
977
+ stub_elastic
978
+ driver.emit(sample_record)
979
+ driver.run
980
+ assert_nil(index_cmds)
981
+ end
982
+
983
+ def test_create_should_not_write_if_theres_no_id
984
+ driver.configure("write_operation create\n")
985
+ stub_elastic_ping
986
+ stub_elastic
987
+ driver.emit(sample_record)
988
+ driver.run
989
+ assert_nil(index_cmds)
990
+ end
991
+
992
+ def test_update_should_write_update_op_and_doc_as_upsert_is_false
993
+ driver.configure("write_operation update
994
+ id_key request_id")
995
+ stub_elastic_ping
996
+ stub_elastic
997
+ driver.emit(sample_record)
998
+ driver.run
999
+ assert(index_cmds[0].has_key?("update"))
1000
+ assert(!index_cmds[1]["doc_as_upsert"])
1001
+ assert(!index_cmds[1]["upsert"])
1002
+ end
1003
+
1004
+ def test_update_should_remove_keys_from_doc_when_keys_are_skipped
1005
+ driver.configure("write_operation update
1006
+ id_key request_id
1007
+ remove_keys_on_update parent_id")
1008
+ stub_elastic_ping
1009
+ stub_elastic
1010
+ driver.emit(sample_record)
1011
+ driver.run
1012
+ assert(index_cmds[1]["doc"])
1013
+ assert(!index_cmds[1]["doc"]["parent_id"])
1014
+ end
1015
+
1016
+ def test_upsert_should_write_update_op_and_doc_as_upsert_is_true
1017
+ driver.configure("write_operation upsert
1018
+ id_key request_id")
1019
+ stub_elastic_ping
1020
+ stub_elastic
1021
+ driver.emit(sample_record)
1022
+ driver.run
1023
+ assert(index_cmds[0].has_key?("update"))
1024
+ assert(index_cmds[1]["doc_as_upsert"])
1025
+ assert(!index_cmds[1]["upsert"])
1026
+ end
1027
+
1028
+ def test_upsert_should_write_update_op_upsert_and_doc_when_keys_are_skipped
1029
+ driver.configure("write_operation upsert
1030
+ id_key request_id
1031
+ remove_keys_on_update parent_id")
1032
+ stub_elastic_ping
1033
+ stub_elastic
1034
+ driver.emit(sample_record)
1035
+ driver.run
1036
+ assert(index_cmds[0].has_key?("update"))
1037
+ assert(!index_cmds[1]["doc_as_upsert"])
1038
+ assert(index_cmds[1]["upsert"])
1039
+ assert(index_cmds[1]["doc"])
1040
+ end
1041
+
1042
+ def test_upsert_should_remove_keys_from_doc_when_keys_are_skipped
1043
+ driver.configure("write_operation upsert
1044
+ id_key request_id
1045
+ remove_keys_on_update parent_id")
1046
+ stub_elastic_ping
1047
+ stub_elastic
1048
+ driver.emit(sample_record)
1049
+ driver.run
1050
+ assert(index_cmds[1]["upsert"] != index_cmds[1]["doc"])
1051
+ assert(!index_cmds[1]["doc"]["parent_id"])
1052
+ assert(index_cmds[1]["upsert"]["parent_id"])
1053
+ end
1054
+
1055
+ def test_upsert_should_remove_multiple_keys_when_keys_are_skipped
1056
+ driver.configure("write_operation upsert
1057
+ id_key id
1058
+ remove_keys_on_update foo,baz")
1059
+ stub_elastic_ping
1060
+ stub_elastic
1061
+ driver.emit("id" => 1, "foo" => "bar", "baz" => "quix", "zip" => "zam")
1062
+ driver.run
1063
+ assert(
1064
+ index_cmds[1]["doc"] == {
1065
+ "id" => 1,
1066
+ "zip" => "zam",
1067
+ }
1068
+ )
1069
+ assert(
1070
+ index_cmds[1]["upsert"] == {
1071
+ "id" => 1,
1072
+ "foo" => "bar",
1073
+ "baz" => "quix",
1074
+ "zip" => "zam",
1075
+ }
1076
+ )
1077
+ end
1078
+
1079
+ def test_upsert_should_remove_keys_from_when_the_keys_are_in_the_record
1080
+ driver.configure("write_operation upsert
1081
+ id_key id
1082
+ remove_keys_on_update_key keys_to_skip")
1083
+ stub_elastic_ping
1084
+ stub_elastic
1085
+ driver.emit("id" => 1, "foo" => "bar", "baz" => "quix", "keys_to_skip" => ["baz"])
1086
+ driver.run
1087
+ assert(
1088
+ index_cmds[1]["doc"] == {
1089
+ "id" => 1,
1090
+ "foo" => "bar",
1091
+ }
1092
+ )
1093
+ assert(
1094
+ index_cmds[1]["upsert"] == {
1095
+ "id" => 1,
1096
+ "foo" => "bar",
1097
+ "baz" => "quix",
1098
+ }
1099
+ )
1100
+ end
1101
+
1102
+ def test_upsert_should_remove_keys_from_key_on_record_has_higher_presedence_than_config
1103
+ driver.configure("write_operation upsert
1104
+ id_key id
1105
+ remove_keys_on_update foo,bar
1106
+ remove_keys_on_update_key keys_to_skip")
1107
+ stub_elastic_ping
1108
+ stub_elastic
1109
+ driver.emit("id" => 1, "foo" => "bar", "baz" => "quix", "keys_to_skip" => ["baz"])
1110
+ driver.run
1111
+ assert(
1112
+ index_cmds[1]["doc"] == {
1113
+ "id" => 1,
1114
+ # we only expect baz to be stripped here, if the config was more important
1115
+ # foo would be stripped too.
1116
+ "foo" => "bar",
1117
+ }
1118
+ )
1119
+ assert(
1120
+ index_cmds[1]["upsert"] == {
1121
+ "id" => 1,
1122
+ "foo" => "bar",
1123
+ "baz" => "quix",
1124
+ }
1125
+ )
1126
+ end
1127
+
1128
+ def test_create_should_write_create_op
1129
+ driver.configure("write_operation create
1130
+ id_key request_id")
1131
+ stub_elastic_ping
1132
+ stub_elastic
1133
+ driver.emit(sample_record)
1134
+ driver.run
1135
+ assert(index_cmds[0].has_key?("create"))
1136
+ end
1137
+
1138
+ end