fluent-plugin-elasticsearch 4.0.5 → 4.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,7 @@ $:.push File.expand_path('../lib', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'fluent-plugin-elasticsearch'
6
- s.version = '4.0.5'
6
+ s.version = '4.0.10'
7
7
  s.authors = ['diogo', 'pitr', 'Hiroshi Hatake']
8
8
  s.email = ['pitr.vern@gmail.com', 'me@diogoterror.com', 'cosmo0920.wp@gmail.com']
9
9
  s.description = %q{Elasticsearch output plugin for Fluent event collector}
@@ -4,7 +4,7 @@ source 'https://rubygems.org'
4
4
  gemspec :path => "../"
5
5
 
6
6
  gem 'simplecov', require: false
7
- gem 'coveralls', require: false
7
+ gem 'coveralls', ">= 0.8.0", require: false
8
8
  gem 'strptime', require: false if RUBY_ENGINE == "ruby" && RUBY_VERSION =~ /^2/
9
9
  gem "irb" if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.6"
10
10
  gem "elasticsearch", "~> 6.8.1"
@@ -4,8 +4,7 @@ source 'https://rubygems.org'
4
4
  gemspec :path => "../"
5
5
 
6
6
  gem 'simplecov', require: false
7
- gem 'coveralls', require: false
7
+ gem 'coveralls', ">= 0.8.0", require: false
8
8
  gem 'strptime', require: false if RUBY_ENGINE == "ruby" && RUBY_VERSION =~ /^2/
9
9
  gem "irb" if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.6"
10
- gem "elasticsearch-xpack"
11
10
  gem "oj"
@@ -58,7 +58,7 @@ module Fluent::ElasticsearchIndexTemplate
58
58
  def indexcreation(index_name, host = nil)
59
59
  client(host).indices.create(:index => index_name)
60
60
  rescue Elasticsearch::Transport::Transport::Error => e
61
- if e.message =~ /"already exists"/
61
+ if e.message =~ /"already exists"/ || e.message =~ /resource_already_exists_exception/
62
62
  log.debug("Index #{index_name} already exists")
63
63
  else
64
64
  log.error("Error while index creation - #{index_name}: #{e.inspect}")
@@ -10,7 +10,7 @@ module Fluent::Plugin
10
10
  [:SSLv23, :TLSv1, :TLSv1_1, :TLSv1_2].freeze
11
11
  end
12
12
 
13
- DEFAULT_VERSION = :TLSv1
13
+ DEFAULT_VERSION = :TLSv1_2
14
14
  METHODS_MAP = begin
15
15
  # When openssl supports OpenSSL::SSL::TLSXXX constants representations, we use them.
16
16
  map = {
@@ -48,8 +48,8 @@ module Fluent::Plugin
48
48
  if USE_TLS_MINMAX_VERSION
49
49
  case
50
50
  when ssl_min_version.nil? && ssl_max_version.nil?
51
- ssl_min_version = METHODS_MAP[ssl_version]
52
- ssl_max_version = METHODS_MAP[ssl_version]
51
+ ssl_min_version = METHODS_MAP[:TLSv1_2]
52
+ ssl_max_version = METHODS_MAP[:TLSv1_3]
53
53
  when ssl_min_version && ssl_max_version.nil?
54
54
  raise Fluent::ConfigError, "When you set 'ssl_min_version', must set 'ssl_max_version' together."
55
55
  when ssl_min_version.nil? && ssl_max_version
@@ -7,6 +7,13 @@ module Fluent::Plugin
7
7
  Fluent::Plugin.register_filter('elasticsearch_genid', self)
8
8
 
9
9
  config_param :hash_id_key, :string, :default => '_hash'
10
+ config_param :include_tag_in_seed, :bool, :default => false
11
+ config_param :include_time_in_seed, :bool, :default => false
12
+ config_param :use_record_as_seed, :bool, :default => false
13
+ config_param :use_entire_record, :bool, :default => false
14
+ config_param :record_keys, :array, :default => []
15
+ config_param :separator, :string, :default => '_'
16
+ config_param :hash_type, :enum, list: [:md5, :sha1, :sha256, :sha512], :default => :sha1
10
17
 
11
18
  def initialize
12
19
  super
@@ -14,12 +21,57 @@ module Fluent::Plugin
14
21
 
15
22
  def configure(conf)
16
23
  super
24
+
25
+ if !@use_entire_record
26
+ if @record_keys.empty? && @use_record_as_seed
27
+ raise Fluent::ConfigError, "When using record as hash seed, users must specify `record_keys`."
28
+ end
29
+ end
30
+
31
+ if @use_record_as_seed
32
+ class << self
33
+ alias_method :filter, :filter_seed_as_record
34
+ end
35
+ else
36
+ class << self
37
+ alias_method :filter, :filter_simple
38
+ end
39
+ end
17
40
  end
18
41
 
19
42
  def filter(tag, time, record)
43
+ # for safety.
44
+ end
45
+
46
+ def filter_simple(tag, time, record)
20
47
  record[@hash_id_key] = Base64.strict_encode64(SecureRandom.uuid)
21
48
  record
22
49
  end
23
50
 
51
+ def filter_seed_as_record(tag, time, record)
52
+ seed = ""
53
+ seed += tag + separator if @include_tag_in_seed
54
+ seed += time.to_s + separator if @include_time_in_seed
55
+ if @use_entire_record
56
+ record.each {|k,v| seed += "|#{k}|#{v}"}
57
+ else
58
+ seed += record_keys.map {|k| record[k]}.join(separator)
59
+ end
60
+ record[@hash_id_key] = Base64.strict_encode64(encode_hash(@hash_type, seed))
61
+ record
62
+ end
63
+
64
+ def encode_hash(type, seed)
65
+ case type
66
+ when :md5
67
+ Digest::MD5.digest(seed)
68
+ when :sha1
69
+ Digest::SHA1.digest(seed)
70
+ when :sha256
71
+ Digest::SHA256.digest(seed)
72
+ when :sha512
73
+ Digest::SHA512.digest(seed)
74
+ end
75
+ end
24
76
  end
25
77
  end
@@ -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
 
@@ -89,6 +90,7 @@ EOC
89
90
  config_param :logstash_dateformat, :string, :default => "%Y.%m.%d"
90
91
  config_param :utc_index, :bool, :default => true
91
92
  config_param :type_name, :string, :default => DEFAULT_TYPE_NAME
93
+ config_param :suppress_type_name, :bool, :default => false
92
94
  config_param :index_name, :string, :default => "fluentd"
93
95
  config_param :id_key, :string, :default => nil
94
96
  config_param :write_operation, :string, :default => "index"
@@ -125,6 +127,7 @@ EOC
125
127
  config_param :templates, :hash, :default => nil
126
128
  config_param :max_retry_putting_template, :integer, :default => 10
127
129
  config_param :fail_on_putting_template_retry_exceed, :bool, :default => true
130
+ config_param :fail_on_detecting_es_version_retry_exceed, :bool, :default => true
128
131
  config_param :max_retry_get_es_version, :integer, :default => 15
129
132
  config_param :include_tag_key, :bool, :default => false
130
133
  config_param :tag_key, :string, :default => 'tag'
@@ -142,6 +145,7 @@ see: https://github.com/elastic/elasticsearch-ruby/pull/514
142
145
  EOC
143
146
  config_param :include_index_in_url, :bool, :default => false
144
147
  config_param :http_backend, :enum, list: [:excon, :typhoeus], :default => :excon
148
+ config_param :http_backend_excon_nonblock, :bool, :default => true
145
149
  config_param :validate_client_version, :bool, :default => false
146
150
  config_param :prefer_oj_serializer, :bool, :default => false
147
151
  config_param :unrecoverable_error_types, :array, :default => ["out_of_memory_error", "es_rejected_execution_exception"]
@@ -157,6 +161,7 @@ EOC
157
161
  config_param :enable_ilm, :bool, :default => false
158
162
  config_param :ilm_policy_id, :string, :default => DEFAULT_POLICY_ID
159
163
  config_param :ilm_policy, :hash, :default => {}
164
+ config_param :ilm_policies, :hash, :default => {}
160
165
  config_param :ilm_policy_overwrite, :bool, :default => false
161
166
  config_param :truncate_caches_interval, :time, :default => nil
162
167
 
@@ -217,6 +222,11 @@ EOC
217
222
  log.info "host placeholder and template installation makes your Elasticsearch cluster a bit slow down(beta)."
218
223
  end
219
224
 
225
+ raise Fluent::ConfigError, "You can't specify ilm_policy and ilm_policies at the same time" unless @ilm_policy.empty? or @ilm_policies.empty?
226
+
227
+ unless @ilm_policy.empty?
228
+ @ilm_policies = { @ilm_policy_id => @ilm_policy }
229
+ end
220
230
  @alias_indexes = []
221
231
  @template_names = []
222
232
  if !dry_run?
@@ -225,14 +235,14 @@ EOC
225
235
  raise Fluent::ConfigError, "deflector_alias is prohibited to use with 'logstash_format at same time." if @logstash_format and @deflector_alias
226
236
  end
227
237
  if @ilm_policy.empty? && @ilm_policy_overwrite
228
- raise Fluent::ConfigError, "ilm_policy_overwrite can work with non empty ilm_policy. Specify non-empty ilm policy into ilm_policy. "
238
+ raise Fluent::ConfigError, "ilm_policy_overwrite requires a non empty ilm_policy."
229
239
  end
230
240
  if @logstash_format || placeholder_substitution_needed_for_template?
231
241
  class << self
232
242
  alias_method :template_installation, :template_installation_actual
233
243
  end
234
244
  else
235
- template_installation_actual(@deflector_alias ? @deflector_alias : @index_name, @template_name, @customize_template, @application_name, @index_name)
245
+ template_installation_actual(@deflector_alias ? @deflector_alias : @index_name, @template_name, @customize_template, @application_name, @index_name, @ilm_policy_id)
236
246
  end
237
247
  verify_ilm_working if @enable_ilm
238
248
  elsif @templates
@@ -290,24 +300,25 @@ EOC
290
300
  raise Fluent::ConfigError, "Could not load sniffer class #{@sniffer_class_name}: #{ex}"
291
301
  end
292
302
 
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
301
- if @last_seen_major_version == 6 && @type_name != DEFAULT_TYPE_NAME_ES_7x
302
- log.info "Detected ES 6.x: ES 7.x will only accept `_doc` in type_name."
303
- end
304
- if @last_seen_major_version == 7 && @type_name != DEFAULT_TYPE_NAME_ES_7x
305
- log.warn "Detected ES 7.x: `_doc` will be used as the document `_type`."
306
- @type_name = '_doc'.freeze
307
- end
308
- if @last_seen_major_version >= 8 && @type_name != DEFAULT_TYPE_NAME_ES_7x
309
- log.info "Detected ES 8.x or above: This parameter has no effect."
303
+ @last_seen_major_version = if major_version = handle_last_seen_es_major_version
304
+ major_version
305
+ else
306
+ @default_elasticsearch_version
307
+ end
308
+ if @suppress_type_name && @last_seen_major_version >= 7
310
309
  @type_name = nil
310
+ else
311
+ if @last_seen_major_version == 6 && @type_name != DEFAULT_TYPE_NAME_ES_7x
312
+ log.info "Detected ES 6.x: ES 7.x will only accept `_doc` in type_name."
313
+ end
314
+ if @last_seen_major_version == 7 && @type_name != DEFAULT_TYPE_NAME_ES_7x
315
+ log.warn "Detected ES 7.x: `_doc` will be used as the document `_type`."
316
+ @type_name = '_doc'.freeze
317
+ end
318
+ if @last_seen_major_version >= 8 && @type_name != DEFAULT_TYPE_NAME_ES_7x
319
+ log.info "Detected ES 8.x or above: This parameter has no effect."
320
+ @type_name = nil
321
+ end
311
322
  end
312
323
 
313
324
  if @validate_client_version && !dry_run?
@@ -329,6 +340,13 @@ EOC
329
340
  end
330
341
  end
331
342
 
343
+ if @ssl_version && @scheme == :https
344
+ if !@http_backend_excon_nonblock
345
+ log.warn "TLS handshake will be stucked with block connection.
346
+ Consider to set `http_backend_excon_nonblock` as true"
347
+ end
348
+ end
349
+
332
350
  # Consider missing the prefix of "$." in nested key specifiers.
333
351
  @id_key = convert_compat_id_key(@id_key) if @id_key
334
352
  @parent_key = convert_compat_id_key(@parent_key) if @parent_key
@@ -337,6 +355,7 @@ EOC
337
355
  @routing_key_name = configure_routing_key_name
338
356
  @meta_config_map = create_meta_config_map
339
357
  @current_config = nil
358
+ @compressable_connection = false
340
359
 
341
360
  @ignore_exception_classes = @ignore_exceptions.map do |exception|
342
361
  unless Object.const_defined?(exception)
@@ -411,7 +430,7 @@ EOC
411
430
  def backend_options
412
431
  case @http_backend
413
432
  when :excon
414
- { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass }
433
+ { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass, nonblock: @http_backend_excon_nonblock }
415
434
  when :typhoeus
416
435
  require 'typhoeus'
417
436
  { sslkey: @client_key, sslcert: @client_cert, keypasswd: @client_key_pass }
@@ -421,6 +440,16 @@ EOC
421
440
  raise Fluent::ConfigError, "You must install #{@http_backend} gem. Exception: #{ex}"
422
441
  end
423
442
 
443
+ def handle_last_seen_es_major_version
444
+ if @verify_es_version_at_startup && !dry_run?
445
+ retry_operate(@max_retry_get_es_version, @fail_on_detecting_es_version_retry_exceed) do
446
+ detect_es_major_version
447
+ end
448
+ else
449
+ nil
450
+ end
451
+ end
452
+
424
453
  def detect_es_major_version
425
454
  @_es_info ||= client.info
426
455
  @_es_info["version"]["number"].to_i
@@ -495,13 +524,15 @@ EOC
495
524
  return Time.at(event_time).to_datetime
496
525
  end
497
526
 
498
- def client(host = nil)
527
+ def client(host = nil, compress_connection = false)
499
528
  # check here to see if we already have a client connection for the given host
500
529
  connection_options = get_connection_options(host)
501
530
 
502
531
  @_es = nil unless is_existing_connection(connection_options[:hosts])
532
+ @_es = nil unless @compressable_connection == compress_connection
503
533
 
504
534
  @_es ||= begin
535
+ @compressable_connection = compress_connection
505
536
  @current_config = connection_options[:hosts].clone
506
537
  adapter_conf = lambda {|f| f.adapter @http_backend, @backend_options }
507
538
  local_reload_connections = @reload_connections
@@ -509,7 +540,7 @@ EOC
509
540
  local_reload_connections = @reload_after
510
541
  end
511
542
 
512
- gzip_headers = if compression
543
+ gzip_headers = if compress_connection
513
544
  {'Content-Encoding' => 'gzip'}
514
545
  else
515
546
  {}
@@ -535,7 +566,7 @@ EOC
535
566
  },
536
567
  sniffer_class: @sniffer_class,
537
568
  serializer_class: @serializer_class,
538
- compression: compression,
569
+ compression: compress_connection,
539
570
  }), &adapter_conf)
540
571
  Elasticsearch::Client.new transport: transport
541
572
  end
@@ -699,7 +730,12 @@ EOC
699
730
  else
700
731
  pipeline = nil
701
732
  end
702
- return logstash_prefix, logstash_dateformat, index_name, type_name, template_name, customize_template, deflector_alias, application_name, pipeline
733
+ if @ilm_policy_id
734
+ ilm_policy_id = extract_placeholders(@ilm_policy_id, chunk)
735
+ else
736
+ ilm_policy_id = nil
737
+ end
738
+ return logstash_prefix, logstash_dateformat, index_name, type_name, template_name, customize_template, deflector_alias, application_name, pipeline, ilm_policy_id
703
739
  end
704
740
 
705
741
  def multi_workers_ready?
@@ -773,7 +809,7 @@ EOC
773
809
  end
774
810
 
775
811
  def process_message(tag, meta, header, time, record, extracted_values)
776
- logstash_prefix, logstash_dateformat, index_name, type_name, _template_name, _customize_template, _deflector_alias, _application_name, pipeline = extracted_values
812
+ logstash_prefix, logstash_dateformat, index_name, type_name, _template_name, _customize_template, _deflector_alias, _application_name, pipeline, _ilm_policy_id = extracted_values
777
813
 
778
814
  if @flatten_hashes
779
815
  record = flatten_record(record)
@@ -825,7 +861,9 @@ EOC
825
861
  target_type = nil
826
862
  end
827
863
  else
828
- if @last_seen_major_version == 7 && @type_name != DEFAULT_TYPE_NAME_ES_7x
864
+ if @suppress_type_name && @last_seen_major_version >= 7
865
+ target_type = nil
866
+ elsif @last_seen_major_version == 7 && @type_name != DEFAULT_TYPE_NAME_ES_7x
829
867
  log.warn "Detected ES 7.x: `_doc` will be used as the document `_type`."
830
868
  target_type = '_doc'.freeze
831
869
  elsif @last_seen_major_version >= 8
@@ -881,16 +919,17 @@ EOC
881
919
  placeholder?(:logstash_prefix, @logstash_prefix.to_s) ||
882
920
  placeholder?(:logstash_dateformat, @logstash_dateformat.to_s) ||
883
921
  placeholder?(:deflector_alias, @deflector_alias.to_s) ||
884
- placeholder?(:application_name, @application_name.to_s)
922
+ placeholder?(:application_name, @application_name.to_s) ||
923
+ placeholder?(:ilm_policy_id, @ilm_policy_id.to_s)
885
924
  log.debug("Need substitution: #{need_substitution}")
886
925
  need_substitution
887
926
  end
888
927
 
889
- def template_installation(deflector_alias, template_name, customize_template, application_name, target_index, host)
928
+ def template_installation(deflector_alias, template_name, customize_template, application_name, ilm_policy_id, target_index, host)
890
929
  # for safety.
891
930
  end
892
931
 
893
- def template_installation_actual(deflector_alias, template_name, customize_template, application_name, target_index, host=nil)
932
+ def template_installation_actual(deflector_alias, template_name, customize_template, application_name, target_index, ilm_policy_id, host=nil)
894
933
  if template_name && @template_file
895
934
  if @alias_indexes.include? deflector_alias
896
935
  log.debug("Index alias #{deflector_alias} already exists (cached)")
@@ -899,11 +938,12 @@ EOC
899
938
  else
900
939
  retry_operate(@max_retry_putting_template, @fail_on_putting_template_retry_exceed) do
901
940
  if customize_template
902
- template_custom_install(template_name, @template_file, @template_overwrite, customize_template, @enable_ilm, deflector_alias, @ilm_policy_id, host)
941
+ template_custom_install(template_name, @template_file, @template_overwrite, customize_template, @enable_ilm, deflector_alias, ilm_policy_id, host)
903
942
  else
904
- template_install(template_name, @template_file, @template_overwrite, @enable_ilm, deflector_alias, @ilm_policy_id, host)
943
+ template_install(template_name, @template_file, @template_overwrite, @enable_ilm, deflector_alias, ilm_policy_id, host)
905
944
  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)
945
+ ilm_policy = @ilm_policies[ilm_policy_id] || {}
946
+ 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
947
  end
908
948
  @alias_indexes << deflector_alias unless deflector_alias.nil?
909
949
  @template_names << template_name unless template_name.nil?
@@ -914,11 +954,11 @@ EOC
914
954
  # send_bulk given a specific bulk request, the original tag,
915
955
  # chunk, and bulk_message_count
916
956
  def send_bulk(data, tag, chunk, bulk_message_count, extracted_values, info)
917
- logstash_prefix, _logstash_dateformat, index_name, _type_name, template_name, customize_template, deflector_alias, application_name, _pipeline = extracted_values
957
+ logstash_prefix, _logstash_dateformat, index_name, _type_name, template_name, customize_template, deflector_alias, application_name, _pipeline, ilm_policy_id = extracted_values
918
958
  if deflector_alias
919
- template_installation(deflector_alias, template_name, customize_template, application_name, index_name, info.host)
959
+ template_installation(deflector_alias, template_name, customize_template, application_name, index_name, ilm_policy_id, info.host)
920
960
  else
921
- template_installation(info.ilm_index, template_name, customize_template, application_name, @logstash_format ? logstash_prefix : index_name, info.host)
961
+ template_installation(info.ilm_index, template_name, customize_template, application_name, @logstash_format ? logstash_prefix : index_name, ilm_policy_id, info.host)
922
962
  end
923
963
 
924
964
  begin
@@ -931,7 +971,7 @@ EOC
931
971
  data
932
972
  end
933
973
 
934
- response = client(info.host).bulk body: prepared_data, index: info.index
974
+ response = client(info.host, compression).bulk body: prepared_data, index: info.index
935
975
  log.on_trace { log.trace "bulk response: #{response}" }
936
976
 
937
977
  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