logstash-output-s3-zst 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,451 @@
1
+ :plugin: s3
2
+ :type: output
3
+ :default_codec: line
4
+
5
+ ///////////////////////////////////////////
6
+ START - GENERATED VARIABLES, DO NOT EDIT!
7
+ ///////////////////////////////////////////
8
+ :version: %VERSION%
9
+ :release_date: %RELEASE_DATE%
10
+ :changelog_url: %CHANGELOG_URL%
11
+ :include_path: ../../../../logstash/docs/include
12
+ ///////////////////////////////////////////
13
+ END - GENERATED VARIABLES, DO NOT EDIT!
14
+ ///////////////////////////////////////////
15
+
16
+ [id="plugins-{type}s-{plugin}"]
17
+
18
+ === S3 output plugin
19
+
20
+ include::{include_path}/plugin_header.asciidoc[]
21
+
22
+ ==== Description
23
+
24
+ This plugin batches and uploads logstash events into Amazon Simple Storage
25
+ Service (Amazon S3).
26
+
27
+ IMPORTANT: The S3 output plugin only supports AWS S3.
28
+ Other S3 compatible storage solutions are not supported.
29
+
30
+ S3 outputs create temporary files into the OS' temporary directory.
31
+ You can specify where to save them using the `temporary_directory` option.
32
+
33
+ IMPORTANT: For configurations containing multiple s3 outputs with the `restore`
34
+ option enabled, each output should define its own `temporary_directory`.
35
+ Shared or nested directories can cause data loss upon recovery.
36
+
37
+ ===== Requirements
38
+
39
+ * Amazon S3 Bucket and S3 Access Permissions (Typically access_key_id and secret_access_key)
40
+ * S3 PutObject permission
41
+
42
+ ===== S3 output file
43
+
44
+ [source,txt]
45
+ -----
46
+ `ls.s3.312bc026-2f5d-49bc-ae9f-5940cf4ad9a6.2013-04-18T10.00.tag_hello.part0.txt`
47
+ -----
48
+
49
+ |=======
50
+ | ls.s3 | indicates logstash plugin s3 |
51
+ | 312bc026-2f5d-49bc-ae9f-5940cf4ad9a6 | a new, random uuid per file. |
52
+ | 2013-04-18T10.00 | represents the time whenever you specify time_file. |
53
+ | tag_hello | indicates the event's tag. |
54
+ | part0 | If you indicate size_file, it will generate more parts if your file.size > size_file.
55
+ When a file is full, it gets pushed to the bucket and then deleted from the temporary directory.
56
+ If a file is empty, it is simply deleted. Empty files will not be pushed. |
57
+ |=======
58
+
59
+ ===== Crash Recovery
60
+
61
+ This plugin will recover and upload temporary log files after crash/abnormal termination when using `restore` set to true
62
+
63
+ ===== Usage
64
+ This is an example of logstash config:
65
+ [source,ruby]
66
+ output {
67
+ s3{
68
+ access_key_id => "crazy_key" (optional)
69
+ secret_access_key => "monkey_access_key" (optional)
70
+ region => "eu-west-1" (optional, default = "us-east-1")
71
+ bucket => "your_bucket" (required)
72
+ size_file => 2048 (optional) - Bytes
73
+ time_file => 5 (optional) - Minutes
74
+ codec => "plain" (optional)
75
+ canned_acl => "private" (optional. Options are "private", "public-read", "public-read-write", "authenticated-read", "aws-exec-read", "bucket-owner-read", "bucket-owner-full-control", "log-delivery-write". Defaults to "private" )
76
+ }
77
+
78
+
79
+ [id="plugins-{type}s-{plugin}-options"]
80
+ ==== S3 Output Configuration Options
81
+
82
+ This plugin supports the following configuration options plus the <<plugins-{type}s-{plugin}-common-options>> described later.
83
+
84
+ [cols="<,<,<",options="header",]
85
+ |=======================================================================
86
+ |Setting |Input type|Required
87
+ | <<plugins-{type}s-{plugin}-access_key_id>> |<<string,string>>|No
88
+ | <<plugins-{type}s-{plugin}-additional_settings>> |<<hash,hash>>|No
89
+ | <<plugins-{type}s-{plugin}-aws_credentials_file>> |<<string,string>>|No
90
+ | <<plugins-{type}s-{plugin}-bucket>> |<<string,string>>|Yes
91
+ | <<plugins-{type}s-{plugin}-canned_acl>> |<<string,string>>, one of `["private", "public-read", "public-read-write", "authenticated-read", "aws-exec-read", "bucket-owner-read", "bucket-owner-full-control", "log-delivery-write"]`|No
92
+ | <<plugins-{type}s-{plugin}-encoding>> |<<string,string>>, one of `["none", "gzip"]`|No
93
+ | <<plugins-{type}s-{plugin}-endpoint>> |<<string,string>>|No
94
+ | <<plugins-{type}s-{plugin}-prefix>> |<<string,string>>|No
95
+ | <<plugins-{type}s-{plugin}-proxy_uri>> |<<string,string>>|No
96
+ | <<plugins-{type}s-{plugin}-region>> |<<string,string>>|No
97
+ | <<plugins-{type}s-{plugin}-restore>> |<<boolean,boolean>>|No
98
+ | <<plugins-{type}s-{plugin}-retry_count>> |<<number,number>>|No
99
+ | <<plugins-{type}s-{plugin}-retry_delay>> |<<number,number>>|No
100
+ | <<plugins-{type}s-{plugin}-role_arn>> |<<string,string>>|No
101
+ | <<plugins-{type}s-{plugin}-role_session_name>> |<<string,string>>|No
102
+ | <<plugins-{type}s-{plugin}-rotation_strategy>> |<<string,string>>, one of `["size_and_time", "size", "time"]`|No
103
+ | <<plugins-{type}s-{plugin}-secret_access_key>> |<<string,string>>|No
104
+ | <<plugins-{type}s-{plugin}-server_side_encryption>> |<<boolean,boolean>>|No
105
+ | <<plugins-{type}s-{plugin}-server_side_encryption_algorithm>> |<<string,string>>, one of `["AES256", "aws:kms"]`|No
106
+ | <<plugins-{type}s-{plugin}-session_token>> |<<string,string>>|No
107
+ | <<plugins-{type}s-{plugin}-signature_version>> |<<string,string>>, one of `["v2", "v4"]`|No
108
+ | <<plugins-{type}s-{plugin}-size_file>> |<<number,number>>|No
109
+ | <<plugins-{type}s-{plugin}-ssekms_key_id>> |<<string,string>>|No
110
+ | <<plugins-{type}s-{plugin}-storage_class>> |<<string,string>>, one of `["STANDARD", "REDUCED_REDUNDANCY", "STANDARD_IA", "ONEZONE_IA"]`|No
111
+ | <<plugins-{type}s-{plugin}-temporary_directory>> |<<string,string>>|No
112
+ | <<plugins-{type}s-{plugin}-time_file>> |<<number,number>>|No
113
+ | <<plugins-{type}s-{plugin}-upload_multipart_threshold>> |<<number,number>>|No
114
+ | <<plugins-{type}s-{plugin}-upload_queue_size>> |<<number,number>>|No
115
+ | <<plugins-{type}s-{plugin}-upload_workers_count>> |<<number,number>>|No
116
+ | <<plugins-{type}s-{plugin}-validate_credentials_on_root_bucket>> |<<boolean,boolean>>|No
117
+ |=======================================================================
118
+
119
+ Also see <<plugins-{type}s-{plugin}-common-options>> for a list of options supported by all
120
+ output plugins.
121
+
122
+ &nbsp;
123
+
124
+ [id="plugins-{type}s-{plugin}-access_key_id"]
125
+ ===== `access_key_id`
126
+
127
+ * Value type is <<string,string>>
128
+ * There is no default value for this setting.
129
+
130
+ This plugin uses the AWS SDK and supports several ways to get credentials, which will be tried in this order:
131
+
132
+ . Static configuration, using `access_key_id` and `secret_access_key` params in logstash plugin config
133
+ . External credentials file specified by `aws_credentials_file`
134
+ . Environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`
135
+ . Environment variables `AMAZON_ACCESS_KEY_ID` and `AMAZON_SECRET_ACCESS_KEY`
136
+ . IAM Instance Profile (available when running inside EC2)
137
+
138
+ [id="plugins-{type}s-{plugin}-additional_settings"]
139
+ ===== `additional_settings`
140
+
141
+ * Value type is <<hash,hash>>
142
+ * Default value is `{}`
143
+
144
+ Key-value pairs of settings and corresponding values used to parametrize
145
+ the connection to S3. See full list in https://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Client.html[the AWS SDK documentation]. Example:
146
+
147
+ [source,ruby]
148
+ output {
149
+ s3 {
150
+ access_key_id => "1234",
151
+ secret_access_key => "secret",
152
+ region => "eu-west-1",
153
+ bucket => "logstash-test",
154
+ additional_settings => {
155
+ "force_path_style" => true,
156
+ "follow_redirects" => false
157
+ }
158
+ }
159
+ }
160
+
161
+ [id="plugins-{type}s-{plugin}-aws_credentials_file"]
162
+ ===== `aws_credentials_file`
163
+
164
+ * Value type is <<string,string>>
165
+ * There is no default value for this setting.
166
+
167
+ Path to YAML file containing a hash of AWS credentials.
168
+ This file will only be loaded if `access_key_id` and
169
+ `secret_access_key` aren't set. The contents of the
170
+ file should look like this:
171
+
172
+ [source,ruby]
173
+ ----------------------------------
174
+ :access_key_id: "12345"
175
+ :secret_access_key: "54321"
176
+ ----------------------------------
177
+
178
+
179
+ [id="plugins-{type}s-{plugin}-bucket"]
180
+ ===== `bucket`
181
+
182
+ * This is a required setting.
183
+ * Value type is <<string,string>>
184
+ * There is no default value for this setting.
185
+
186
+ S3 bucket
187
+
188
+ [id="plugins-{type}s-{plugin}-canned_acl"]
189
+ ===== `canned_acl`
190
+
191
+ * Value can be any of: `private`, `public-read`, `public-read-write`, `authenticated-read`, `aws-exec-read`, `bucket-owner-read`, `bucket-owner-full-control`, `log-delivery-write`
192
+ * Default value is `"private"`
193
+
194
+ The S3 canned ACL to use when putting the file. Defaults to "private".
195
+
196
+ [id="plugins-{type}s-{plugin}-encoding"]
197
+ ===== `encoding`
198
+
199
+ * Value can be any of: `none`, `gzip`
200
+ * Default value is `"none"`
201
+
202
+ Specify the content encoding. Supports ("gzip"). Defaults to "none"
203
+
204
+ [id="plugins-{type}s-{plugin}-endpoint"]
205
+ ===== `endpoint`
206
+
207
+ * Value type is <<string,string>>
208
+ * There is no default value for this setting.
209
+
210
+ The endpoint to connect to. By default it is constructed using the value of `region`.
211
+ This is useful when connecting to S3 compatible services, but beware that these aren't
212
+ guaranteed to work correctly with the AWS SDK.
213
+ The endpoint should be an HTTP or HTTPS URL, e.g. https://example.com
214
+
215
+ [id="plugins-{type}s-{plugin}-prefix"]
216
+ ===== `prefix`
217
+
218
+ * Value type is <<string,string>>
219
+ * Default value is `""`
220
+
221
+ Specify a prefix to the uploaded filename to simulate directories on S3.
222
+ Prefix does not require leading slash.
223
+ This option supports
224
+ {logstash-ref}/event-dependent-configuration.html#sprintf[Logstash
225
+ interpolation]. For example, files can be prefixed with the event date using
226
+ `prefix = "%{+YYYY}/%{+MM}/%{+dd}"`.
227
+
228
+ IMPORTANT: Take care when you are using interpolated strings in prefixes. This
229
+ has the potential to create large numbers of unique prefixes, causing large
230
+ numbers of in-progress uploads. This scenario may result in performance and
231
+ stability issues, which can be further exacerbated when you use a
232
+ rotation_strategy that delays uploads.
233
+
234
+ [id="plugins-{type}s-{plugin}-proxy_uri"]
235
+ ===== `proxy_uri`
236
+
237
+ * Value type is <<string,string>>
238
+ * There is no default value for this setting.
239
+
240
+ URI to proxy server if required
241
+
242
+ [id="plugins-{type}s-{plugin}-region"]
243
+ ===== `region`
244
+
245
+ * Value type is <<string,string>>
246
+ * Default value is `"us-east-1"`
247
+
248
+ The AWS Region
249
+
250
+ [id="plugins-{type}s-{plugin}-restore"]
251
+ ===== `restore`
252
+
253
+ * Value type is <<boolean,boolean>>
254
+ * Default value is `true`
255
+
256
+ Used to enable recovery after crash/abnormal termination.
257
+ Temporary log files will be recovered and uploaded.
258
+
259
+ NOTE: If you're using multiple S3 outputs, always set
260
+ <<plugins-{type}s-{plugin}-temporary_directory>> to a
261
+ unique directory. Otherwise the recovery mechanism won't work correctly.
262
+
263
+ [id="plugins-{type}s-{plugin}-retry_count"]
264
+ ===== `retry_count`
265
+
266
+ * Value type is <<number,number>>
267
+ * Default value is `Infinity`
268
+
269
+ Allows to limit number of retries when S3 uploading fails.
270
+
271
+ [id="plugins-{type}s-{plugin}-retry_delay"]
272
+ ===== `retry_delay`
273
+
274
+ * Value type is <<number,number>>
275
+ * Default value is `1`
276
+
277
+ Delay (in seconds) to wait between consecutive retries on upload failures.
278
+
279
+ [id="plugins-{type}s-{plugin}-role_arn"]
280
+ ===== `role_arn`
281
+
282
+ * Value type is <<string,string>>
283
+ * There is no default value for this setting.
284
+
285
+ The AWS IAM Role to assume, if any.
286
+ This is used to generate temporary credentials, typically for cross-account access.
287
+ See the https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html[AssumeRole API documentation] for more information.
288
+
289
+ [id="plugins-{type}s-{plugin}-role_session_name"]
290
+ ===== `role_session_name`
291
+
292
+ * Value type is <<string,string>>
293
+ * Default value is `"logstash"`
294
+
295
+ Session name to use when assuming an IAM role.
296
+
297
+ [id="plugins-{type}s-{plugin}-rotation_strategy"]
298
+ ===== `rotation_strategy`
299
+
300
+ * Value can be any of: `size_and_time`, `size`, `time`
301
+ * Default value is `"size_and_time"`
302
+
303
+ Controls when to close the file and push it to S3.
304
+
305
+ If you set this value to `size`, it uses the value set in
306
+ <<plugins-{type}s-{plugin}-size_file,`size_file`>>.
307
+ If you set this value to `time`, it uses the value set in
308
+ <<plugins-{type}s-{plugin}-time_file,`time_file`>>.
309
+ If you set this value to `size_and_time`, it uses the values from
310
+ <<plugins-{type}s-{plugin}-size_file,`size_file`>> and
311
+ <<plugins-{type}s-{plugin}-time_file,`time_file`>>, and splits the file when
312
+ either one matches.
313
+
314
+ The default strategy checks both size and time. The first value to
315
+ match triggers file rotation.
316
+
317
+ [id="plugins-{type}s-{plugin}-secret_access_key"]
318
+ ===== `secret_access_key`
319
+
320
+ * Value type is <<string,string>>
321
+ * There is no default value for this setting.
322
+
323
+ The AWS Secret Access Key
324
+
325
+ [id="plugins-{type}s-{plugin}-server_side_encryption"]
326
+ ===== `server_side_encryption`
327
+
328
+ * Value type is <<boolean,boolean>>
329
+ * Default value is `false`
330
+
331
+ Specifies whether or not to use S3's server side encryption. Defaults to no encryption.
332
+
333
+ [id="plugins-{type}s-{plugin}-server_side_encryption_algorithm"]
334
+ ===== `server_side_encryption_algorithm`
335
+
336
+ * Value can be any of: `AES256`, `aws:kms`
337
+ * Default value is `"AES256"`
338
+
339
+ Specifies what type of encryption to use when SSE is enabled.
340
+
341
+ [id="plugins-{type}s-{plugin}-session_token"]
342
+ ===== `session_token`
343
+
344
+ * Value type is <<string,string>>
345
+ * There is no default value for this setting.
346
+
347
+ The AWS Session token for temporary credential
348
+
349
+ [id="plugins-{type}s-{plugin}-signature_version"]
350
+ ===== `signature_version`
351
+
352
+ * Value can be any of: `v2`, `v4`
353
+ * There is no default value for this setting.
354
+
355
+ The version of the S3 signature hash to use. Normally uses the internal client default, can be explicitly
356
+ specified here
357
+
358
+ [id="plugins-{type}s-{plugin}-size_file"]
359
+ ===== `size_file`
360
+
361
+ * Value type is <<number,number>>
362
+ * Default value is `5242880`
363
+
364
+ Set the file size in bytes. When the number of bytes exceeds the `size_file`
365
+ value, a new file is created. If you use tags, Logstash generates a specific size
366
+ file for every tag.
367
+
368
+ [id="plugins-{type}s-{plugin}-ssekms_key_id"]
369
+ ===== `ssekms_key_id`
370
+
371
+ * Value type is <<string,string>>
372
+ * There is no default value for this setting.
373
+
374
+ The key to use when specified along with server_side_encryption => aws:kms.
375
+ If server_side_encryption => aws:kms is set but this is not default KMS key is used.
376
+ http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingKMSEncryption.html
377
+
378
+ [id="plugins-{type}s-{plugin}-storage_class"]
379
+ ===== `storage_class`
380
+
381
+ * Value can be any of: `STANDARD`, `REDUCED_REDUNDANCY`, `STANDARD_IA`, `ONEZONE_IA`
382
+ * Default value is `"STANDARD"`
383
+
384
+ Specifies what S3 storage class to use when uploading the file.
385
+ More information about the different storage classes can be found:
386
+ http://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html
387
+ Defaults to STANDARD.
388
+
389
+ [id="plugins-{type}s-{plugin}-temporary_directory"]
390
+ ===== `temporary_directory`
391
+
392
+ * Value type is <<string,string>>
393
+ * Default value is `"/tmp/logstash"`
394
+
395
+ Set the directory where logstash will store the tmp files before sending it to S3
396
+ default to the current OS temporary directory in linux `/tmp/logstash`.
397
+
398
+ WARNING: Using multiple S3 outputs with `restore => true` requires unique directories
399
+ per output. All of the directory's contents are processed and deleted upon recovery, and shared or nested directories can cause data loss.
400
+ For example, an output using `/tmp/s3` and a second configured with `/tmp/s3/sub` would
401
+ cause issues. Having temporary directories `/tmp/s3/sub1` and `/tmp/s3/sub2` is fine.
402
+
403
+ [id="plugins-{type}s-{plugin}-time_file"]
404
+ ===== `time_file`
405
+
406
+ * Value type is <<number,number>>
407
+ * Default value is `15`
408
+
409
+ Set the time, in MINUTES, to close the current sub_time_section of bucket.
410
+ If <<plugins-{type}s-{plugin}-rotation_strategy,`rotation_strategy`>> is set to `time` or `size_and_time`, then `time_file` cannot be set to 0.
411
+ Otherwise, the plugin raises a configuration error.
412
+
413
+ [id="plugins-{type}s-{plugin}-upload_multipart_threshold"]
414
+ ===== `upload_multipart_threshold`
415
+
416
+ * Value type is <<number,number>>
417
+ * Default value is `15728640`
418
+
419
+ Files larger than this number are uploaded using the S3 multipart APIs
420
+
421
+ [id="plugins-{type}s-{plugin}-upload_queue_size"]
422
+ ===== `upload_queue_size`
423
+
424
+ * Value type is <<number,number>>
425
+ * Default value is `4`
426
+
427
+ Number of items we can keep in the local queue before uploading them
428
+
429
+ [id="plugins-{type}s-{plugin}-upload_workers_count"]
430
+ ===== `upload_workers_count`
431
+
432
+ * Value type is <<number,number>>
433
+ * Default value is `4`
434
+
435
+ Specify how many workers to use to upload the files to S3
436
+
437
+ [id="plugins-{type}s-{plugin}-validate_credentials_on_root_bucket"]
438
+ ===== `validate_credentials_on_root_bucket`
439
+
440
+ * Value type is <<boolean,boolean>>
441
+ * Default value is `true`
442
+
443
+ The common use case is to define permissions on the root bucket and give Logstash
444
+ full access to write logs.
445
+ In some circumstances, you need more granular permissions on the subfolder. This
446
+ allows you to disable the check at startup.
447
+
448
+ [id="plugins-{type}s-{plugin}-common-options"]
449
+ include::{include_path}/{type}.asciidoc[]
450
+
451
+ :default_codec!:
@@ -0,0 +1,177 @@
1
+ # encoding: utf-8
2
+ require "java"
3
+ require "concurrent/map"
4
+ require "concurrent/timer_task"
5
+ require "logstash/util"
6
+
7
+ module LogStash
8
+ module Outputs
9
+ class S3
10
+ class FileRepository
11
+ DEFAULT_STATE_SWEEPER_INTERVAL_SECS = 60
12
+ DEFAULT_STALE_TIME_SECS = 15 * 60
13
+ # Ensure that all access or work done
14
+ # on a factory is threadsafe
15
+ class PrefixedValue
16
+ def initialize(file_factory, stale_time)
17
+ @file_factory = file_factory
18
+ @lock = Monitor.new
19
+ @stale_time = stale_time
20
+ @is_deleted = false
21
+ end
22
+
23
+ def with_lock
24
+ @lock.synchronize {
25
+ yield @file_factory
26
+ }
27
+ end
28
+
29
+ def stale?
30
+ with_lock { |factory| factory.current.size == 0 && (Time.now - factory.current.ctime > @stale_time) }
31
+ end
32
+
33
+ def apply(prefix)
34
+ return self
35
+ end
36
+
37
+ def delete!
38
+ with_lock do |factory|
39
+ factory.current.delete!
40
+ @is_deleted = true
41
+ end
42
+ end
43
+
44
+ def deleted?
45
+ with_lock { |_| @is_deleted }
46
+ end
47
+ end
48
+
49
+ class FactoryInitializer
50
+
51
+ def initialize(tags, encoding, temporary_directory, stale_time)
52
+ @tags = tags
53
+ @encoding = encoding
54
+ @temporary_directory = temporary_directory
55
+ @stale_time = stale_time
56
+ end
57
+
58
+ def create_value(prefix_key)
59
+ PrefixedValue.new(TemporaryFileFactory.new(prefix_key, @tags, @encoding, @temporary_directory), @stale_time)
60
+ end
61
+
62
+ end
63
+
64
+ def initialize(tags, encoding, temporary_directory,
65
+ stale_time = DEFAULT_STALE_TIME_SECS,
66
+ sweeper_interval = DEFAULT_STATE_SWEEPER_INTERVAL_SECS)
67
+ # The path need to contains the prefix so when we start
68
+ # logtash after a crash we keep the remote structure
69
+ @prefixed_factories = Concurrent::Map.new
70
+
71
+ @sweeper_interval = sweeper_interval
72
+
73
+ @factory_initializer = FactoryInitializer.new(tags, encoding, temporary_directory, stale_time)
74
+
75
+ start_stale_sweeper
76
+ end
77
+
78
+ def keys
79
+ @prefixed_factories.keys
80
+ end
81
+
82
+ def each_files
83
+ each_factory(keys) do |factory|
84
+ yield factory.current
85
+ end
86
+ end
87
+
88
+ ##
89
+ # Yields the file factory while the current thread has exclusive access to it, creating a new
90
+ # one if one does not exist or if the current one is being reaped by the stale watcher.
91
+ # @param prefix_key [String]: the prefix key
92
+ # @yieldparam factory [TemporaryFileFactory]: a temporary file factory that this thread has exclusive access to
93
+ # @yieldreturn [Object]: a value to return; should NOT be the factory, which should be contained by the exclusive access scope.
94
+ # @return [Object]: the value returned by the provided block
95
+ def get_factory(prefix_key)
96
+
97
+ # fast-path: if factory exists and is not deleted, yield it with exclusive access and return
98
+ prefix_val = @prefixed_factories.get(prefix_key)
99
+ prefix_val&.with_lock do |factory|
100
+ # intentional local-jump to ensure deletion detection
101
+ # is done inside the exclusive access.
102
+ return yield(factory) unless prefix_val.deleted?
103
+ end
104
+
105
+ # slow-path:
106
+ # the Concurrent::Map#get operation is lock-free, but may have returned an entry that was being deleted by
107
+ # another thread (such as via stale detection). If we failed to retrieve a value, or retrieved one that had
108
+ # been marked deleted, use the atomic Concurrent::Map#compute to retrieve a non-deleted entry.
109
+ prefix_val = @prefixed_factories.compute(prefix_key) do |existing|
110
+ existing && !existing.deleted? ? existing : @factory_initializer.create_value(prefix_key)
111
+ end
112
+ prefix_val.with_lock { |factory| yield factory }
113
+ end
114
+
115
+ ##
116
+ # Yields each non-deleted file factory while the current thread has exclusive access to it.
117
+ # @param prefixes [Array<String>]: the prefix keys
118
+ # @yieldparam factory [TemporaryFileFactory]
119
+ # @return [void]
120
+ def each_factory(prefixes)
121
+ prefixes.each do |prefix_key|
122
+ prefix_val = @prefixed_factories.get(prefix_key)
123
+ prefix_val&.with_lock do |factory|
124
+ yield factory unless prefix_val.deleted?
125
+ end
126
+ end
127
+ end
128
+
129
+ def get_file(prefix_key)
130
+ get_factory(prefix_key) { |factory| yield factory.current }
131
+ end
132
+
133
+ def shutdown
134
+ stop_stale_sweeper
135
+ end
136
+
137
+ def size
138
+ @prefixed_factories.size
139
+ end
140
+
141
+ def remove_if_stale(prefix_key)
142
+ # we use the ATOMIC `Concurrent::Map#compute_if_present` to atomically
143
+ # detect the staleness, mark a stale prefixed factory as deleted, and delete from the map.
144
+ @prefixed_factories.compute_if_present(prefix_key) do |prefixed_factory|
145
+ # once we have retrieved an instance, we acquire exclusive access to it
146
+ # for stale detection, marking it as deleted before releasing the lock
147
+ # and causing it to become deleted from the map.
148
+ prefixed_factory.with_lock do |_|
149
+ if prefixed_factory.stale?
150
+ prefixed_factory.delete! # mark deleted to prevent reuse
151
+ nil # cause deletion
152
+ else
153
+ prefixed_factory # keep existing
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ def start_stale_sweeper
160
+ @stale_sweeper = Concurrent::TimerTask.new(:execution_interval => @sweeper_interval) do
161
+ LogStash::Util.set_thread_name("S3, Stale factory sweeper")
162
+
163
+ @prefixed_factories.keys.each do |prefix|
164
+ remove_if_stale(prefix)
165
+ end
166
+ end
167
+
168
+ @stale_sweeper.execute
169
+ end
170
+
171
+ def stop_stale_sweeper
172
+ @stale_sweeper.shutdown
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,22 @@
1
+ # This is patch related to the autoloading and ruby
2
+ #
3
+ # The fix exist in jruby 9k but not in the current jruby, not sure when or it will be backported
4
+ # https://github.com/jruby/jruby/issues/3645
5
+ #
6
+ # AWS is doing tricky name discovery in the module to generate the correct error class and
7
+ # this strategy is bogus in jruby and `eager_autoload` don't fix this issue.
8
+ #
9
+ # This will be a short lived patch since AWS is removing the need.
10
+ # see: https://github.com/aws/aws-sdk-ruby/issues/1301#issuecomment-261115960
11
+ old_stderr = $stderr
12
+
13
+ $stderr = StringIO.new
14
+ begin
15
+ module Aws
16
+ const_set(:S3, Aws::S3)
17
+ end
18
+ ensure
19
+ $stderr = old_stderr
20
+ end
21
+
22
+
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+ module LogStash
3
+ module Outputs
4
+ class S3
5
+ class PathValidator
6
+ INVALID_CHARACTERS = "\^`><"
7
+
8
+ def self.valid?(name)
9
+ name.match(matches_re).nil?
10
+ end
11
+
12
+ def self.matches_re
13
+ /[#{Regexp.escape(INVALID_CHARACTERS)}]/
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ require "logstash/outputs/s3/size_rotation_policy"
3
+ require "logstash/outputs/s3/time_rotation_policy"
4
+
5
+ module LogStash
6
+ module Outputs
7
+ class S3
8
+ class SizeAndTimeRotationPolicy
9
+ def initialize(file_size, time_file)
10
+ @size_strategy = SizeRotationPolicy.new(file_size)
11
+ @time_strategy = TimeRotationPolicy.new(time_file)
12
+ end
13
+
14
+ def rotate?(file)
15
+ @size_strategy.rotate?(file) || @time_strategy.rotate?(file)
16
+ end
17
+
18
+ def needs_periodic?
19
+ true
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end