fluent-plugin-elasticsearch 4.0.4 → 4.0.9

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.
@@ -55,6 +55,7 @@ module Fluent::Plugin
55
55
  attr_reader :alias_indexes
56
56
  attr_reader :template_names
57
57
  attr_reader :ssl_version_options
58
+ attr_reader :compressable_connection
58
59
 
59
60
  helpers :event_emitter, :compat_parameters, :record_accessor, :timer
60
61
 
@@ -125,6 +126,7 @@ EOC
125
126
  config_param :templates, :hash, :default => nil
126
127
  config_param :max_retry_putting_template, :integer, :default => 10
127
128
  config_param :fail_on_putting_template_retry_exceed, :bool, :default => true
129
+ config_param :fail_on_detecting_es_version_retry_exceed, :bool, :default => true
128
130
  config_param :max_retry_get_es_version, :integer, :default => 15
129
131
  config_param :include_tag_key, :bool, :default => false
130
132
  config_param :tag_key, :string, :default => 'tag'
@@ -142,6 +144,7 @@ see: https://github.com/elastic/elasticsearch-ruby/pull/514
142
144
  EOC
143
145
  config_param :include_index_in_url, :bool, :default => false
144
146
  config_param :http_backend, :enum, list: [:excon, :typhoeus], :default => :excon
147
+ config_param :http_backend_excon_nonblock, :bool, :default => true
145
148
  config_param :validate_client_version, :bool, :default => false
146
149
  config_param :prefer_oj_serializer, :bool, :default => false
147
150
  config_param :unrecoverable_error_types, :array, :default => ["out_of_memory_error", "es_rejected_execution_exception"]
@@ -157,6 +160,7 @@ EOC
157
160
  config_param :enable_ilm, :bool, :default => false
158
161
  config_param :ilm_policy_id, :string, :default => DEFAULT_POLICY_ID
159
162
  config_param :ilm_policy, :hash, :default => {}
163
+ config_param :ilm_policies, :hash, :default => {}
160
164
  config_param :ilm_policy_overwrite, :bool, :default => false
161
165
  config_param :truncate_caches_interval, :time, :default => nil
162
166
 
@@ -217,6 +221,11 @@ EOC
217
221
  log.info "host placeholder and template installation makes your Elasticsearch cluster a bit slow down(beta)."
218
222
  end
219
223
 
224
+ raise Fluent::ConfigError, "You can't specify ilm_policy and ilm_policies at the same time" unless @ilm_policy.empty? or @ilm_policies.empty?
225
+
226
+ unless @ilm_policy.empty?
227
+ @ilm_policies = { @ilm_policy_id => @ilm_policy }
228
+ end
220
229
  @alias_indexes = []
221
230
  @template_names = []
222
231
  if !dry_run?
@@ -232,7 +241,7 @@ EOC
232
241
  alias_method :template_installation, :template_installation_actual
233
242
  end
234
243
  else
235
- template_installation_actual(@deflector_alias ? @deflector_alias : @index_name, @template_name, @customize_template, @application_name, @index_name)
244
+ template_installation_actual(@deflector_alias ? @deflector_alias : @index_name, @template_name, @customize_template, @application_name, @index_name, @ilm_policy_id)
236
245
  end
237
246
  verify_ilm_working if @enable_ilm
238
247
  elsif @templates
@@ -290,14 +299,11 @@ EOC
290
299
  raise Fluent::ConfigError, "Could not load sniffer class #{@sniffer_class_name}: #{ex}"
291
300
  end
292
301
 
293
- @last_seen_major_version =
294
- if @verify_es_version_at_startup && !dry_run?
295
- retry_operate(@max_retry_get_es_version) do
296
- detect_es_major_version
297
- end
298
- else
299
- @default_elasticsearch_version
300
- end
302
+ @last_seen_major_version = if major_version = handle_last_seen_es_major_version
303
+ major_version
304
+ else
305
+ @default_elasticsearch_version
306
+ end
301
307
  if @last_seen_major_version == 6 && @type_name != DEFAULT_TYPE_NAME_ES_7x
302
308
  log.info "Detected ES 6.x: ES 7.x will only accept `_doc` in type_name."
303
309
  end
@@ -329,6 +335,13 @@ EOC
329
335
  end
330
336
  end
331
337
 
338
+ if @ssl_version && @scheme == :https
339
+ if !@http_backend_excon_nonblock
340
+ log.warn "TLS handshake will be stucked with block connection.
341
+ Consider to set `http_backend_excon_nonblock` as true"
342
+ end
343
+ end
344
+
332
345
  # Consider missing the prefix of "$." in nested key specifiers.
333
346
  @id_key = convert_compat_id_key(@id_key) if @id_key
334
347
  @parent_key = convert_compat_id_key(@parent_key) if @parent_key
@@ -337,6 +350,7 @@ EOC
337
350
  @routing_key_name = configure_routing_key_name
338
351
  @meta_config_map = create_meta_config_map
339
352
  @current_config = nil
353
+ @compressable_connection = false
340
354
 
341
355
  @ignore_exception_classes = @ignore_exceptions.map do |exception|
342
356
  unless Object.const_defined?(exception)
@@ -358,9 +372,7 @@ EOC
358
372
  end
359
373
  end
360
374
 
361
- version_arr = ::Elasticsearch::Transport::VERSION.split('.')
362
-
363
- if (version_arr[0].to_i < 7) || (version_arr[0].to_i == 7 && version_arr[1].to_i < 2)
375
+ if Gem::Version.create(::Elasticsearch::Transport::VERSION) < Gem::Version.create("7.2.0")
364
376
  if compression
365
377
  raise Fluent::ConfigError, <<-EOC
366
378
  Cannot use compression with elasticsearch-transport plugin version < 7.2.0
@@ -413,7 +425,7 @@ EOC
413
425
  def backend_options
414
426
  case @http_backend
415
427
  when :excon
416
- { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass }
428
+ { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass, nonblock: @http_backend_excon_nonblock }
417
429
  when :typhoeus
418
430
  require 'typhoeus'
419
431
  { sslkey: @client_key, sslcert: @client_cert, keypasswd: @client_key_pass }
@@ -423,6 +435,16 @@ EOC
423
435
  raise Fluent::ConfigError, "You must install #{@http_backend} gem. Exception: #{ex}"
424
436
  end
425
437
 
438
+ def handle_last_seen_es_major_version
439
+ if @verify_es_version_at_startup && !dry_run?
440
+ retry_operate(@max_retry_get_es_version, @fail_on_detecting_es_version_retry_exceed) do
441
+ detect_es_major_version
442
+ end
443
+ else
444
+ nil
445
+ end
446
+ end
447
+
426
448
  def detect_es_major_version
427
449
  @_es_info ||= client.info
428
450
  @_es_info["version"]["number"].to_i
@@ -497,13 +519,15 @@ EOC
497
519
  return Time.at(event_time).to_datetime
498
520
  end
499
521
 
500
- def client(host = nil)
522
+ def client(host = nil, compress_connection = false)
501
523
  # check here to see if we already have a client connection for the given host
502
524
  connection_options = get_connection_options(host)
503
525
 
504
526
  @_es = nil unless is_existing_connection(connection_options[:hosts])
527
+ @_es = nil unless @compressable_connection == compress_connection
505
528
 
506
529
  @_es ||= begin
530
+ @compressable_connection = compress_connection
507
531
  @current_config = connection_options[:hosts].clone
508
532
  adapter_conf = lambda {|f| f.adapter @http_backend, @backend_options }
509
533
  local_reload_connections = @reload_connections
@@ -511,7 +535,7 @@ EOC
511
535
  local_reload_connections = @reload_after
512
536
  end
513
537
 
514
- gzip_headers = if compression
538
+ gzip_headers = if compress_connection
515
539
  {'Content-Encoding' => 'gzip'}
516
540
  else
517
541
  {}
@@ -537,7 +561,7 @@ EOC
537
561
  },
538
562
  sniffer_class: @sniffer_class,
539
563
  serializer_class: @serializer_class,
540
- compression: compression,
564
+ compression: compress_connection,
541
565
  }), &adapter_conf)
542
566
  Elasticsearch::Client.new transport: transport
543
567
  end
@@ -669,6 +693,7 @@ EOC
669
693
 
670
694
  def expand_placeholders(chunk)
671
695
  logstash_prefix = extract_placeholders(@logstash_prefix, chunk)
696
+ logstash_dateformat = extract_placeholders(@logstash_dateformat, chunk)
672
697
  index_name = extract_placeholders(@index_name, chunk)
673
698
  if @type_name
674
699
  type_name = extract_placeholders(@type_name, chunk)
@@ -700,7 +725,12 @@ EOC
700
725
  else
701
726
  pipeline = nil
702
727
  end
703
- return logstash_prefix, index_name, type_name, template_name, customize_template, deflector_alias, application_name, pipeline
728
+ if @ilm_policy_id
729
+ ilm_policy_id = extract_placeholders(@ilm_policy_id, chunk)
730
+ else
731
+ ilm_policy_id = nil
732
+ end
733
+ return logstash_prefix, logstash_dateformat, index_name, type_name, template_name, customize_template, deflector_alias, application_name, pipeline, ilm_policy_id
704
734
  end
705
735
 
706
736
  def multi_workers_ready?
@@ -774,7 +804,7 @@ EOC
774
804
  end
775
805
 
776
806
  def process_message(tag, meta, header, time, record, extracted_values)
777
- logstash_prefix, index_name, type_name, _template_name, _customize_template, _deflector_alias, _application_name, pipeline = extracted_values
807
+ logstash_prefix, logstash_dateformat, index_name, type_name, _template_name, _customize_template, _deflector_alias, _application_name, pipeline, _ilm_policy_id = extracted_values
778
808
 
779
809
  if @flatten_hashes
780
810
  record = flatten_record(record)
@@ -800,7 +830,7 @@ EOC
800
830
  target_index = target_index_parent.delete(target_index_child_key)
801
831
  elsif @logstash_format
802
832
  dt = dt.new_offset(0) if @utc_index
803
- target_index = "#{logstash_prefix}#{@logstash_prefix_separator}#{dt.strftime(@logstash_dateformat)}"
833
+ target_index = "#{logstash_prefix}#{@logstash_prefix_separator}#{dt.strftime(logstash_dateformat)}"
804
834
  else
805
835
  target_index = index_name
806
836
  end
@@ -880,17 +910,19 @@ EOC
880
910
  placeholder?(:template_name, @template_name.to_s) ||
881
911
  @customize_template&.values&.any? { |value| placeholder?(:customize_template, value.to_s) } ||
882
912
  placeholder?(:logstash_prefix, @logstash_prefix.to_s) ||
913
+ placeholder?(:logstash_dateformat, @logstash_dateformat.to_s) ||
883
914
  placeholder?(:deflector_alias, @deflector_alias.to_s) ||
884
- placeholder?(:application_name, @application_name.to_s)
915
+ placeholder?(:application_name, @application_name.to_s) ||
916
+ placeholder?(:ilm_policy_id, @ilm_policy_id.to_s)
885
917
  log.debug("Need substitution: #{need_substitution}")
886
918
  need_substitution
887
919
  end
888
920
 
889
- def template_installation(deflector_alias, template_name, customize_template, application_name, target_index, host)
921
+ def template_installation(deflector_alias, template_name, customize_template, application_name, ilm_policy_id, target_index, host)
890
922
  # for safety.
891
923
  end
892
924
 
893
- def template_installation_actual(deflector_alias, template_name, customize_template, application_name, target_index, host=nil)
925
+ def template_installation_actual(deflector_alias, template_name, customize_template, application_name, target_index, ilm_policy_id, host=nil)
894
926
  if template_name && @template_file
895
927
  if @alias_indexes.include? deflector_alias
896
928
  log.debug("Index alias #{deflector_alias} already exists (cached)")
@@ -899,11 +931,12 @@ EOC
899
931
  else
900
932
  retry_operate(@max_retry_putting_template, @fail_on_putting_template_retry_exceed) do
901
933
  if customize_template
902
- template_custom_install(template_name, @template_file, @template_overwrite, customize_template, @enable_ilm, deflector_alias, @ilm_policy_id, host)
934
+ template_custom_install(template_name, @template_file, @template_overwrite, customize_template, @enable_ilm, deflector_alias, ilm_policy_id, host)
903
935
  else
904
- template_install(template_name, @template_file, @template_overwrite, @enable_ilm, deflector_alias, @ilm_policy_id, host)
936
+ template_install(template_name, @template_file, @template_overwrite, @enable_ilm, deflector_alias, ilm_policy_id, host)
905
937
  end
906
- create_rollover_alias(target_index, @rollover_index, deflector_alias, application_name, @index_date_pattern, @index_separator, @enable_ilm, @ilm_policy_id, @ilm_policy, @ilm_policy_overwrite, host)
938
+ ilm_policy = @ilm_policies[ilm_policy_id] || {}
939
+ create_rollover_alias(target_index, @rollover_index, deflector_alias, application_name, @index_date_pattern, @index_separator, @enable_ilm, ilm_policy_id, ilm_policy, @ilm_policy_overwrite, host)
907
940
  end
908
941
  @alias_indexes << deflector_alias unless deflector_alias.nil?
909
942
  @template_names << template_name unless template_name.nil?
@@ -914,11 +947,11 @@ EOC
914
947
  # send_bulk given a specific bulk request, the original tag,
915
948
  # chunk, and bulk_message_count
916
949
  def send_bulk(data, tag, chunk, bulk_message_count, extracted_values, info)
917
- logstash_prefix, index_name, _type_name, template_name, customize_template, deflector_alias, application_name, _pipeline = extracted_values
950
+ logstash_prefix, _logstash_dateformat, index_name, _type_name, template_name, customize_template, deflector_alias, application_name, _pipeline, ilm_policy_id = extracted_values
918
951
  if deflector_alias
919
- template_installation(deflector_alias, template_name, customize_template, application_name, index_name, info.host)
952
+ template_installation(deflector_alias, template_name, customize_template, application_name, index_name, ilm_policy_id, info.host)
920
953
  else
921
- template_installation(info.ilm_index, template_name, customize_template, application_name, @logstash_format ? logstash_prefix : index_name, info.host)
954
+ template_installation(info.ilm_index, template_name, customize_template, application_name, @logstash_format ? logstash_prefix : index_name, ilm_policy_id, info.host)
922
955
  end
923
956
 
924
957
  begin
@@ -931,7 +964,7 @@ EOC
931
964
  data
932
965
  end
933
966
 
934
- response = client(info.host).bulk body: prepared_data, index: info.index
967
+ response = client(info.host, compression).bulk body: prepared_data, index: info.index
935
968
  log.on_trace { log.trace "bulk response: #{response}" }
936
969
 
937
970
  if response['errors']
@@ -35,16 +35,18 @@ module Fluent::Plugin
35
35
  end
36
36
 
37
37
 
38
- def client(host = nil)
38
+ def client(host = nil, compress_connection = false)
39
39
  # check here to see if we already have a client connection for the given host
40
40
  connection_options = get_connection_options(host)
41
41
 
42
42
  @_es = nil unless is_existing_connection(connection_options[:hosts])
43
+ @_es = nil unless @compressable_connection == compress_connection
43
44
 
44
45
  @_es ||= begin
46
+ @compressable_connection = compress_connection
45
47
  @current_config = connection_options[:hosts].clone
46
48
  adapter_conf = lambda {|f| f.adapter @http_backend, @backend_options }
47
- gzip_headers = if compression
49
+ gzip_headers = if compress_connection
48
50
  {'Content-Encoding' => 'gzip'}
49
51
  else
50
52
  {}
@@ -67,7 +69,7 @@ module Fluent::Plugin
67
69
  password: @password,
68
70
  scheme: @scheme
69
71
  },
70
- compression: compression,
72
+ compression: compress_connection,
71
73
  }), &adapter_conf)
72
74
  Elasticsearch::Client.new transport: transport
73
75
  end
@@ -228,7 +230,7 @@ module Fluent::Plugin
228
230
  else
229
231
  data
230
232
  end
231
- response = client(host).bulk body: prepared_data, index: index
233
+ response = client(host, compression).bulk body: prepared_data, index: index
232
234
  if response['errors']
233
235
  log.error "Could not push log to Elasticsearch: #{response}"
234
236
  end
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require_relative '../helper'
2
2
  require 'fluent/plugin/out_elasticsearch'
3
3
  require 'fluent/plugin/elasticsearch_error_handler'
4
4
  require 'json'
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require_relative '../helper'
2
2
  require 'elasticsearch'
3
3
  require 'fluent/plugin/elasticsearch_index_lifecycle_management'
4
4
 
@@ -62,8 +62,8 @@ class TestElasticsearchTLS < Test::Unit::TestCase
62
62
  d = driver('')
63
63
  ssl_version_options = d.instance.set_tls_minmax_version_config(d.instance.ssl_version, nil, nil)
64
64
  if @use_tls_minmax_version
65
- assert_equal({max_version: OpenSSL::SSL::TLS1_VERSION,
66
- min_version: OpenSSL::SSL::TLS1_VERSION}, ssl_version_options)
65
+ assert_equal({max_version: OpenSSL::SSL::TLS1_3_VERSION,
66
+ min_version: OpenSSL::SSL::TLS1_2_VERSION}, ssl_version_options)
67
67
  else
68
68
  assert_equal({version: Fluent::Plugin::ElasticsearchTLS::DEFAULT_VERSION}, ssl_version_options)
69
69
  end
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require_relative '../helper'
2
2
  require 'date'
3
3
  require 'fluent/test/helpers'
4
4
  require 'json'
@@ -4,6 +4,7 @@ require 'fluent/test/helpers'
4
4
  require 'json'
5
5
  require 'fluent/test/driver/input'
6
6
  require 'flexmock/test_unit'
7
+ require 'fluent/plugin/in_elasticsearch'
7
8
 
8
9
  class ElasticsearchInputTest < Test::Unit::TestCase
9
10
  include FlexMock::TestCase
@@ -16,7 +17,6 @@ class ElasticsearchInputTest < Test::Unit::TestCase
16
17
 
17
18
  def setup
18
19
  Fluent::Test.setup
19
- require 'fluent/plugin/in_elasticsearch'
20
20
  @driver = nil
21
21
  log = Fluent::Engine.log
22
22
  log.out.logs.slice!(0, log.out.logs.length)
@@ -0,0 +1,19 @@
1
+ require_relative '../helper'
2
+ require 'elasticsearch'
3
+
4
+ class OjSerializerTest < Test::Unit::TestCase
5
+ def setup
6
+ begin
7
+ require 'fluent/plugin/oj_serializer'
8
+ rescue LoadError
9
+ omit "OjSerializer testcase needs oj gem."
10
+ end
11
+ @serializer = Fluent::Plugin::Serializer::Oj.new
12
+ end
13
+
14
+ def test_serializer
15
+ data = {"message" => "Hi"}
16
+ assert_equal data.to_json, @serializer.dump(data)
17
+ assert_equal data, @serializer.load(data.to_json)
18
+ end
19
+ end
@@ -1,11 +1,12 @@
1
- require 'helper'
1
+ require_relative '../helper'
2
2
  require 'date'
3
3
  require 'fluent/test/helpers'
4
4
  require 'json'
5
5
  require 'fluent/test/driver/output'
6
6
  require 'flexmock/test_unit'
7
+ require 'fluent/plugin/out_elasticsearch'
7
8
 
8
- class ElasticsearchOutput < Test::Unit::TestCase
9
+ class ElasticsearchOutputTest < Test::Unit::TestCase
9
10
  include FlexMock::TestCase
10
11
  include Fluent::Test::Helpers
11
12
 
@@ -13,7 +14,6 @@ class ElasticsearchOutput < Test::Unit::TestCase
13
14
 
14
15
  def setup
15
16
  Fluent::Test.setup
16
- require 'fluent/plugin/out_elasticsearch'
17
17
  @driver = nil
18
18
  log = Fluent::Engine.log
19
19
  log.out.logs.slice!(0, log.out.logs.length)
@@ -201,6 +201,14 @@ class ElasticsearchOutput < Test::Unit::TestCase
201
201
  assert_compare(exp_matches, operator, matches.length, "Logs do not contain '#{msg}' '#{logs}'")
202
202
  end
203
203
 
204
+ def alias_endpoint
205
+ if Gem::Version.create(::Elasticsearch::VERSION) >= Gem::Version.create("7.5.0-pre")
206
+ "_aliases"
207
+ else
208
+ "_alias"
209
+ end
210
+ end
211
+
204
212
  def test_configure
205
213
  config = %{
206
214
  host logs.google.com
@@ -222,7 +230,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
222
230
  assert_nil instance.ssl_max_version
223
231
  assert_nil instance.ssl_min_version
224
232
  if Fluent::Plugin::ElasticsearchTLS::USE_TLS_MINMAX_VERSION
225
- assert_equal({max_version: OpenSSL::SSL::TLS1_VERSION, min_version: OpenSSL::SSL::TLS1_VERSION},
233
+ assert_equal({max_version: OpenSSL::SSL::TLS1_3_VERSION, min_version: OpenSSL::SSL::TLS1_2_VERSION},
226
234
  instance.ssl_version_options)
227
235
  else
228
236
  assert_equal({version: Fluent::Plugin::ElasticsearchTLS::DEFAULT_VERSION},
@@ -243,9 +251,12 @@ class ElasticsearchOutput < Test::Unit::TestCase
243
251
  assert_equal 20 * 1024 * 1024, Fluent::Plugin::ElasticsearchOutput::TARGET_BULK_BYTES
244
252
  assert_false instance.compression
245
253
  assert_equal :no_compression, instance.compression_level
254
+ assert_true instance.http_backend_excon_nonblock
246
255
  end
247
256
 
248
257
  test 'configure compression' do
258
+ omit "elastisearch-ruby v7.2.0 or later is needed." if Gem::Version.create(::Elasticsearch::Transport::VERSION) < Gem::Version.create("7.2.0")
259
+
249
260
  config = %{
250
261
  compression_level best_compression
251
262
  }
@@ -255,6 +266,8 @@ class ElasticsearchOutput < Test::Unit::TestCase
255
266
  end
256
267
 
257
268
  test 'check compression strategy' do
269
+ omit "elastisearch-ruby v7.2.0 or later is needed." if Gem::Version.create(::Elasticsearch::Transport::VERSION) < Gem::Version.create("7.2.0")
270
+
258
271
  config = %{
259
272
  compression_level best_speed
260
273
  }
@@ -264,21 +277,43 @@ class ElasticsearchOutput < Test::Unit::TestCase
264
277
  end
265
278
 
266
279
  test 'check content-encoding header with compression' do
280
+ omit "elastisearch-ruby v7.2.0 or later is needed." if Gem::Version.create(::Elasticsearch::Transport::VERSION) < Gem::Version.create("7.2.0")
281
+
267
282
  config = %{
268
283
  compression_level best_compression
269
284
  }
270
285
  instance = driver(config).instance
271
286
 
272
- assert_equal "gzip", instance.client.transport.options[:transport_options][:headers]["Content-Encoding"]
287
+ assert_equal nil, instance.client.transport.options[:transport_options][:headers]["Content-Encoding"]
288
+
289
+ stub_request(:post, "http://localhost:9200/_bulk").
290
+ to_return(status: 200, body: "", headers: {})
291
+ driver.run(default_tag: 'test') do
292
+ driver.feed(sample_record)
293
+ end
294
+ compressable = instance.compressable_connection
295
+
296
+ assert_equal "gzip", instance.client(nil, compressable).transport.options[:transport_options][:headers]["Content-Encoding"]
273
297
  end
274
298
 
275
299
  test 'check compression option is passed to transport' do
300
+ omit "elastisearch-ruby v7.2.0 or later is needed." if Gem::Version.create(::Elasticsearch::Transport::VERSION) < Gem::Version.create("7.2.0")
301
+
276
302
  config = %{
277
303
  compression_level best_compression
278
304
  }
279
305
  instance = driver(config).instance
280
306
 
281
- assert_equal true, instance.client.transport.options[:compression]
307
+ assert_equal false, instance.client.transport.options[:compression]
308
+
309
+ stub_request(:post, "http://localhost:9200/_bulk").
310
+ to_return(status: 200, body: "", headers: {})
311
+ driver.run(default_tag: 'test') do
312
+ driver.feed(sample_record)
313
+ end
314
+ compressable = instance.compressable_connection
315
+
316
+ assert_equal true, instance.client(nil, compressable).transport.options[:compression]
282
317
  end
283
318
 
284
319
  test 'configure Content-Type' do
@@ -316,6 +351,20 @@ class ElasticsearchOutput < Test::Unit::TestCase
316
351
  }
317
352
  end
318
353
 
354
+ sub_test_case 'Check TLS handshake stuck warning log' do
355
+ test 'warning TLS log' do
356
+ config = %{
357
+ scheme https
358
+ http_backend_excon_nonblock false
359
+ ssl_version TLSv1_2
360
+ @log_level info
361
+ }
362
+ driver(config)
363
+ logs = driver.logs
364
+ assert_logs_include(logs, /TLS handshake will be stucked with block connection.\n Consider to set `http_backend_excon_nonblock` as true\n/)
365
+ end
366
+ end
367
+
319
368
  sub_test_case 'ILM default config' do
320
369
  setup do
321
370
  begin
@@ -338,7 +387,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
338
387
  to_return(status: 200, body: "", headers: {})
339
388
  stub_request(:head, "http://localhost:9200/_alias/fluentd").
340
389
  to_return(status: 404, body: "", headers: {})
341
- stub_request(:put, "http://localhost:9200/%3Cfluentd-default-%7Bnow%2Fd%7D-000001%3E/_alias/fluentd").
390
+ stub_request(:put, "http://localhost:9200/%3Cfluentd-default-%7Bnow%2Fd%7D-000001%3E/#{alias_endpoint}/fluentd").
342
391
  with(body: "{\"aliases\":{\"fluentd\":{\"is_write_index\":true}}}").
343
392
  to_return(status: 200, body: "", headers: {})
344
393
  stub_request(:put, "http://localhost:9200/%3Cfluentd-default-%7Bnow%2Fd%7D-000001%3E").
@@ -372,7 +421,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
372
421
  to_return(status: 200, body: "", headers: {})
373
422
  stub_request(:head, "http://localhost:9200/_alias/fluentd").
374
423
  to_return(status: 404, body: "", headers: {})
375
- stub_request(:put, "http://localhost:9200/%3Cfluentd-default-%7Bnow%2Fd%7D-000001%3E/_alias/fluentd").
424
+ stub_request(:put, "http://localhost:9200/%3Cfluentd-default-%7Bnow%2Fd%7D-000001%3E/#{alias_endpoint}/fluentd").
376
425
  with(body: "{\"aliases\":{\"fluentd\":{\"is_write_index\":true}}}").
377
426
  to_return(status: 200, body: "", headers: {})
378
427
  stub_request(:put, "http://localhost:9200/%3Cfluentd-default-%7Bnow%2Fd%7D-000001%3E").
@@ -519,6 +568,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
519
568
  "template_name_placeholder" => ["template_name", "logstash-${mykey}"],
520
569
  "customize_template" => ["customize_template", '{"<<TAG>>":"${mykey}"}'],
521
570
  "logstash_prefix_placeholder" => ["logstash_prefix", "fluentd-${mykey}"],
571
+ "logstash_dateformat_placeholder" => ["logstash_dateformat", "${mykey}"],
522
572
  "deflector_alias_placeholder" => ["deflector_alias", "fluentd-${mykey}"],
523
573
  "application_name_placeholder" => ["application_name", "fluentd-${mykey}"],
524
574
  )
@@ -544,6 +594,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
544
594
  "template_name_placeholder" => ["template_name", "logstash-${tag}-%Y%m%d"],
545
595
  "customize_template" => ["customize_template", '{"<<TAG>>":"${es_index}"}'],
546
596
  "logstash_prefix_placeholder" => ["logstash_prefix", "fluentd-${es_index}-%Y%m%d"],
597
+ "logstash_dataformat_placeholder" => ["logstash_dateformat", "${es_index}"],
547
598
  "deflector_alias_placeholder" => ["deflector_alias", "fluentd-%Y%m%d"],
548
599
  "application_name_placeholder" => ["application_name", "fluentd-${tag}-${es_index}-%Y%m%d"],
549
600
  )
@@ -694,6 +745,60 @@ class ElasticsearchOutput < Test::Unit::TestCase
694
745
  end
695
746
  end
696
747
 
748
+ class GetElasticsearchVersionWithFallbackTest < self
749
+ def create_driver(conf='', client_version="\"5.0\"")
750
+ # For request stub to detect compatibility.
751
+ @client_version ||= client_version
752
+ # Ensure original implementation existence.
753
+ Fluent::Plugin::ElasticsearchOutput.module_eval(<<-CODE)
754
+ def detect_es_major_version
755
+ @_es_info ||= client.info
756
+ @_es_info["version"]["number"].to_i
757
+ end
758
+ CODE
759
+ Fluent::Plugin::ElasticsearchOutput.module_eval(<<-CODE)
760
+ def client_library_version
761
+ #{@client_version}
762
+ end
763
+ CODE
764
+ Fluent::Test::Driver::Output.new(Fluent::Plugin::ElasticsearchOutput).configure(conf)
765
+ end
766
+
767
+ data("Elasticsearch 5" => ["5.0", 5],
768
+ "Elasticsearch 6" => ["6.0", 6],
769
+ "Elasticsearch 7" => ["7.0", 7],
770
+ "Elasticsearch 8" => ["8.0", 8])
771
+ def test_retry_get_es_version_without_fail_on_detecting_es_version_retry_exceeded(data)
772
+ client_version, es_major_version = data
773
+ config = %{
774
+ host logs.google.com
775
+ port 778
776
+ scheme https
777
+ path /es/
778
+ user john
779
+ password doe
780
+ verify_es_version_at_startup true
781
+ max_retry_get_es_version 2
782
+ fail_on_detecting_es_version_retry_exceed false
783
+ default_elasticsearch_version #{es_major_version}
784
+ @log_level info
785
+ }
786
+
787
+ connection_resets = 0
788
+ stub_request(:get, "https://logs.google.com:778/es//").
789
+ with(basic_auth: ['john', 'doe']) do |req|
790
+ connection_resets += 1
791
+ raise Faraday::ConnectionFailed, "Test message"
792
+ end
793
+
794
+ d = create_driver(config, client_version)
795
+
796
+ assert_equal es_major_version, d.instance.default_elasticsearch_version
797
+ assert_equal 3, connection_resets
798
+ assert_equal es_major_version, d.instance.instance_variable_get(:@last_seen_major_version)
799
+ end
800
+ end
801
+
697
802
  def test_template_already_present
698
803
  config = %{
699
804
  host logs.google.com
@@ -791,7 +896,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
791
896
  stub_request(:put, "https://logs.google.com:777/es//%3Cfluentd-test.template-default-000001%3E").
792
897
  with(basic_auth: ['john', 'doe']).
793
898
  to_return(status: 200, body: "", headers: {})
794
- stub_request(:put, "https://logs.google.com:777/es//%3Cfluentd-test.template-default-000001%3E/_alias/myapp_deflector-test.template").
899
+ stub_request(:put, "https://logs.google.com:777/es//%3Cfluentd-test.template-default-000001%3E/#{alias_endpoint}/myapp_deflector-test.template").
795
900
  with(basic_auth: ['john', 'doe'],
796
901
  body: "{\"aliases\":{\"myapp_deflector-test.template\":{\"is_write_index\":true}}}").
797
902
  to_return(:status => 200, :body => "", :headers => {})
@@ -849,7 +954,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
849
954
  stub_request(:put, "https://logs.google.com:777/es//%3Cfluentd-test.template-default-000001%3E").
850
955
  with(basic_auth: ['john', 'doe']).
851
956
  to_return(status: 200, body: "", headers: {})
852
- stub_request(:put, "https://logs.google.com:777/es//%3Cfluentd-test.template-default-000001%3E/_alias/myapp_deflector-test.template").
957
+ stub_request(:put, "https://logs.google.com:777/es//%3Cfluentd-test.template-default-000001%3E/#{alias_endpoint}/myapp_deflector-test.template").
853
958
  with(basic_auth: ['john', 'doe'],
854
959
  body: "{\"aliases\":{\"myapp_deflector-test.template\":{\"is_write_index\":true}}}").
855
960
  to_return(:status => 200, :body => "", :headers => {})
@@ -928,7 +1033,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
928
1033
  stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E").
929
1034
  with(basic_auth: ['john', 'doe']).
930
1035
  to_return(:status => 200, :body => "", :headers => {})
931
- stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/logstash").
1036
+ stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/logstash").
932
1037
  with(basic_auth: ['john', 'doe'],
933
1038
  :body => "{\"aliases\":{\"logstash\":{\"is_write_index\":true}}}").
934
1039
  to_return(:status => 200, :body => "", :headers => {})
@@ -995,7 +1100,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
995
1100
  stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E").
996
1101
  with(basic_auth: ['john', 'doe']).
997
1102
  to_return(:status => 200, :body => "", :headers => {})
998
- stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/logstash").
1103
+ stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/logstash").
999
1104
  with(basic_auth: ['john', 'doe'],
1000
1105
  :body => "{\"aliases\":{\"logstash\":{\"is_write_index\":true}}}").
1001
1106
  to_return(:status => 200, :body => "", :headers => {})
@@ -1061,7 +1166,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1061
1166
  stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E").
1062
1167
  with(basic_auth: ['john', 'doe']).
1063
1168
  to_return(:status => 200, :body => "", :headers => {})
1064
- stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/myapp_deflector").
1169
+ stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/myapp_deflector").
1065
1170
  with(basic_auth: ['john', 'doe'],
1066
1171
  :body => "{\"aliases\":{\"myapp_deflector\":{\"is_write_index\":true}}}").
1067
1172
  to_return(:status => 200, :body => "", :headers => {})
@@ -1126,7 +1231,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1126
1231
  stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-000001%3E").
1127
1232
  with(basic_auth: ['john', 'doe']).
1128
1233
  to_return(:status => 200, :body => "", :headers => {})
1129
- stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-000001%3E/_alias/logstash").
1234
+ stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-000001%3E/#{alias_endpoint}/logstash").
1130
1235
  with(basic_auth: ['john', 'doe'],
1131
1236
  :body => "{\"aliases\":{\"logstash\":{\"is_write_index\":true}}}").
1132
1237
  to_return(:status => 200, :body => "", :headers => {})
@@ -1193,7 +1298,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1193
1298
  stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E").
1194
1299
  with(basic_auth: ['john', 'doe']).
1195
1300
  to_return(:status => 200, :body => "", :headers => {})
1196
- stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/logstash").
1301
+ stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/logstash").
1197
1302
  with(body: "{\"aliases\":{\"logstash\":{\"is_write_index\":true}}}").
1198
1303
  to_return(status: 200, body: "", headers: {})
1199
1304
  stub_request(:get, "https://logs.google.com:777/es//_xpack").
@@ -1212,6 +1317,224 @@ class ElasticsearchOutput < Test::Unit::TestCase
1212
1317
  assert_requested(:put, "https://logs.google.com:777/es//_template/logstash", times: 1)
1213
1318
  end
1214
1319
 
1320
+ def test_template_create_with_rollover_index_and_ilm_policies_and_placeholders
1321
+ cwd = File.dirname(__FILE__)
1322
+ template_file = File.join(cwd, 'test_template.json')
1323
+
1324
+ config = %{
1325
+ host logs.google.com
1326
+ port 777
1327
+ scheme https
1328
+ path /es/
1329
+ user john
1330
+ password doe
1331
+ template_name logstash
1332
+ template_file #{template_file}
1333
+ index_date_pattern now/w{xxxx.ww}
1334
+ ilm_policy_id fluentd-policy
1335
+ enable_ilm true
1336
+ index_name logstash
1337
+ ilm_policies {"fluentd-policy":{"policy":{"phases":{"hot":{"actions":{"rollover":{"max_size":"70gb", "max_age":"30d"}}}}}}}
1338
+ }
1339
+
1340
+ # connection start
1341
+ stub_request(:head, "https://logs.google.com:777/es//").
1342
+ with(basic_auth: ['john', 'doe']).
1343
+ to_return(:status => 200, :body => "", :headers => {})
1344
+ # check if template exists
1345
+ stub_request(:get, "https://logs.google.com:777/es//_template/logstash").
1346
+ with(basic_auth: ['john', 'doe']).
1347
+ to_return(:status => 404, :body => "", :headers => {})
1348
+ # creation
1349
+ stub_request(:put, "https://logs.google.com:777/es//_template/logstash").
1350
+ with(basic_auth: ['john', 'doe']).
1351
+ to_return(:status => 200, :body => "", :headers => {})
1352
+ # check if alias exists
1353
+ stub_request(:head, "https://logs.google.com:777/es//_alias/logstash").
1354
+ with(basic_auth: ['john', 'doe']).
1355
+ to_return(:status => 404, :body => "", :headers => {})
1356
+ stub_request(:get, "https://logs.google.com:777/es//_template/logstash").
1357
+ with(basic_auth: ['john', 'doe']).
1358
+ to_return(status: 404, body: "", headers: {})
1359
+ stub_request(:put, "https://logs.google.com:777/es//_template/logstash").
1360
+ with(basic_auth: ['john', 'doe'],
1361
+ body: "{\"settings\":{\"number_of_shards\":1,\"index.lifecycle.name\":\"fluentd-policy\",\"index.lifecycle.rollover_alias\":\"myalogs\"},\"mappings\":{\"type1\":{\"_source\":{\"enabled\":false},\"properties\":{\"host_name\":{\"type\":\"string\",\"index\":\"not_analyzed\"},\"created_at\":{\"type\":\"date\",\"format\":\"EEE MMM dd HH:mm:ss Z YYYY\"}}}},\"index_patterns\":\"mylogs-*\",\"order\":51}").
1362
+ to_return(status: 200, body: "", headers: {})
1363
+ # put the alias for the index
1364
+ stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E").
1365
+ with(basic_auth: ['john', 'doe']).
1366
+ to_return(:status => 200, :body => "", :headers => {})
1367
+ stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/logstash").
1368
+ with(body: "{\"aliases\":{\"logstash\":{\"is_write_index\":true}}}").
1369
+ to_return(status: 200, body: "", headers: {})
1370
+ stub_request(:get, "https://logs.google.com:777/es//_xpack").
1371
+ with(basic_auth: ['john', 'doe']).
1372
+ to_return(:status => 200, :body => '{"features":{"ilm":{"available":true,"enabled":true}}}', :headers => {"Content-Type"=> "application/json"})
1373
+ stub_request(:get, "https://logs.google.com:777/es//_ilm/policy/fluentd-policy").
1374
+ with(basic_auth: ['john', 'doe']).
1375
+ to_return(:status => 404, :body => "", :headers => {})
1376
+ stub_request(:put, "https://logs.google.com:777/es//_ilm/policy/fluentd-policy").
1377
+ with(basic_auth: ['john', 'doe'],
1378
+ :body => "{\"policy\":{\"phases\":{\"hot\":{\"actions\":{\"rollover\":{\"max_size\":\"70gb\",\"max_age\":\"30d\"}}}}}}").
1379
+ to_return(:status => 200, :body => "", :headers => {})
1380
+
1381
+ driver(config)
1382
+
1383
+ elastic_request = stub_elastic("https://logs.google.com:777/es//_bulk")
1384
+ driver.run(default_tag: 'test') do
1385
+ driver.feed(sample_record)
1386
+ end
1387
+ assert_requested(:put, "https://logs.google.com:777/es//_template/logstash", times: 1)
1388
+
1389
+ assert_requested(elastic_request)
1390
+ end
1391
+
1392
+ class TemplateCreateWithRolloverIndexAndILMPoliciesWithPlaceholdersTest < self
1393
+ def test_tag_placeholder
1394
+ cwd = File.dirname(__FILE__)
1395
+ template_file = File.join(cwd, 'test_template.json')
1396
+
1397
+ config = %{
1398
+ host logs.google.com
1399
+ port 777
1400
+ scheme https
1401
+ path /es/
1402
+ user john
1403
+ password doe
1404
+ template_name logstash
1405
+ template_file #{template_file}
1406
+ index_date_pattern now/w{xxxx.ww}
1407
+ ilm_policy_id ${tag}
1408
+ enable_ilm true
1409
+ index_name logstash
1410
+ ilm_policies {"fluentd-policy":{"policy":{"phases":{"hot":{"actions":{"rollover":{"max_size":"70gb", "max_age":"30d"}}}}}}}
1411
+ }
1412
+
1413
+ # connection start
1414
+ stub_request(:head, "https://logs.google.com:777/es//").
1415
+ with(basic_auth: ['john', 'doe']).
1416
+ to_return(:status => 200, :body => "", :headers => {})
1417
+ # check if template exists
1418
+ stub_request(:get, "https://logs.google.com:777/es//_template/logstash").
1419
+ with(basic_auth: ['john', 'doe']).
1420
+ to_return(:status => 404, :body => "", :headers => {})
1421
+ # creation
1422
+ stub_request(:put, "https://logs.google.com:777/es//_template/logstash").
1423
+ with(basic_auth: ['john', 'doe']).
1424
+ to_return(:status => 200, :body => "", :headers => {})
1425
+ # check if alias exists
1426
+ stub_request(:head, "https://logs.google.com:777/es//_alias/logstash").
1427
+ with(basic_auth: ['john', 'doe']).
1428
+ to_return(:status => 404, :body => "", :headers => {})
1429
+ stub_request(:get, "https://logs.google.com:777/es//_template/logstash").
1430
+ with(basic_auth: ['john', 'doe']).
1431
+ to_return(status: 404, body: "", headers: {})
1432
+ stub_request(:put, "https://logs.google.com:777/es//_template/logstash").
1433
+ with(basic_auth: ['john', 'doe'],
1434
+ body: "{\"settings\":{\"number_of_shards\":1,\"index.lifecycle.name\":\"fluentd-policy\",\"index.lifecycle.rollover_alias\":\"myalogs\"},\"mappings\":{\"type1\":{\"_source\":{\"enabled\":false},\"properties\":{\"host_name\":{\"type\":\"string\",\"index\":\"not_analyzed\"},\"created_at\":{\"type\":\"date\",\"format\":\"EEE MMM dd HH:mm:ss Z YYYY\"}}}},\"index_patterns\":\"mylogs-*\",\"order\":51}").
1435
+ to_return(status: 200, body: "", headers: {})
1436
+ # put the alias for the index
1437
+ stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E").
1438
+ with(basic_auth: ['john', 'doe']).
1439
+ to_return(:status => 200, :body => "", :headers => {})
1440
+ stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/logstash").
1441
+ with(body: "{\"aliases\":{\"logstash\":{\"is_write_index\":true}}}").
1442
+ to_return(status: 200, body: "", headers: {})
1443
+ stub_request(:get, "https://logs.google.com:777/es//_xpack").
1444
+ with(basic_auth: ['john', 'doe']).
1445
+ to_return(:status => 200, :body => '{"features":{"ilm":{"available":true,"enabled":true}}}', :headers => {"Content-Type"=> "application/json"})
1446
+ stub_request(:get, "https://logs.google.com:777/es//_ilm/policy/fluentd-policy").
1447
+ with(basic_auth: ['john', 'doe']).
1448
+ to_return(:status => 404, :body => "", :headers => {})
1449
+ stub_request(:put, "https://logs.google.com:777/es//_ilm/policy/fluentd-policy").
1450
+ with(basic_auth: ['john', 'doe'],
1451
+ body: "{\"policy\":{\"phases\":{\"hot\":{\"actions\":{\"rollover\":{\"max_size\":\"70gb\",\"max_age\":\"30d\"}}}}}}").
1452
+ to_return(:status => 200, :body => "", :headers => {})
1453
+
1454
+ driver(config)
1455
+
1456
+ elastic_request = stub_elastic("https://logs.google.com:777/es//_bulk")
1457
+ driver.run(default_tag: 'fluentd-policy') do
1458
+ driver.feed(sample_record)
1459
+ end
1460
+ assert_requested(:put, "https://logs.google.com:777/es//_template/logstash", times: 1)
1461
+
1462
+ assert_requested(elastic_request)
1463
+ end
1464
+
1465
+ def test_tag_placeholder_with_multiple_policies
1466
+ cwd = File.dirname(__FILE__)
1467
+ template_file = File.join(cwd, 'test_template.json')
1468
+
1469
+ config = %{
1470
+ host logs.google.com
1471
+ port 777
1472
+ scheme https
1473
+ path /es/
1474
+ user john
1475
+ password doe
1476
+ template_name logstash
1477
+ template_file #{template_file}
1478
+ index_date_pattern now/w{xxxx.ww}
1479
+ ilm_policy_id ${tag}
1480
+ enable_ilm true
1481
+ index_name logstash
1482
+ ilm_policies {"fluentd-policy":{"policy":{"phases":{"hot":{"actions":{"rollover":{"max_size":"70gb", "max_age":"30d"}}}}}}, "fluentd-policy2":{"policy":{"phases":{"hot":{"actions":{"rollover":{"max_size":"80gb", "max_age":"20d"}}}}}}}
1483
+ }
1484
+
1485
+ # connection start
1486
+ stub_request(:head, "https://logs.google.com:777/es//").
1487
+ with(basic_auth: ['john', 'doe']).
1488
+ to_return(:status => 200, :body => "", :headers => {})
1489
+ # check if template exists
1490
+ stub_request(:get, "https://logs.google.com:777/es//_template/logstash").
1491
+ with(basic_auth: ['john', 'doe']).
1492
+ to_return(:status => 404, :body => "", :headers => {})
1493
+ # creation
1494
+ stub_request(:put, "https://logs.google.com:777/es//_template/logstash").
1495
+ with(basic_auth: ['john', 'doe']).
1496
+ to_return(:status => 200, :body => "", :headers => {})
1497
+ # check if alias exists
1498
+ stub_request(:head, "https://logs.google.com:777/es//_alias/logstash").
1499
+ with(basic_auth: ['john', 'doe']).
1500
+ to_return(:status => 404, :body => "", :headers => {})
1501
+ stub_request(:get, "https://logs.google.com:777/es//_template/logstash").
1502
+ with(basic_auth: ['john', 'doe']).
1503
+ to_return(status: 404, body: "", headers: {})
1504
+ stub_request(:put, "https://logs.google.com:777/es//_template/logstash").
1505
+ with(basic_auth: ['john', 'doe'],
1506
+ body: "{\"settings\":{\"number_of_shards\":1,\"index.lifecycle.name\":\"fluentd-policy\",\"index.lifecycle.rollover_alias\":\"myalogs\"},\"mappings\":{\"type1\":{\"_source\":{\"enabled\":false},\"properties\":{\"host_name\":{\"type\":\"string\",\"index\":\"not_analyzed\"},\"created_at\":{\"type\":\"date\",\"format\":\"EEE MMM dd HH:mm:ss Z YYYY\"}}}},\"index_patterns\":\"mylogs-*\",\"order\":51}").
1507
+ to_return(status: 200, body: "", headers: {})
1508
+ # put the alias for the index
1509
+ stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E").
1510
+ with(basic_auth: ['john', 'doe']).
1511
+ to_return(:status => 200, :body => "", :headers => {})
1512
+ stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/logstash").
1513
+ with(body: "{\"aliases\":{\"logstash\":{\"is_write_index\":true}}}").
1514
+ to_return(status: 200, body: "", headers: {})
1515
+ stub_request(:get, "https://logs.google.com:777/es//_xpack").
1516
+ with(basic_auth: ['john', 'doe']).
1517
+ to_return(:status => 200, :body => '{"features":{"ilm":{"available":true,"enabled":true}}}', :headers => {"Content-Type"=> "application/json"})
1518
+ stub_request(:get, "https://logs.google.com:777/es//_ilm/policy/fluentd-policy2").
1519
+ with(basic_auth: ['john', 'doe']).
1520
+ to_return(:status => 404, :body => "", :headers => {})
1521
+ stub_request(:put, "https://logs.google.com:777/es//_ilm/policy/fluentd-policy2").
1522
+ with(basic_auth: ['john', 'doe'],
1523
+ body: "{\"policy\":{\"phases\":{\"hot\":{\"actions\":{\"rollover\":{\"max_size\":\"80gb\",\"max_age\":\"20d\"}}}}}}").
1524
+ to_return(:status => 200, :body => "", :headers => {})
1525
+
1526
+ driver(config)
1527
+
1528
+ elastic_request = stub_elastic("https://logs.google.com:777/es//_bulk")
1529
+ driver.run(default_tag: 'fluentd-policy2') do
1530
+ driver.feed(sample_record)
1531
+ end
1532
+ assert_requested(:put, "https://logs.google.com:777/es//_template/logstash", times: 1)
1533
+
1534
+ assert_requested(elastic_request)
1535
+ end
1536
+ end
1537
+
1215
1538
  def test_template_create_with_rollover_index_and_default_ilm_and_placeholders
1216
1539
  cwd = File.dirname(__FILE__)
1217
1540
  template_file = File.join(cwd, 'test_template.json')
@@ -1257,7 +1580,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1257
1580
  stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-test-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E").
1258
1581
  with(basic_auth: ['john', 'doe']).
1259
1582
  to_return(:status => 200, :body => "", :headers => {})
1260
- stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-test-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/logstash-test").
1583
+ stub_request(:put, "https://logs.google.com:777/es//%3Clogstash-test-default-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/logstash-test").
1261
1584
  with(basic_auth: ['john', 'doe'],
1262
1585
  :body => "{\"aliases\":{\"logstash-test\":{\"is_write_index\":true}}}").
1263
1586
  to_return(:status => 200, :body => "", :headers => {})
@@ -1441,7 +1764,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1441
1764
  with(basic_auth: ['john', 'doe']).
1442
1765
  to_return(:status => 404, :body => "", :headers => {})
1443
1766
  # put the alias for the index
1444
- stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/mylogs").
1767
+ stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/mylogs").
1445
1768
  with(basic_auth: ['john', 'doe']).
1446
1769
  to_return(:status => 200, :body => "", :headers => {})
1447
1770
 
@@ -1450,7 +1773,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1450
1773
  assert_requested(:put, "https://logs.google.com:777/es//_template/myapp_alias_template", times: 1)
1451
1774
  end
1452
1775
 
1453
- def test_custom_template_with_rollover_index_create_and_deflector_alias
1776
+ def test_custom_template_with_rollover_index_create_and_deflector_alias
1454
1777
  cwd = File.dirname(__FILE__)
1455
1778
  template_file = File.join(cwd, 'test_alias_template.json')
1456
1779
 
@@ -1492,7 +1815,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1492
1815
  with(basic_auth: ['john', 'doe']).
1493
1816
  to_return(:status => 404, :body => "", :headers => {})
1494
1817
  # put the alias for the index
1495
- stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/myapp_deflector").
1818
+ stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/myapp_deflector").
1496
1819
  with(basic_auth: ['john', 'doe']).
1497
1820
  to_return(:status => 200, :body => "", :headers => {})
1498
1821
 
@@ -1544,7 +1867,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1544
1867
  with(basic_auth: ['john', 'doe']).
1545
1868
  to_return(:status => 404, :body => "", :headers => {})
1546
1869
  # put the alias for the index
1547
- stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/mylogs-#{timestr}").
1870
+ stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/mylogs-#{timestr}").
1548
1871
  with(basic_auth: ['john', 'doe']).
1549
1872
  to_return(:status => 200, :body => "", :headers => {})
1550
1873
 
@@ -1615,7 +1938,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1615
1938
  body: "{\"order\":6,\"settings\":{\"index.lifecycle.name\":\"fluentd-policy\",\"index.lifecycle.rollover_alias\":\"mylogs\"},\"mappings\":{},\"aliases\":{\"myapp-logs-alias\":{}},\"index_patterns\":\"mylogs-*\"}").
1616
1939
  to_return(status: 200, body: "", headers: {})
1617
1940
  # put the alias for the index
1618
- stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/mylogs").
1941
+ stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/mylogs").
1619
1942
  with(basic_auth: ['john', 'doe'],
1620
1943
  :body => "{\"aliases\":{\"mylogs\":{\"is_write_index\":true}}}").
1621
1944
  to_return(:status => 200, :body => "", :headers => {})
@@ -1686,7 +2009,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1686
2009
  body: "{\"order\":6,\"settings\":{\"index.lifecycle.name\":\"fluentd-policy\",\"index.lifecycle.rollover_alias\":\"mylogs\"},\"mappings\":{},\"aliases\":{\"myapp-logs-alias\":{}},\"index_patterns\":\"mylogs-*\"}").
1687
2010
  to_return(status: 200, body: "", headers: {})
1688
2011
  # put the alias for the index
1689
- stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/mylogs").
2012
+ stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/mylogs").
1690
2013
  with(basic_auth: ['john', 'doe'],
1691
2014
  :body => "{\"aliases\":{\"mylogs\":{\"is_write_index\":true}}}").
1692
2015
  to_return(:status => 200, :body => "", :headers => {})
@@ -1756,7 +2079,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1756
2079
  body: "{\"order\":6,\"settings\":{\"index.lifecycle.name\":\"fluentd-policy\",\"index.lifecycle.rollover_alias\":\"myapp_deflector\"},\"mappings\":{},\"aliases\":{\"myapp-logs-alias\":{}},\"index_patterns\":\"myapp_deflector-*\"}").
1757
2080
  to_return(status: 200, body: "", headers: {})
1758
2081
  # put the alias for the index
1759
- stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/myapp_deflector").
2082
+ stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/myapp_deflector").
1760
2083
  with(basic_auth: ['john', 'doe'],
1761
2084
  :body => "{\"aliases\":{\"myapp_deflector\":{\"is_write_index\":true}}}").
1762
2085
  to_return(:status => 200, :body => "", :headers => {})
@@ -1825,7 +2148,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1825
2148
  body: "{\"order\":8,\"settings\":{\"index.lifecycle.name\":\"fluentd-policy\",\"index.lifecycle.rollover_alias\":\"mylogs-custom-test\"},\"mappings\":{},\"aliases\":{\"myapp-logs-alias\":{}},\"index_patterns\":\"mylogs-custom-test-*\"}").
1826
2149
  to_return(status: 200, body: "", headers: {})
1827
2150
  # put the alias for the index
1828
- stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-custom-test-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/mylogs-custom-test").
2151
+ stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-custom-test-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/mylogs-custom-test").
1829
2152
  with(basic_auth: ['john', 'doe'],
1830
2153
  :body => "{\"aliases\":{\"mylogs-custom-test\":{\"is_write_index\":true}}}").
1831
2154
  to_return(:status => 200, :body => "", :headers => {})
@@ -1902,7 +2225,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
1902
2225
  with(basic_auth: ['john', 'doe']).
1903
2226
  to_return(status: 200, body: "", headers: {})
1904
2227
  # put the alias for the index
1905
- stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/_alias/mylogs").
2228
+ stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fw%7Bxxxx.ww%7D%7D-000001%3E/#{alias_endpoint}/mylogs").
1906
2229
  with(basic_auth: ['john', 'doe'],
1907
2230
  :body => "{\"aliases\":{\"mylogs\":{\"is_write_index\":true}}}").
1908
2231
  to_return(:status => 200, :body => "", :headers => {})
@@ -2034,7 +2357,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
2034
2357
  with(basic_auth: ['john', 'doe']).
2035
2358
  to_return(:status => 404, :body => "", :headers => {})
2036
2359
  # put the alias for the index
2037
- stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fd%7D-000001%3E/_alias/myapp_deflector").
2360
+ stub_request(:put, "https://logs.google.com:777/es//%3Cmylogs-myapp-%7Bnow%2Fd%7D-000001%3E/#{alias_endpoint}/myapp_deflector").
2038
2361
  with(basic_auth: ['john', 'doe']).
2039
2362
  to_return(:status => 200, :body => "", :headers => {})
2040
2363
 
@@ -2548,6 +2871,8 @@ class ElasticsearchOutput < Test::Unit::TestCase
2548
2871
 
2549
2872
 
2550
2873
  def test_writes_to_default_index_with_compression
2874
+ omit "elastisearch-ruby v7.2.0 or later is needed." if Gem::Version.create(::Elasticsearch::Transport::VERSION) < Gem::Version.create("7.2.0")
2875
+
2551
2876
  config = %[
2552
2877
  compression_level default_compression
2553
2878
  ]
@@ -3121,6 +3446,54 @@ class ElasticsearchOutput < Test::Unit::TestCase
3121
3446
  end
3122
3447
  end
3123
3448
 
3449
+ class LogStashDateformatPlaceholdersTest < self
3450
+ def test_writes_to_logstash_index_with_specified_prefix_and_dateformat_placeholder_pattern_1
3451
+ driver.configure(Fluent::Config::Element.new(
3452
+ 'ROOT', '', {
3453
+ '@type' => 'elasticsearch',
3454
+ 'logstash_format' => true,
3455
+ 'logstash_dateformat' => '${indexformat}',
3456
+ 'logstash_prefix' => 'myprefix',
3457
+ }, [
3458
+ Fluent::Config::Element.new('buffer', 'tag,time,indexformat', {
3459
+ 'chunk_keys' => ['tag', 'time', 'indexformat'],
3460
+ 'timekey' => 3600,
3461
+ }, [])
3462
+ ]
3463
+ ))
3464
+ time = Time.parse Date.today.iso8601
3465
+ logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m.%d")}"
3466
+ stub_elastic
3467
+ driver.run(default_tag: 'test') do
3468
+ driver.feed(time.to_i, sample_record.merge('indexformat' => '%Y.%m.%d'))
3469
+ end
3470
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
3471
+ end
3472
+
3473
+ def test_writes_to_logstash_index_with_specified_prefix_and_dateformat_placeholder_pattern_2
3474
+ driver.configure(Fluent::Config::Element.new(
3475
+ 'ROOT', '', {
3476
+ '@type' => 'elasticsearch',
3477
+ 'logstash_format' => true,
3478
+ 'logstash_dateformat' => '${indexformat}',
3479
+ 'logstash_prefix' => 'myprefix',
3480
+ }, [
3481
+ Fluent::Config::Element.new('buffer', 'tag,time,indexformat', {
3482
+ 'chunk_keys' => ['tag', 'time', 'indexformat'],
3483
+ 'timekey' => 3600,
3484
+ }, [])
3485
+ ]
3486
+ ))
3487
+ time = Time.parse Date.today.iso8601
3488
+ logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m")}"
3489
+ stub_elastic
3490
+ driver.run(default_tag: 'test') do
3491
+ driver.feed(time.to_i, sample_record.merge('indexformat' => '%Y.%m'))
3492
+ end
3493
+ assert_equal(logstash_index, index_cmds.first['index']['_index'])
3494
+ end
3495
+ end
3496
+
3124
3497
  class HostnamePlaceholders < self
3125
3498
  def test_writes_to_extracted_host
3126
3499
  driver.configure("host ${tag}\n")