fluent-plugin-elasticsearch 5.4.3 → 6.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 542a7706becd1b24f8d3e6ad8957015dba5f721b3a93047ec4bea80313df8200
4
- data.tar.gz: 8104645d96578abf0f4357a22c83a7f9cbc548e7bbc35ef5eeb8726deaada6f8
3
+ metadata.gz: b54470881e62c1a0c6fccc56867faf07ecbe210a0926a8073fc646fcd2ffc9e1
4
+ data.tar.gz: f973db55d17915664f6cb59676738c62f7408c3d94734cdb54b76025d62d82c8
5
5
  SHA512:
6
- metadata.gz: 93a2a932a766170b197f3ded762c89912f743cec3ddcef3e7719d8ca57b504f6f7b51bc17bac02ef5073fd1fade3366140a7d775351c8b86b1f05693a76be122
7
- data.tar.gz: 35b82c172909a1f47dc74507c7ea9df451576b9cb1c8dcba85fdb094b3568b2187aafa1aecbd3367ef2ab0a347a30f90d8b663780e3261bdefc5dcb2b24f0133
6
+ metadata.gz: 45a60caf34b6e02e5e2a46fd02535a3fa1648d1feb712c1d20c1a88f041c29a39fe688afba1c88511a572075db7e98c767ad81b4197b6bc56a1e1e27d9149764
7
+ data.tar.gz: 2e0d0dab94d7c3112b637f185c9df0bf16c2fb1805d9186de2fecf6d25e66eea269482431b2db20b62e66f16ebcbd66dd576d6e1e957c12c29d68728b7132806
@@ -11,7 +11,7 @@ jobs:
11
11
  strategy:
12
12
  fail-fast: false
13
13
  matrix:
14
- ruby: [ '3.0', '3.1', '3.2' ]
14
+ ruby: [ '3.0', '3.1', '3.2', '3.3', '3.4' ]
15
15
  os:
16
16
  - ubuntu-latest
17
17
  name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }}
@@ -11,7 +11,7 @@ jobs:
11
11
  strategy:
12
12
  fail-fast: false
13
13
  matrix:
14
- ruby: [ '3.0', '3.1', '3.2' ]
14
+ ruby: [ '3.0', '3.1', '3.2', '3.3', '3.4' ]
15
15
  os:
16
16
  - macOS-latest
17
17
  name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }}
@@ -11,7 +11,7 @@ jobs:
11
11
  strategy:
12
12
  fail-fast: false
13
13
  matrix:
14
- ruby: [ '3.0', '3.1', '3.2' ]
14
+ ruby: [ '3.0', '3.1', '3.2', '3.3', '3.4' ]
15
15
  os:
16
16
  - windows-latest
17
17
  name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }}
data/History.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ### [Unreleased]
4
4
 
5
+ ### 6.0.0
6
+ - Adjust Content-Type and Accept headers for sending logs into ES9 (#1064)
7
+
8
+ ### 5.4.4
9
+ - docs: Clarify README docs for template_name and templates (#1043)
10
+ - `out_elasticsearch_data_stream`: Avoid long worrying log line at info level (#1044)
11
+ - `out_elasticsearch_data_stream`: Support `id_key` and `remove_keys` (#1057)
12
+ - `out_elasticsearch`: Fix memory leaks when exception was raised frequently (#1065)
13
+
5
14
  ### 5.4.3
6
15
  - add data_stream_template\_use\_index\_patterns\_wildcard in elasticsearch\_data\_stream (#1040)
7
16
 
data/README.md CHANGED
@@ -527,7 +527,7 @@ into same document with data1 as wanted and duplicated document is avoided.
527
527
 
528
528
  ### template_name
529
529
 
530
- The name of the template to define. If a template by the name given is already present, it will be left unchanged, unless [template_overwrite](#template_overwrite) is set, in which case the template will be updated.
530
+ The name of the index template to create on fluentd startup. If a template by the name given is already present, it will be left unchanged, unless [template_overwrite](#template_overwrite) is set, in which case the template will be updated.
531
531
 
532
532
  This parameter along with template_file allow the plugin to behave similarly to Logstash (it installs a template at creation time) so that raw records are available. See [https://github.com/uken/fluent-plugin-elasticsearch/issues/33](https://github.com/uken/fluent-plugin-elasticsearch/issues/33).
533
533
 
@@ -541,7 +541,7 @@ The path to the file containing the template to install.
541
541
 
542
542
  ### templates
543
543
 
544
- Specify index templates in form of hash. Can contain multiple templates.
544
+ Specify index templates (to be created on startup) in the form of a hash (accepts JSON dict). Can contain multiple templates.
545
545
 
546
546
  ```
547
547
  templates { "template_name_1": "path_to_template_1_file", "template_name_2": "path_to_template_2_file"}
@@ -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 = '5.4.3'
6
+ s.version = '6.0.0'
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}
@@ -73,6 +73,7 @@ module Fluent::Plugin
73
73
  DEFAULT_RELOAD_AFTER = -1
74
74
  DEFAULT_TARGET_BULK_BYTES = -1
75
75
  DEFAULT_POLICY_ID = "logstash-policy"
76
+ ES9_CONTENT_TYPE = "application/vnd.elasticsearch+x-ndjson; compatible-with=9"
76
77
 
77
78
  config_param :host, :string, :default => 'localhost'
78
79
  config_param :port, :integer, :default => 9200
@@ -350,10 +351,22 @@ EOC
350
351
  log.warn "Detected ES 7.x: `_doc` will be used as the document `_type`."
351
352
  @type_name = '_doc'.freeze
352
353
  end
353
- if @last_seen_major_version >= 8 && @type_name != DEFAULT_TYPE_NAME_ES_7x
354
- log.debug "Detected ES 8.x or above: This parameter has no effect."
354
+ if @last_seen_major_version == 8 && @type_name != DEFAULT_TYPE_NAME_ES_7x
355
+ log.debug "Detected ES 8.x: This parameter has no effect."
355
356
  @type_name = nil
356
357
  end
358
+ if @last_seen_major_version >= 9
359
+ if @type_name != DEFAULT_TYPE_NAME_ES_7x
360
+ log.debug "Detected ES 9.x or above: This parameter has no effect."
361
+ @type_name = nil
362
+ end
363
+ @accept_type = nil
364
+ if @content_type != ES9_CONTENT_TYPE
365
+ log.trace "Detected ES 9.x or above: Content-Type will be adjusted."
366
+ @content_type = ES9_CONTENT_TYPE
367
+ @accept_type = ES9_CONTENT_TYPE
368
+ end
369
+ end
357
370
  end
358
371
 
359
372
  if @validate_client_version && !dry_run?
@@ -614,6 +627,8 @@ EOC
614
627
  .merge(@custom_headers)
615
628
  .merge(@api_key_header)
616
629
  .merge(gzip_headers)
630
+ headers.merge!('Accept' => @accept_type) if @accept_type
631
+
617
632
  ssl_options = { verify: @ssl_verify, ca_file: @ca_file}.merge(@ssl_version_options)
618
633
 
619
634
  transport = TRANSPORT_CLASS::Transport::HTTP::Faraday.new(connection_options.merge(
@@ -883,11 +898,11 @@ EOC
883
898
  if split_request?(bulk_message, info)
884
899
  bulk_message.each do |info, msgs|
885
900
  send_bulk(msgs, tag, chunk, bulk_message_count[info], extracted_values, info, unpackedMsgArr[info]) unless msgs.empty?
901
+ ensure
886
902
  unpackedMsgArr[info].clear
887
903
  msgs.clear
888
904
  # Clear bulk_message_count for this info.
889
905
  bulk_message_count[info] = 0;
890
- next
891
906
  end
892
907
  end
893
908
 
@@ -907,7 +922,7 @@ EOC
907
922
 
908
923
  bulk_message.each do |info, msgs|
909
924
  send_bulk(msgs, tag, chunk, bulk_message_count[info], extracted_values, info, unpackedMsgArr[info]) unless msgs.empty?
910
-
925
+ ensure
911
926
  unpackedMsgArr[info].clear
912
927
  msgs.clear
913
928
  end
@@ -142,7 +142,7 @@ module Fluent::Plugin
142
142
  response = client(host).indices.get_data_stream(params)
143
143
  return (not response.is_a?(TRANSPORT_CLASS::Transport::Errors::NotFound))
144
144
  rescue TRANSPORT_CLASS::Transport::Errors::NotFound => e
145
- log.info "Specified data stream does not exist. Will be created: <#{e}>"
145
+ log.info "Specified data stream does not exist. Will be created: <#{datastream_name}>"
146
146
  return false
147
147
  end
148
148
  end
@@ -219,6 +219,8 @@ module Fluent::Plugin
219
219
  data_stream_name = @data_stream_name
220
220
  data_stream_template_name = @data_stream_template_name
221
221
  data_stream_ilm_name = @data_stream_ilm_name
222
+ id_key = @id_key
223
+ remove_keys = @remove_keys
222
224
  host = nil
223
225
  if @use_placeholder
224
226
  host = if @hosts
@@ -257,7 +259,15 @@ module Fluent::Plugin
257
259
  unless record.has_key?("@timestamp")
258
260
  record.merge!({"@timestamp" => Time.at(time).iso8601(@time_precision)})
259
261
  end
260
- bulk_message = append_record_to_messages(CREATE_OP, {}, headers, record, bulk_message)
262
+
263
+ # meta variable to be appended in bulk_message
264
+ meta = {}
265
+ meta = {'_id' => record[id_key]} if id_key and record[id_key]
266
+
267
+ # Remove any key in remove_keys if defined
268
+ remove_keys.each { |key| record.delete(key) } if remove_keys
269
+
270
+ bulk_message = append_record_to_messages(CREATE_OP, meta, headers, record, bulk_message)
261
271
  rescue => e
262
272
  router.emit_error_event(tag, time, record, e)
263
273
  end
@@ -37,6 +37,10 @@ class TestElasticsearchIndexLifecycleManagement < Test::Unit::TestCase
37
37
  end
38
38
  end
39
39
 
40
+ def elasticsearch_miscellaneous_content_type?
41
+ Gem::Version.create(Elasticsearch::VERSION) >= Gem::Version.new("9.0.0")
42
+ end
43
+
40
44
  def ilm_existence_endpoint(policy_id)
41
45
  if Gem::Version.new(Elasticsearch::VERSION) >= Gem::Version.new("8.0.0")
42
46
  "_ilm/policy/#{policy_id}"
@@ -90,10 +94,20 @@ class TestElasticsearchIndexLifecycleManagement < Test::Unit::TestCase
90
94
  def test_create_ilm_policy
91
95
  stub_request(:get, "http://localhost:9200/#{ilm_creation_endpoint("fluent-policy")}").
92
96
  to_return(:status => 404, :body => "", :headers => {'x-elastic-product' => 'Elasticsearch'})
93
- stub_request(:put, "http://localhost:9200/#{ilm_creation_endpoint("fluent-policy")}").
94
- with(:body => "{\"policy\":{\"phases\":{\"hot\":{\"actions\":{\"rollover\":{\"max_size\":\"50gb\",\"max_age\":\"30d\"}}}}}}",
95
- :headers => {'Content-Type'=>'application/json'}).
96
- to_return(:status => 200, :body => "", :headers => {'x-elastic-product' => 'Elasticsearch'})
97
+ if elasticsearch_miscellaneous_content_type?
98
+ stub_request(:put, "http://localhost:9200/#{ilm_creation_endpoint("fluent-policy")}").
99
+ with(
100
+ body: "{\"policy\":{\"phases\":{\"hot\":{\"actions\":{\"rollover\":{\"max_size\":\"50gb\",\"max_age\":\"30d\"}}}}}}",
101
+ headers: {
102
+ 'Content-Type'=>'application/vnd.elasticsearch+json; compatible-with=9',
103
+ }).
104
+ to_return(:status => 200, :body => "", :headers => {'x-elastic-product' => 'Elasticsearch'})
105
+ else
106
+ stub_request(:put, "http://localhost:9200/#{ilm_creation_endpoint("fluent-policy")}").
107
+ with(:body => "{\"policy\":{\"phases\":{\"hot\":{\"actions\":{\"rollover\":{\"max_size\":\"50gb\",\"max_age\":\"30d\"}}}}}}",
108
+ :headers => {'Content-Type'=>'application/json'}).
109
+ to_return(:status => 200, :body => "", :headers => {'x-elastic-product' => 'Elasticsearch'})
110
+ end
97
111
  stub_elastic_info
98
112
  create_ilm_policy("fluent-policy")
99
113
 
@@ -65,6 +65,10 @@ class ElasticsearchOutputTest < Test::Unit::TestCase
65
65
  Gem::Version.create(::TRANSPORT_CLASS::VERSION) >= Gem::Version.new("8.0.0")
66
66
  end
67
67
 
68
+ def elasticsearch_miscellaneous_content_type?
69
+ Gem::Version.create(Elasticsearch::VERSION) >= Gem::Version.new("9.0.0")
70
+ end
71
+
68
72
  def default_type_name
69
73
  Fluent::Plugin::ElasticsearchOutput::DEFAULT_TYPE_NAME
70
74
  end
@@ -86,7 +90,13 @@ class ElasticsearchOutputTest < Test::Unit::TestCase
86
90
  end
87
91
 
88
92
  def stub_elastic(url="http://localhost:9200/_bulk")
89
- stub_request(:post, url).with do |req|
93
+ headers = if elasticsearch_miscellaneous_content_type?
94
+ { "Content-Type" => "application/vnd.elasticsearch+x-ndjson; compatible-with=9" }
95
+ else
96
+ {}
97
+ end
98
+
99
+ stub_request(:post, url).with({headers: headers}) do |req|
90
100
  @index_cmds = req.body.split("\n").map {|r| JSON.parse(r) }
91
101
  end.to_return({:status => 200, :body => "", :headers => { 'Content-Type' => 'json', 'x-elastic-product' => 'Elasticsearch' } })
92
102
  end
@@ -3889,7 +3899,12 @@ class ElasticsearchOutputTest < Test::Unit::TestCase
3889
3899
  def test_content_type_header
3890
3900
  stub_request(:head, "http://localhost:9200/").
3891
3901
  to_return(:status => 200, :body => "", :headers => {'x-elastic-product' => 'Elasticsearch'})
3892
- if Elasticsearch::VERSION >= "6.0.2"
3902
+
3903
+ if elasticsearch_miscellaneous_content_type?
3904
+ elastic_request = stub_request(:post, "http://localhost:9200/_bulk").
3905
+ with(headers: { "Content-Type" => "application/vnd.elasticsearch+x-ndjson; compatible-with=9" }).
3906
+ to_return(:status => 200, :body => "", :headers => {'x-elastic-product' => 'Elasticsearch'})
3907
+ elsif Elasticsearch::VERSION >= "6.0.2"
3893
3908
  elastic_request = stub_request(:post, "http://localhost:9200/_bulk").
3894
3909
  with(headers: { "Content-Type" => "application/x-ndjson" }).
3895
3910
  to_return(:status => 200, :body => "", :headers => {'x-elastic-product' => 'Elasticsearch'})
@@ -4007,6 +4022,7 @@ class ElasticsearchOutputTest < Test::Unit::TestCase
4007
4022
  data('Elasticsearch 6' => [6, Fluent::Plugin::ElasticsearchOutput::DEFAULT_TYPE_NAME],
4008
4023
  'Elasticsearch 7' => [7, Fluent::Plugin::ElasticsearchOutput::DEFAULT_TYPE_NAME_ES_7x],
4009
4024
  'Elasticsearch 8' => [8, nil],
4025
+ 'Elasticsearch 9' => [9, nil],
4010
4026
  )
4011
4027
  def test_writes_to_default_type(data)
4012
4028
  version, index_type = data
@@ -5005,7 +5021,8 @@ class ElasticsearchOutputTest < Test::Unit::TestCase
5005
5021
  driver.feed(time.to_i, sample_record.merge({"pipeline_id" => pipeline_id}))
5006
5022
  end
5007
5023
  }
5008
- assert_equal("could not push logs to Elasticsearch cluster ({:host=>\"myhost-1\", :port=>9200, :scheme=>\"http\"}): [503] ", exception.message)
5024
+ params = {:host=> "myhost-1", :port=>9200, :scheme=>"http"}
5025
+ assert_equal("could not push logs to Elasticsearch cluster (#{params}): [503] ", exception.message)
5009
5026
  end
5010
5027
  end
5011
5028
 
@@ -19,6 +19,7 @@ class ElasticsearchOutputDataStreamTest < Test::Unit::TestCase
19
19
  @driver = nil
20
20
  log = Fluent::Engine.log
21
21
  log.out.logs.slice!(0, log.out.logs.length)
22
+ @bulk_meta = []
22
23
  @bulk_records = []
23
24
  end
24
25
 
@@ -87,6 +88,10 @@ class ElasticsearchOutputDataStreamTest < Test::Unit::TestCase
87
88
  {'message' => 'Sample record no timestamp'}
88
89
  end
89
90
 
91
+ def sample_record_with_hash
92
+ {'@timestamp' => SAMPLE_RECORD_TIMESTAMP, 'message' => 'Sample record', '_hash' => 'new_id_value'}
93
+ end
94
+
90
95
  RESPONSE_ACKNOWLEDGED = {"acknowledged": true}
91
96
  DUPLICATED_DATA_STREAM_EXCEPTION = {"error": {}, "status": 400}
92
97
  NONEXISTENT_DATA_STREAM_EXCEPTION = {"error": {}, "status": 404}
@@ -133,6 +138,10 @@ class ElasticsearchOutputDataStreamTest < Test::Unit::TestCase
133
138
  # {"create": {}}\nhttp://localhost:9200/_ilm/policy/foo_ilm_bar
134
139
  # {"@timestamp": ...}
135
140
  ops = req_body.split("\n")
141
+ @bulk_meta += ops.values_at(
142
+ * ops.each_index.select {|i| i.even? }
143
+ ).map{ |i| JSON.parse(i) }
144
+
136
145
  @bulk_records += ops.values_at(
137
146
  * ops.each_index.select {|i| i.odd? }
138
147
  ).map{ |i| JSON.parse(i) }
@@ -1196,4 +1205,73 @@ class ElasticsearchOutputDataStreamTest < Test::Unit::TestCase
1196
1205
  assert_equal 1, @bulk_records.length
1197
1206
  assert(@bulk_records[0].has_key?('@timestamp'))
1198
1207
  end
1208
+
1209
+ def test_id_key_if_value_present_in_record
1210
+ omit REQUIRED_ELASTIC_MESSAGE unless data_stream_supported?
1211
+
1212
+ stub_default
1213
+ stub_bulk_feed
1214
+ conf = config_element(
1215
+ 'ROOT', '', {
1216
+ '@type' => ELASTIC_DATA_STREAM_TYPE,
1217
+ 'data_stream_name' => 'foo',
1218
+ 'data_stream_ilm_name' => 'foo_ilm_policy',
1219
+ 'data_stream_template_name' => 'foo_tpl',
1220
+ 'id_key' => '_hash'
1221
+ })
1222
+ driver(conf).run(default_tag: 'test') do
1223
+ driver.feed(sample_record_with_hash)
1224
+ end
1225
+ assert_equal 1, @bulk_records.length
1226
+ assert_equal 1, @bulk_meta.length
1227
+ assert(@bulk_meta[0].has_key?('create'))
1228
+ assert(@bulk_meta[0]['create'].has_key?('_id'))
1229
+ assert_equal 'new_id_value', @bulk_meta[0]['create']['_id']
1230
+
1231
+ end
1232
+
1233
+ def test_id_key_if_value_not_present_in_record
1234
+ omit REQUIRED_ELASTIC_MESSAGE unless data_stream_supported?
1235
+
1236
+ stub_default
1237
+ stub_bulk_feed
1238
+ conf = config_element(
1239
+ 'ROOT', '', {
1240
+ '@type' => ELASTIC_DATA_STREAM_TYPE,
1241
+ 'data_stream_name' => 'foo',
1242
+ 'data_stream_ilm_name' => 'foo_ilm_policy',
1243
+ 'data_stream_template_name' => 'foo_tpl',
1244
+ 'id_key' => '_hash'
1245
+ })
1246
+ driver(conf).run(default_tag: 'test') do
1247
+ driver.feed(sample_record)
1248
+ end
1249
+ assert_equal 1, @bulk_records.length
1250
+ assert_equal 1, @bulk_meta.length
1251
+ assert(@bulk_meta[0].has_key?('create'))
1252
+ assert_false(@bulk_meta[0]['create'].has_key?('_id'))
1253
+
1254
+ end
1255
+
1256
+ def test_remove_keys_if_key_present_in_record
1257
+ omit REQUIRED_ELASTIC_MESSAGE unless data_stream_supported?
1258
+
1259
+ stub_default
1260
+ stub_bulk_feed
1261
+ conf = config_element(
1262
+ 'ROOT', '', {
1263
+ '@type' => ELASTIC_DATA_STREAM_TYPE,
1264
+ 'data_stream_name' => 'foo',
1265
+ 'data_stream_ilm_name' => 'foo_ilm_policy',
1266
+ 'data_stream_template_name' => 'foo_tpl',
1267
+ 'remove_keys' => '_hash, message'
1268
+ })
1269
+ driver(conf).run(default_tag: 'test') do
1270
+ driver.feed(sample_record_with_hash)
1271
+ end
1272
+ assert_equal 1, @bulk_records.length
1273
+ assert_false(@bulk_records[0].has_key?('_hash'))
1274
+ assert_false(@bulk_records[0].has_key?('message'))
1275
+
1276
+ end
1199
1277
  end
@@ -50,6 +50,10 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
50
50
  Gem::Version.create(::TRANSPORT_CLASS::VERSION) >= Gem::Version.new("8.0.0")
51
51
  end
52
52
 
53
+ def elasticsearch_miscellaneous_content_type?
54
+ Gem::Version.create(Elasticsearch::VERSION) >= Gem::Version.new("9.0.0")
55
+ end
56
+
53
57
  def default_type_name
54
58
  Fluent::Plugin::ElasticsearchOutput::DEFAULT_TYPE_NAME
55
59
  end
@@ -388,7 +392,11 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
388
392
  def test_content_type_header
389
393
  stub_request(:head, "http://localhost:9200/").
390
394
  to_return(:status => 200, :body => "", :headers => {'x-elastic-product' => 'Elasticsearch'})
391
- if Elasticsearch::VERSION >= "6.0.2"
395
+ if elasticsearch_miscellaneous_content_type?
396
+ elastic_request = stub_request(:post, "http://localhost:9200/_bulk").
397
+ with(headers: { "Content-Type" => "application/vnd.elasticsearch+x-ndjson; compatible-with=9" }).
398
+ to_return(:status => 200, :body => "", :headers => {'x-elastic-product' => 'Elasticsearch'})
399
+ elsif Elasticsearch::VERSION >= "6.0.2"
392
400
  elastic_request = stub_request(:post, "http://localhost:9200/_bulk").
393
401
  with(headers: { "Content-Type" => "application/x-ndjson"}).
394
402
  to_return(:status => 200, :body => "", :headers => {'x-elastic-product' => 'Elasticsearch'})
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.4.3
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - diogo
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-01-15 00:00:00.000000000 Z
13
+ date: 2025-05-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: fluentd