fluent-plugin-elasticsearch 4.0.4 → 4.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -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")