fluent-plugin-s3 1.7.1 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.yaml +1 -0
- data/.github/ISSUE_TEMPLATE/feature_request.yaml +1 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/linux.yml +3 -3
- data/.github/workflows/stale-actions.yml +11 -9
- data/ChangeLog +9 -0
- data/VERSION +1 -1
- data/docs/credentials.md +1 -1
- data/docs/howto.md +1 -1
- data/docs/input.md +4 -0
- data/fluent-plugin-s3.gemspec +1 -0
- data/lib/fluent/plugin/in_s3.rb +23 -5
- data/lib/fluent/plugin/out_s3.rb +2 -2
- data/lib/fluent/plugin/s3_compressor_zstd.rb +30 -0
- data/test/test_in_s3.rb +49 -3
- data/test/test_out_s3.rb +39 -0
- metadata +22 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c72b8fcce805d79141dededa99e19fe802a27b169f4f39b6f842dfc2829daab
|
4
|
+
data.tar.gz: eb62e090ec39010bf6f2598c827d875ae0032dccc14b71607dcd92fa80082d0e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53e0911c336861aa4dddb73e9f0f5f58fa78d8d8434a217e55f2532fbb264c7ec7e894cc9f1cfd1abc0452f065954099658420bf435dd5bfe7a8a402ecab0e25
|
7
|
+
data.tar.gz: 3916876756d629413c80a6a24f428ff6a453e284a235d0805853b4b01b7bfb6f7866426342c5a598d00a53fe3ee2daf46ac90f4ba04577f762bc3fbabfef1e7f
|
data/.github/workflows/linux.yml
CHANGED
@@ -10,12 +10,12 @@ jobs:
|
|
10
10
|
strategy:
|
11
11
|
fail-fast: false
|
12
12
|
matrix:
|
13
|
-
ruby: [ '3.1', '3.0', '2.7' ]
|
13
|
+
ruby: [ '3.2', '3.1', '3.0', '2.7' ]
|
14
14
|
os:
|
15
15
|
- ubuntu-latest
|
16
16
|
name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }}
|
17
17
|
steps:
|
18
|
-
- uses: actions/checkout@
|
18
|
+
- uses: actions/checkout@v4
|
19
19
|
- uses: ruby/setup-ruby@v1
|
20
20
|
with:
|
21
21
|
ruby-version: ${{ matrix.ruby }}
|
@@ -23,6 +23,6 @@ jobs:
|
|
23
23
|
env:
|
24
24
|
CI: true
|
25
25
|
run: |
|
26
|
-
gem install
|
26
|
+
gem install rake
|
27
27
|
bundle install --jobs 4 --retry 3
|
28
28
|
bundle exec rake test
|
@@ -7,16 +7,18 @@ jobs:
|
|
7
7
|
stale:
|
8
8
|
runs-on: ubuntu-latest
|
9
9
|
steps:
|
10
|
-
- uses: actions/stale@
|
10
|
+
- uses: actions/stale@v8
|
11
11
|
with:
|
12
12
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
13
|
-
days-before-stale:
|
14
|
-
days-before-close:
|
15
|
-
stale-issue-message: "This issue has been automatically marked as stale because it has been open
|
16
|
-
stale-pr-message: "This PR has been automatically marked as stale because it has been open
|
17
|
-
close-issue-message: "This issue was automatically closed because of stale in
|
18
|
-
close-pr-message: "This PR was automatically closed because of stale in
|
13
|
+
days-before-stale: 30
|
14
|
+
days-before-close: 7
|
15
|
+
stale-issue-message: "This issue has been automatically marked as stale because it has been open 30 days with no activity. Remove stale label or comment or this issue will be closed in 7 days"
|
16
|
+
stale-pr-message: "This PR has been automatically marked as stale because it has been open 30 days with no activity. Remove stale label or comment or this PR will be closed in 7 days"
|
17
|
+
close-issue-message: "This issue was automatically closed because of stale in 7 days"
|
18
|
+
close-pr-message: "This PR was automatically closed because of stale in 7 days"
|
19
19
|
stale-pr-label: "stale"
|
20
20
|
stale-issue-label: "stale"
|
21
|
-
exempt-issue-labels: "bug,help wanted,enhancement"
|
22
|
-
exempt-pr-labels: "bug,help wanted,enhancement"
|
21
|
+
exempt-issue-labels: "waiting-for-triage,bug,help wanted,enhancement"
|
22
|
+
exempt-pr-labels: "waiting-for-triage,bug,help wanted,enhancement"
|
23
|
+
exempt-all-assignees: true
|
24
|
+
exempt-all-milestones: true
|
data/ChangeLog
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
Release 1.8.0 - 2024/11/06
|
2
|
+
|
3
|
+
* out_s3: Add zstd compression support
|
4
|
+
|
5
|
+
Release 1.7.2 - 2022/10/19
|
6
|
+
|
7
|
+
* in_s3: Add `event_bridge_mode` parameter
|
8
|
+
* out_s3: Fix `s3_object_key_format` check to allow `%{hex_random}` as well as `%{uuid_flush}` or `${chunk_id}`
|
9
|
+
|
1
10
|
Release 1.7.1 - 2022/07/15
|
2
11
|
|
3
12
|
* in_s3: Add `match_regexp` parameter to selectively download S3 files based on the object key
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.8.0
|
data/docs/credentials.md
CHANGED
data/docs/howto.md
CHANGED
@@ -7,7 +7,7 @@ downstream processors to better identify the source of a given record.
|
|
7
7
|
|
8
8
|
# IAM Policy
|
9
9
|
|
10
|
-
The following is an example for a IAM policy needed to write to an s3 bucket (matches my-s3bucket/logs, my-s3bucket
|
10
|
+
The following is an example for a IAM policy needed to write to an s3 bucket (matches my-s3bucket/logs, my-s3bucket/test, etc.).
|
11
11
|
|
12
12
|
{
|
13
13
|
"Version": "2012-10-17",
|
data/docs/input.md
CHANGED
@@ -101,3 +101,7 @@ The long polling interval. Default is 20.
|
|
101
101
|
### retry_error_interval
|
102
102
|
|
103
103
|
Interval to retry polling SQS if polling unsuccessful, in seconds. Default is 300.
|
104
|
+
|
105
|
+
### event_bridge_mode
|
106
|
+
When true, Amazon S3 Event Notification should be configured using the EventBridge integration. Default is false.
|
107
|
+
See [Configure S3 event notification using EventBridge](https://docs.aws.amazon.com/AmazonS3/latest/userguide/EventBridge.html) for additional information.
|
data/fluent-plugin-s3.gemspec
CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.add_dependency "fluentd", [">= 0.14.22", "< 2"]
|
20
20
|
gem.add_dependency "aws-sdk-s3", "~> 1.60"
|
21
21
|
gem.add_dependency "aws-sdk-sqs", "~> 1.23"
|
22
|
+
gem.add_dependency 'zstd-ruby'
|
22
23
|
gem.add_development_dependency "rake", ">= 0.9.2"
|
23
24
|
gem.add_development_dependency "test-unit", ">= 3.0.8"
|
24
25
|
gem.add_development_dependency "test-unit-rr", ">= 1.0.3"
|
data/lib/fluent/plugin/in_s3.rb
CHANGED
@@ -110,6 +110,8 @@ module Fluent::Plugin
|
|
110
110
|
config_param :wait_time_seconds, :integer, default: 20
|
111
111
|
desc "Polling error retry interval."
|
112
112
|
config_param :retry_error_interval, :integer, default: 300
|
113
|
+
desc "Event bridge mode"
|
114
|
+
config_param :event_bridge_mode, :bool, default: false
|
113
115
|
end
|
114
116
|
|
115
117
|
desc "Tag string"
|
@@ -205,10 +207,9 @@ module Fluent::Plugin
|
|
205
207
|
begin
|
206
208
|
body = Yajl.load(message.body)
|
207
209
|
log.debug(body)
|
208
|
-
next unless body
|
210
|
+
next unless is_valid_queue(body) # skip test queue
|
209
211
|
if @match_regexp
|
210
|
-
|
211
|
-
raw_key = s3["object"]["key"]
|
212
|
+
raw_key = get_raw_key(body)
|
212
213
|
key = CGI.unescape(raw_key)
|
213
214
|
next unless @match_regexp.match?(key)
|
214
215
|
end
|
@@ -226,6 +227,24 @@ module Fluent::Plugin
|
|
226
227
|
end
|
227
228
|
end
|
228
229
|
|
230
|
+
def is_valid_queue(body)
|
231
|
+
if @sqs.event_bridge_mode
|
232
|
+
log.debug("checking for eventbridge property")
|
233
|
+
!!body["detail"]
|
234
|
+
else
|
235
|
+
log.debug("checking for Records property")
|
236
|
+
!!body["Records"]
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def get_raw_key(body)
|
241
|
+
if @sqs.event_bridge_mode
|
242
|
+
body["detail"]["object"]["key"]
|
243
|
+
else
|
244
|
+
body["Records"].first["s3"]["object"]["key"]
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
229
248
|
def setup_credentials
|
230
249
|
options = {}
|
231
250
|
credentials_options = {}
|
@@ -318,8 +337,7 @@ module Fluent::Plugin
|
|
318
337
|
end
|
319
338
|
|
320
339
|
def process(body)
|
321
|
-
|
322
|
-
raw_key = s3["object"]["key"]
|
340
|
+
raw_key = get_raw_key(body)
|
323
341
|
key = CGI.unescape(raw_key)
|
324
342
|
|
325
343
|
io = @bucket.object(key).get.body
|
data/lib/fluent/plugin/out_s3.rb
CHANGED
@@ -471,8 +471,8 @@ module Fluent::Plugin
|
|
471
471
|
end
|
472
472
|
|
473
473
|
is_working_on_parallel = @buffer_config.flush_thread_count > 1 || system_config.workers > 1
|
474
|
-
if is_working_on_parallel && ['${chunk_id}', '%{uuid_flush}'].none? { |key| @s3_object_key_format.include?(key) }
|
475
|
-
log.warn "No ${chunk_id} or %{
|
474
|
+
if is_working_on_parallel && ['${chunk_id}', '%{uuid_flush}', '%{hex_random}'].none? { |key| @s3_object_key_format.include?(key) }
|
475
|
+
log.warn "No ${chunk_id}, %{uuid_flush} or %{hex_random} in s3_object_key_format with multiple flush threads or multiple workers. Recommend to set ${chunk_id}, %{uuid_flush} or %{hex_random} to avoid data lost by object conflict"
|
476
476
|
end
|
477
477
|
end
|
478
478
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'zstd-ruby'
|
2
|
+
|
3
|
+
module Fluent::Plugin
|
4
|
+
class S3Output
|
5
|
+
class ZstdCompressor < Compressor
|
6
|
+
S3Output.register_compressor('zstd', self)
|
7
|
+
|
8
|
+
config_section :compress, param_name: :compress_config, init: true, multi: false do
|
9
|
+
desc "Compression level for zstd (1-22)"
|
10
|
+
config_param :level, :integer, default: 3
|
11
|
+
end
|
12
|
+
|
13
|
+
def ext
|
14
|
+
'zst'.freeze
|
15
|
+
end
|
16
|
+
|
17
|
+
def content_type
|
18
|
+
'application/x-zst'.freeze
|
19
|
+
end
|
20
|
+
|
21
|
+
def compress(chunk, tmp)
|
22
|
+
compressed = Zstd.compress(chunk.read, level: @compress_config.level)
|
23
|
+
tmp.write(compressed)
|
24
|
+
rescue => e
|
25
|
+
log.warn "zstd compression failed: #{e.message}"
|
26
|
+
raise
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/test/test_in_s3.rb
CHANGED
@@ -166,9 +166,9 @@ buffer_type memory
|
|
166
166
|
aws_key_id sqs_test_key_id
|
167
167
|
</sqs>
|
168
168
|
EOS
|
169
|
-
|
170
|
-
|
171
|
-
|
169
|
+
create_driver(conf)
|
170
|
+
}
|
171
|
+
end
|
172
172
|
|
173
173
|
def test_sqs_with_invalid_aws_keys_missing_key_id
|
174
174
|
assert_raise(Fluent::ConfigError, "sqs/aws_key_id or sqs/aws_sec_key is missing") {
|
@@ -677,4 +677,50 @@ EOS
|
|
677
677
|
d.run {}
|
678
678
|
end
|
679
679
|
end
|
680
|
+
|
681
|
+
def test_event_bridge_mode
|
682
|
+
setup_mocks
|
683
|
+
d = create_driver("
|
684
|
+
aws_key_id test_key_id
|
685
|
+
aws_sec_key test_sec_key
|
686
|
+
s3_bucket test_bucket
|
687
|
+
buffer_type memory
|
688
|
+
check_apikey_on_start false
|
689
|
+
store_as text
|
690
|
+
format none
|
691
|
+
<sqs>
|
692
|
+
event_bridge_mode true
|
693
|
+
queue_name test_queue
|
694
|
+
queue_owner_aws_account_id 123456789123
|
695
|
+
</sqs>
|
696
|
+
")
|
697
|
+
|
698
|
+
s3_object = stub(Object.new)
|
699
|
+
s3_response = stub(Object.new)
|
700
|
+
s3_response.body { StringIO.new("aaa") }
|
701
|
+
s3_object.get { s3_response }
|
702
|
+
@s3_bucket.object(anything).at_least(1) { s3_object }
|
703
|
+
|
704
|
+
body = {
|
705
|
+
"detail" => {
|
706
|
+
"object" => {
|
707
|
+
"key" => "test_key"
|
708
|
+
}
|
709
|
+
}
|
710
|
+
}
|
711
|
+
|
712
|
+
message = Struct::StubMessage.new(1, 1, Yajl.dump(body))
|
713
|
+
@sqs_poller.get_messages(anything, anything) do |config, stats|
|
714
|
+
config.before_request.call(stats) if config.before_request
|
715
|
+
stats.request_count += 1
|
716
|
+
if stats.request_count >= 1
|
717
|
+
d.instance.instance_variable_set(:@running, false)
|
718
|
+
end
|
719
|
+
[message]
|
720
|
+
end
|
721
|
+
d.run(expect_emits: 1)
|
722
|
+
events = d.events
|
723
|
+
assert_equal({ "message" => "aaa" }, events.first[2])
|
724
|
+
end
|
725
|
+
|
680
726
|
end
|
data/test/test_out_s3.rb
CHANGED
@@ -109,6 +109,18 @@ class S3OutputTest < Test::Unit::TestCase
|
|
109
109
|
assert(e.is_a?(Fluent::ConfigError))
|
110
110
|
end
|
111
111
|
|
112
|
+
data('level default' => nil,
|
113
|
+
'level 1' => 1)
|
114
|
+
def test_configure_with_mime_type_zstd(level)
|
115
|
+
conf = CONFIG.clone
|
116
|
+
conf << "\nstore_as zstd\n"
|
117
|
+
conf << "\n<compress>\nlevel #{level}\n</compress>\n" if level
|
118
|
+
d = create_driver(conf)
|
119
|
+
assert_equal 'zst', d.instance.instance_variable_get(:@compressor).ext
|
120
|
+
assert_equal 'application/x-zst', d.instance.instance_variable_get(:@compressor).content_type
|
121
|
+
assert_equal (level || 3), d.instance.instance_variable_get(:@compressor).instance_variable_get(:@compress_config).level
|
122
|
+
end
|
123
|
+
|
112
124
|
def test_configure_with_path_style
|
113
125
|
conf = CONFIG.clone
|
114
126
|
conf << "\nforce_path_style true\n"
|
@@ -456,6 +468,33 @@ EOC
|
|
456
468
|
FileUtils.rm_f(s3_local_file_path)
|
457
469
|
end
|
458
470
|
|
471
|
+
def test_write_with_zstd
|
472
|
+
setup_mocks(true)
|
473
|
+
s3_local_file_path = "/tmp/s3-test.zst"
|
474
|
+
|
475
|
+
expected_s3path = "log/events/ts=20110102-13/events_0-#{Socket.gethostname}.zst"
|
476
|
+
|
477
|
+
setup_s3_object_mocks(s3_local_file_path: s3_local_file_path, s3path: expected_s3path)
|
478
|
+
|
479
|
+
config = CONFIG_TIME_SLICE + "\nstore_as zstd\n"
|
480
|
+
d = create_time_sliced_driver(config)
|
481
|
+
|
482
|
+
time = event_time("2011-01-02 13:14:15 UTC")
|
483
|
+
d.run(default_tag: "test") do
|
484
|
+
d.feed(time, { "a" => 1 })
|
485
|
+
d.feed(time, { "a" => 2 })
|
486
|
+
end
|
487
|
+
|
488
|
+
File.open(s3_local_file_path, 'rb') do |file|
|
489
|
+
compressed_data = file.read
|
490
|
+
uncompressed_data = Zstd.decompress(compressed_data)
|
491
|
+
expected_data = %[2011-01-02T13:14:15Z\ttest\t{"a":1}\n] +
|
492
|
+
%[2011-01-02T13:14:15Z\ttest\t{"a":2}\n]
|
493
|
+
assert_equal expected_data, uncompressed_data
|
494
|
+
end
|
495
|
+
FileUtils.rm_f(s3_local_file_path)
|
496
|
+
end
|
497
|
+
|
459
498
|
class MockResponse
|
460
499
|
attr_reader :data
|
461
500
|
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-s3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sadayuki Furuhashi
|
8
8
|
- Masahiro Nakagawa
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2024-11-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fluentd
|
@@ -59,6 +59,20 @@ dependencies:
|
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '1.23'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: zstd-ruby
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
type: :runtime
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
62
76
|
- !ruby/object:Gem::Dependency
|
63
77
|
name: rake
|
64
78
|
requirement: !ruby/object:Gem::Requirement
|
@@ -138,6 +152,7 @@ files:
|
|
138
152
|
- ".github/ISSUE_TEMPLATE/bug_report.yaml"
|
139
153
|
- ".github/ISSUE_TEMPLATE/config.yml"
|
140
154
|
- ".github/ISSUE_TEMPLATE/feature_request.yaml"
|
155
|
+
- ".github/dependabot.yml"
|
141
156
|
- ".github/workflows/linux.yml"
|
142
157
|
- ".github/workflows/stale-actions.yml"
|
143
158
|
- ".gitignore"
|
@@ -162,6 +177,7 @@ files:
|
|
162
177
|
- lib/fluent/plugin/s3_compressor_lzma2.rb
|
163
178
|
- lib/fluent/plugin/s3_compressor_lzo.rb
|
164
179
|
- lib/fluent/plugin/s3_compressor_parquet.rb
|
180
|
+
- lib/fluent/plugin/s3_compressor_zstd.rb
|
165
181
|
- lib/fluent/plugin/s3_extractor_gzip_command.rb
|
166
182
|
- lib/fluent/plugin/s3_extractor_lzma2.rb
|
167
183
|
- lib/fluent/plugin/s3_extractor_lzo.rb
|
@@ -171,7 +187,7 @@ homepage: https://github.com/fluent/fluent-plugin-s3
|
|
171
187
|
licenses:
|
172
188
|
- Apache-2.0
|
173
189
|
metadata: {}
|
174
|
-
post_install_message:
|
190
|
+
post_install_message:
|
175
191
|
rdoc_options: []
|
176
192
|
require_paths:
|
177
193
|
- lib
|
@@ -186,8 +202,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
202
|
- !ruby/object:Gem::Version
|
187
203
|
version: '0'
|
188
204
|
requirements: []
|
189
|
-
rubygems_version: 3.
|
190
|
-
signing_key:
|
205
|
+
rubygems_version: 3.5.22
|
206
|
+
signing_key:
|
191
207
|
specification_version: 4
|
192
208
|
summary: Amazon S3 output plugin for Fluentd event collector
|
193
209
|
test_files: []
|