logstash-output-s3-zst 1.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.
@@ -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