logstash-logger 0.23.0 → 0.24.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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +25 -1
- data/lib/logstash-logger/device.rb +2 -0
- data/lib/logstash-logger/device/aws_stream.rb +91 -0
- data/lib/logstash-logger/device/firehose.rb +37 -0
- data/lib/logstash-logger/device/kinesis.rb +19 -60
- data/lib/logstash-logger/version.rb +1 -1
- data/spec/device/firehose_spec.rb +45 -0
- data/spec/spec_helper.rb +1 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a53c4f86f44f72b31d055db56d35e6e374cfe30
|
4
|
+
data.tar.gz: de52e5fcefe9adf476a5b104d92ee2b6d9f1b1e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 861e72a87a6230f386f15b9b14d5df7f303a294f843cc841352693a57fbdc17f0e55e5b8f04ba19ed6a13a72d1737ede43323b3786226cb4621487a70a68b886
|
7
|
+
data.tar.gz: 2f1e95420c8e2a5bb69a2a36ab4f8e4f40c4500d834fb16be66c113f5b3645e188434ab04fbded1b805cd110a52754e82b71e6927269abf1a4afbfeac038d451
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -9,7 +9,7 @@ writing to a file or syslog since Logstash can receive the structured data direc
|
|
9
9
|
## Features
|
10
10
|
|
11
11
|
* Can write directly to a logstash listener over a UDP or TCP/SSL connection.
|
12
|
-
* Can write to a file, Redis, Kafka, Kinesis, a unix socket, syslog, stdout, or stderr.
|
12
|
+
* Can write to a file, Redis, Kafka, Kinesis, Firehose, a unix socket, syslog, stdout, or stderr.
|
13
13
|
* Logger can take a string message, a hash, a `LogStash::Event`, an object, or a JSON string as input.
|
14
14
|
* Events are automatically populated with message, timestamp, host, and severity.
|
15
15
|
* Writes in logstash JSON format, but supports other formats as well.
|
@@ -572,6 +572,30 @@ config.logstash.aws_secret_access_key = 'ASKASKHLD1234123412341234'
|
|
572
572
|
|
573
573
|
```
|
574
574
|
|
575
|
+
#### Firehose
|
576
|
+
|
577
|
+
Add the aws-sdk gem to your Gemfile:
|
578
|
+
|
579
|
+
gem 'aws-sdk'
|
580
|
+
|
581
|
+
```ruby
|
582
|
+
# Required
|
583
|
+
config.logstash.type = :firehose
|
584
|
+
|
585
|
+
# Optional, will default to the 'logstash' delivery stream
|
586
|
+
config.logstash.stream = 'my-stream-name'
|
587
|
+
|
588
|
+
# Optional, will default to 'us-east-1'
|
589
|
+
config.logstash.aws_region = 'us-west-2'
|
590
|
+
|
591
|
+
# Optional, will default to the AWS_ACCESS_KEY_ID environment variable
|
592
|
+
config.logstash.aws_access_key_id = 'ASKASKHLD12341'
|
593
|
+
|
594
|
+
# Optional, will default to the AWS_SECRET_ACCESS_KEY environment variable
|
595
|
+
config.logstash.aws_secret_access_key = 'ASKASKHLD1234123412341234'
|
596
|
+
|
597
|
+
```
|
598
|
+
|
575
599
|
#### File
|
576
600
|
|
577
601
|
```ruby
|
@@ -13,6 +13,7 @@ module LogStashLogger
|
|
13
13
|
autoload :Redis, 'logstash-logger/device/redis'
|
14
14
|
autoload :Kafka, 'logstash-logger/device/kafka'
|
15
15
|
autoload :Kinesis, 'logstash-logger/device/kinesis'
|
16
|
+
autoload :Firehose, 'logstash-logger/device/firehose'
|
16
17
|
autoload :File, 'logstash-logger/device/file'
|
17
18
|
autoload :IO, 'logstash-logger/device/io'
|
18
19
|
autoload :Stdout, 'logstash-logger/device/stdout'
|
@@ -53,6 +54,7 @@ module LogStashLogger
|
|
53
54
|
when :redis then Redis
|
54
55
|
when :kafka then Kafka
|
55
56
|
when :kinesis then Kinesis
|
57
|
+
when :firehose then Firehose
|
56
58
|
when :io then IO
|
57
59
|
when :stdout then Stdout
|
58
60
|
when :stderr then Stderr
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
|
3
|
+
module LogStashLogger
|
4
|
+
module Device
|
5
|
+
class AwsStream < Connectable
|
6
|
+
|
7
|
+
DEFAULT_REGION = 'us-east-1'
|
8
|
+
DEFAULT_STREAM = 'logstash'
|
9
|
+
|
10
|
+
@stream_class = nil
|
11
|
+
@recoverable_error_codes = []
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_accessor :stream_class, :recoverable_error_codes
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_accessor :aws_region, :stream
|
18
|
+
|
19
|
+
def initialize(opts)
|
20
|
+
super
|
21
|
+
@access_key_id = opts[:aws_access_key_id] || ENV['AWS_ACCESS_KEY_ID']
|
22
|
+
@secret_access_key = opts[:aws_secret_access_key] || ENV['AWS_SECRET_ACCESS_KEY']
|
23
|
+
@aws_region = opts[:aws_region] || DEFAULT_REGION
|
24
|
+
@stream = opts[:stream] || DEFAULT_STREAM
|
25
|
+
end
|
26
|
+
|
27
|
+
def transform_message(message)
|
28
|
+
fail NotImplementedError
|
29
|
+
end
|
30
|
+
|
31
|
+
def put_records(records)
|
32
|
+
fail NotImplementedError
|
33
|
+
end
|
34
|
+
|
35
|
+
def is_successful_response(resp)
|
36
|
+
fail NotImplementedError
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_response_records(resp)
|
40
|
+
fail NotImplementedError
|
41
|
+
end
|
42
|
+
|
43
|
+
def connect
|
44
|
+
@io = self.class.stream_class.new(
|
45
|
+
region: @aws_region,
|
46
|
+
credentials: ::Aws::Credentials.new(@access_key_id, @secret_access_key)
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def with_connection
|
51
|
+
connect unless connected?
|
52
|
+
yield
|
53
|
+
rescue => e
|
54
|
+
log_error(e)
|
55
|
+
log_warning("giving up")
|
56
|
+
close(flush: false)
|
57
|
+
end
|
58
|
+
|
59
|
+
def write_batch(messages, group = nil)
|
60
|
+
records = messages.map{ |m| transform_message(m) }
|
61
|
+
|
62
|
+
with_connection do
|
63
|
+
resp = put_records(records)
|
64
|
+
|
65
|
+
# Put any failed records back into the buffer
|
66
|
+
if !is_successful_response(resp)
|
67
|
+
get_response_records(resp).each_with_index do |record, index|
|
68
|
+
if self.class.recoverable_error_codes.include?(record.error_code)
|
69
|
+
log_warning("Failed to post record using #{self.class.stream_class.name} with error: #{record.error_code} #{record.error_message}")
|
70
|
+
log_warning("Retrying")
|
71
|
+
write(records[index][:data])
|
72
|
+
elsif !record.error_code.nil? && record.error_code != ''
|
73
|
+
log_error("Failed to post record using #{self.class.stream_class.name} with error: #{record.error_code} #{record.error_message}")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def write_one(message)
|
81
|
+
write_batch([message])
|
82
|
+
end
|
83
|
+
|
84
|
+
def close!
|
85
|
+
@io = nil
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'logstash-logger/device/aws_stream'
|
3
|
+
|
4
|
+
module LogStashLogger
|
5
|
+
module Device
|
6
|
+
class Firehose < AwsStream
|
7
|
+
@stream_class = ::Aws::Firehose::Client
|
8
|
+
@recoverable_error_codes = [
|
9
|
+
"ServiceUnavailable",
|
10
|
+
"InternalFailure",
|
11
|
+
"ServiceUnavailableException"
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
def transform_message(message)
|
15
|
+
{
|
16
|
+
data: message
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def put_records(records)
|
21
|
+
@io.put_record_batch({
|
22
|
+
records: records,
|
23
|
+
delivery_stream_name: @stream
|
24
|
+
})
|
25
|
+
end
|
26
|
+
|
27
|
+
def is_successful_response(resp)
|
28
|
+
resp.failed_put_count == 0
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_response_records(resp)
|
32
|
+
resp.request_responses
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,80 +1,39 @@
|
|
1
1
|
require 'aws-sdk'
|
2
|
+
require 'logstash-logger/device/aws_stream'
|
2
3
|
|
3
4
|
module LogStashLogger
|
4
5
|
module Device
|
5
|
-
class Kinesis <
|
6
|
-
|
7
|
-
|
8
|
-
DEFAULT_STREAM = 'logstash'
|
9
|
-
RECOVERABLE_ERROR_CODES = [
|
6
|
+
class Kinesis < AwsStream
|
7
|
+
@stream_class = ::Aws::Kinesis::Client
|
8
|
+
@recoverable_error_codes = [
|
10
9
|
"ServiceUnavailable",
|
11
10
|
"Throttling",
|
12
11
|
"RequestExpired",
|
13
12
|
"ProvisionedThroughputExceededException"
|
14
|
-
]
|
15
|
-
|
16
|
-
attr_accessor :aws_region, :stream
|
13
|
+
].freeze
|
17
14
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
@stream = opts[:stream] || DEFAULT_STREAM
|
15
|
+
def transform_message(message)
|
16
|
+
{
|
17
|
+
data: message,
|
18
|
+
partition_key: SecureRandom.uuid
|
19
|
+
}
|
24
20
|
end
|
25
21
|
|
26
|
-
def
|
27
|
-
@io
|
28
|
-
|
29
|
-
|
30
|
-
)
|
22
|
+
def put_records(records)
|
23
|
+
@io.put_records({
|
24
|
+
records: records,
|
25
|
+
stream_name: @stream
|
26
|
+
})
|
31
27
|
end
|
32
28
|
|
33
|
-
def
|
34
|
-
|
35
|
-
yield
|
36
|
-
rescue => e
|
37
|
-
log_error(e)
|
38
|
-
log_warning("giving up")
|
39
|
-
close(flush: false)
|
29
|
+
def is_successful_response(resp)
|
30
|
+
resp.failed_record_count == 0
|
40
31
|
end
|
41
32
|
|
42
|
-
def
|
43
|
-
|
44
|
-
{
|
45
|
-
data: message,
|
46
|
-
partition_key: SecureRandom.uuid
|
47
|
-
}
|
48
|
-
end
|
49
|
-
|
50
|
-
with_connection do
|
51
|
-
resp = @io.put_records({
|
52
|
-
records: kinesis_records,
|
53
|
-
stream_name: @stream
|
54
|
-
})
|
55
|
-
|
56
|
-
# Put any failed records back into the buffer
|
57
|
-
if resp.failed_record_count != 0
|
58
|
-
resp.records.each_with_index do |record, index|
|
59
|
-
if RECOVERABLE_ERROR_CODES.include?(record.error_code)
|
60
|
-
log_warning("Failed to post record to kinesis with error: #{record.error_code} #{record.error_message}")
|
61
|
-
log_warning("Retrying")
|
62
|
-
write(kinesis_records[index][:data])
|
63
|
-
elsif !record.error_code.nil? && record.error_code != ''
|
64
|
-
log_error("Failed to post record to kinesis with error: #{record.error_code} #{record.error_message}")
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
33
|
+
def get_response_records(resp)
|
34
|
+
resp.records
|
69
35
|
end
|
70
36
|
|
71
|
-
def write_one(message)
|
72
|
-
write_batch([message])
|
73
|
-
end
|
74
|
-
|
75
|
-
def close!
|
76
|
-
@io = nil
|
77
|
-
end
|
78
37
|
end
|
79
38
|
end
|
80
39
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'logstash-logger'
|
2
|
+
|
3
|
+
describe LogStashLogger::Device::Kinesis do
|
4
|
+
include_context 'device'
|
5
|
+
|
6
|
+
let(:client) { double("Aws::Firehose::Client") }
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
allow(Aws::Firehose::Client).to receive(:new) { client }
|
10
|
+
end
|
11
|
+
|
12
|
+
it "writes to a Firehose stream" do
|
13
|
+
response = ::Aws::Firehose::Types::PutRecordBatchOutput.new
|
14
|
+
response.failed_put_count = 0
|
15
|
+
response.request_responses = []
|
16
|
+
expect(client).to receive(:put_record_batch) { response }
|
17
|
+
firehose_device.write "foo"
|
18
|
+
|
19
|
+
expect(firehose_device).to be_connected
|
20
|
+
firehose_device.close!
|
21
|
+
expect(firehose_device).not_to be_connected
|
22
|
+
end
|
23
|
+
|
24
|
+
it "it puts records with recoverable errors back in the buffer" do
|
25
|
+
failed_record = ::Aws::Firehose::Types::PutRecordBatchResponseEntry.new
|
26
|
+
failed_record.error_code = "InternalFailure"
|
27
|
+
failed_record.error_message = "InternalFailure"
|
28
|
+
response = ::Aws::Firehose::Types::PutRecordBatchOutput.new
|
29
|
+
response.failed_put_count = 1
|
30
|
+
response.request_responses = [failed_record]
|
31
|
+
|
32
|
+
expect(client).to receive(:put_record_batch) { response }
|
33
|
+
expect(firehose_device).to receive(:write).with("foo")
|
34
|
+
|
35
|
+
firehose_device.write_one "foo"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "defaults the AWS region to us-east-1" do
|
39
|
+
expect(firehose_device.aws_region).to eq('us-east-1')
|
40
|
+
end
|
41
|
+
|
42
|
+
it "defaults the Firehose stream to logstash" do
|
43
|
+
expect(firehose_device.stream).to eq('logstash')
|
44
|
+
end
|
45
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -62,6 +62,7 @@ RSpec.shared_context 'device' do
|
|
62
62
|
let(:redis_device) { LogStashLogger::Device.new(type: :redis, sync: true) }
|
63
63
|
let(:kafka_device) { LogStashLogger::Device.new(type: :kafka, sync: true) }
|
64
64
|
let(:kinesis_device) { LogStashLogger::Device.new(type: :kinesis, sync: true) }
|
65
|
+
let(:firehose_device) { LogStashLogger::Device.new(type: :firehose, sync: true) }
|
65
66
|
|
66
67
|
let(:outputs) { [{type: :stdout}, {type: :io, io: io}] }
|
67
68
|
let(:multi_delegator_device) { LogStashLogger::Device.new(type: :multi_delegator, outputs: outputs) }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-logger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.24.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Butler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-04-
|
11
|
+
date: 2017-04-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -191,10 +191,12 @@ files:
|
|
191
191
|
- lib/logstash-logger/buffer.rb
|
192
192
|
- lib/logstash-logger/configuration.rb
|
193
193
|
- lib/logstash-logger/device.rb
|
194
|
+
- lib/logstash-logger/device/aws_stream.rb
|
194
195
|
- lib/logstash-logger/device/balancer.rb
|
195
196
|
- lib/logstash-logger/device/base.rb
|
196
197
|
- lib/logstash-logger/device/connectable.rb
|
197
198
|
- lib/logstash-logger/device/file.rb
|
199
|
+
- lib/logstash-logger/device/firehose.rb
|
198
200
|
- lib/logstash-logger/device/io.rb
|
199
201
|
- lib/logstash-logger/device/kafka.rb
|
200
202
|
- lib/logstash-logger/device/kinesis.rb
|
@@ -234,6 +236,7 @@ files:
|
|
234
236
|
- spec/device/balancer_spec.rb
|
235
237
|
- spec/device/connectable_spec.rb
|
236
238
|
- spec/device/file_spec.rb
|
239
|
+
- spec/device/firehose_spec.rb
|
237
240
|
- spec/device/io_spec.rb
|
238
241
|
- spec/device/kafka_spec.rb
|
239
242
|
- spec/device/kinesis_spec.rb
|
@@ -290,6 +293,7 @@ test_files:
|
|
290
293
|
- spec/device/balancer_spec.rb
|
291
294
|
- spec/device/connectable_spec.rb
|
292
295
|
- spec/device/file_spec.rb
|
296
|
+
- spec/device/firehose_spec.rb
|
293
297
|
- spec/device/io_spec.rb
|
294
298
|
- spec/device/kafka_spec.rb
|
295
299
|
- spec/device/kinesis_spec.rb
|