logstash-output-sns 1.0.0 → 2.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile +1 -1
- data/lib/logstash/outputs/sns.rb +57 -62
- data/logstash-output-sns.gemspec +2 -4
- data/spec/outputs/sns_spec.rb +131 -7
- metadata +5 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b4ac99bfe2f2202031197d1244322ea5922043b
|
4
|
+
data.tar.gz: 3708b40a61096f6f3f26a0e89126172812ad7d93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c5f526f7fd22744a1eed1e441b9a1c3ad505d5fbad019155bac79224c80c8c153216462bb96259fcc76aca4a5d0c9beb2a6819bfdd9c5f6e39c4624c6fdffa2
|
7
|
+
data.tar.gz: 4c27f467d148a9575a79f0390e0958e2948890a1e4b9f98c54bd0ec8d8f33b63599014600516c2cb926287ce413b8904d2c34f8211c13dc6aacae292f3b1b862
|
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,6 @@
|
|
1
|
+
# 1.0.0
|
2
|
+
* Full refactor.
|
3
|
+
* This plugin now uses codecs for all formatting. The 'format' option has now been removed. Please use a codec.
|
4
|
+
# 0.1.5
|
5
|
+
* If no `subject` are specified fallback to the %{host} key (https://github.com/logstash-plugins/logstash-output-sns/pull/2)
|
6
|
+
* Migrate the SNS Api to use the AWS-SDK v2
|
data/Gemfile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
-
gemspec
|
2
|
+
gemspec
|
data/lib/logstash/outputs/sns.rb
CHANGED
@@ -6,7 +6,7 @@ require "logstash/plugin_mixins/aws_config"
|
|
6
6
|
# SNS output.
|
7
7
|
#
|
8
8
|
# Send events to Amazon's Simple Notification Service, a hosted pub/sub
|
9
|
-
# framework. It supports
|
9
|
+
# framework. It supports various subscription types, including email, HTTP/S, SMS, and SQS.
|
10
10
|
#
|
11
11
|
# For further documentation about the service see:
|
12
12
|
#
|
@@ -17,25 +17,23 @@ require "logstash/plugin_mixins/aws_config"
|
|
17
17
|
# * `sns` - If no ARN is found in the configuration file, this will be used as
|
18
18
|
# the ARN to publish.
|
19
19
|
# * `sns_subject` - The subject line that should be used.
|
20
|
-
# Optional. The "%{host}" will be used if not present
|
21
|
-
# `
|
22
|
-
# * `sns_message` -
|
23
|
-
# sent. Optional. The event serialzed as JSON will be used if not present and
|
20
|
+
# Optional. The "%{host}" will be used if `sns_subject` is not present. The subject
|
21
|
+
# will be truncated to 100 characters. If `sns_subject` is set to a non-string value a JSON version of that value will be saved.
|
22
|
+
# * `sns_message` - Optional string of message to be sent. If this is set to a non-string value it will be encoded with the specified `codec`. If this is not set the entire event will be encoded with the codec.
|
24
23
|
# with the @message truncated so that the length of the JSON fits in
|
25
|
-
# `
|
24
|
+
# `32768` bytes.
|
26
25
|
#
|
27
26
|
class LogStash::Outputs::Sns < LogStash::Outputs::Base
|
28
|
-
include LogStash::PluginMixins::AwsConfig
|
27
|
+
include LogStash::PluginMixins::AwsConfig::V2
|
29
28
|
|
30
29
|
MAX_SUBJECT_SIZE_IN_CHARACTERS = 100
|
31
30
|
MAX_MESSAGE_SIZE_IN_BYTES = 32768
|
31
|
+
NO_SUBJECT = "NO SUBJECT"
|
32
32
|
|
33
33
|
config_name "sns"
|
34
34
|
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
# SNS topic ARN.
|
35
|
+
# Optional ARN to send messages to. If you do not set this you must
|
36
|
+
# include the `sns` field in your events to set the ARN on a per-message basis!
|
39
37
|
config :arn, :validate => :string
|
40
38
|
|
41
39
|
# When an ARN for an SNS topic is specified here, the message
|
@@ -46,23 +44,16 @@ class LogStash::Outputs::Sns < LogStash::Outputs::Base
|
|
46
44
|
#
|
47
45
|
config :publish_boot_message_arn, :validate => :string
|
48
46
|
|
49
|
-
public
|
50
|
-
def aws_service_endpoint(region)
|
51
|
-
return {
|
52
|
-
:sns_endpoint => "sns.#{region}.amazonaws.com"
|
53
|
-
}
|
54
|
-
end
|
55
|
-
|
56
47
|
public
|
57
48
|
def register
|
58
|
-
require "aws-sdk"
|
49
|
+
require "aws-sdk-resources"
|
59
50
|
|
60
|
-
@sns =
|
51
|
+
@sns = Aws::SNS::Client.new(aws_options_hash)
|
61
52
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
53
|
+
publish_boot_message_arn()
|
54
|
+
|
55
|
+
@codec.on_event do |event, encoded|
|
56
|
+
send_sns_message(event_arn(event), event_subject(event), encoded)
|
66
57
|
end
|
67
58
|
end
|
68
59
|
|
@@ -70,54 +61,58 @@ class LogStash::Outputs::Sns < LogStash::Outputs::Base
|
|
70
61
|
def receive(event)
|
71
62
|
return unless output?(event)
|
72
63
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
message = Array(event["sns_message"]).first
|
78
|
-
subject = Array(event["sns_subject"]).first || event["host"]
|
79
|
-
|
80
|
-
# Ensure message doesn't exceed the maximum size.
|
81
|
-
if message
|
82
|
-
# TODO: Utilize `byteslice` in JRuby 1.7: http://jira.codehaus.org/browse/JRUBY-5547
|
83
|
-
message = message.slice(0, MAX_MESSAGE_SIZE_IN_BYTES)
|
84
|
-
else
|
85
|
-
if @format == "plain"
|
86
|
-
message = self.class.format_message(event)
|
64
|
+
if (sns_msg = event["sns_message"])
|
65
|
+
if sns_msg.is_a?(String)
|
66
|
+
send_sns_message(event_arn(event), event_subject(event), sns_msg)
|
87
67
|
else
|
88
|
-
|
68
|
+
@codec.encode(sns_msg)
|
89
69
|
end
|
70
|
+
else
|
71
|
+
@codec.encode(event)
|
90
72
|
end
|
73
|
+
end
|
91
74
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
75
|
+
private
|
76
|
+
def publish_boot_message_arn
|
77
|
+
# Try to publish a "Logstash booted" message to the ARN provided to
|
78
|
+
# cause an error ASAP if the credentials are bad.
|
79
|
+
if @publish_boot_message_arn
|
80
|
+
send_sns_message(@publish_boot_message_arn, 'Logstash booted', 'Logstash successfully booted')
|
81
|
+
end
|
98
82
|
end
|
99
83
|
|
100
|
-
|
101
|
-
|
102
|
-
|
84
|
+
private
|
85
|
+
def send_sns_message(arn, subject, message)
|
86
|
+
raise ArgumentError, 'An SNS ARN is required.' unless arn
|
103
87
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
88
|
+
trunc_subj = subject.slice(0, MAX_SUBJECT_SIZE_IN_CHARACTERS)
|
89
|
+
trunc_msg = message.slice(0, MAX_MESSAGE_SIZE_IN_BYTES)
|
90
|
+
|
91
|
+
@logger.debug? && @logger.debug("Sending event to SNS topic [#{arn}] with subject [#{trunc_subj}] and message: #{trunc_msg}")
|
109
92
|
|
110
|
-
|
93
|
+
@sns.publish({
|
94
|
+
:topic_arn => arn,
|
95
|
+
:subject => trunc_subj,
|
96
|
+
:message => trunc_msg
|
97
|
+
})
|
111
98
|
end
|
112
99
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
100
|
+
private
|
101
|
+
def event_subject(event)
|
102
|
+
sns_subject = event["sns_subject"]
|
103
|
+
if sns_subject.is_a?(String)
|
104
|
+
sns_subject
|
105
|
+
elsif sns_subject
|
106
|
+
LogStash::Json.dump(sns_subject)
|
107
|
+
elsif event["host"]
|
108
|
+
event["host"]
|
109
|
+
else
|
110
|
+
NO_SUBJECT
|
111
|
+
end
|
112
|
+
end
|
119
113
|
|
120
|
-
|
121
|
-
|
114
|
+
private
|
115
|
+
def event_arn(event)
|
116
|
+
event["sns"] || @arn
|
122
117
|
end
|
123
118
|
end
|
data/logstash-output-sns.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-output-sns'
|
4
|
-
s.version = '
|
4
|
+
s.version = '2.0.0'
|
5
5
|
s.licenses = ['Apache License (2.0)']
|
6
6
|
s.summary = "Send events to Amazon's Simple Notification Service a hosted pub/sub framework"
|
7
7
|
s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
|
@@ -21,9 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
|
22
22
|
# Gem dependencies
|
23
23
|
s.add_runtime_dependency "logstash-core", '>= 1.4.0', '< 2.0.0'
|
24
|
-
s.add_runtime_dependency 'logstash-mixin-aws'
|
25
|
-
s.add_runtime_dependency 'aws-sdk'
|
24
|
+
s.add_runtime_dependency 'logstash-mixin-aws', '>= 1.0.0'
|
26
25
|
|
27
26
|
s.add_development_dependency 'logstash-devutils'
|
28
27
|
end
|
29
|
-
|
data/spec/outputs/sns_spec.rb
CHANGED
@@ -2,17 +2,141 @@
|
|
2
2
|
require "logstash/devutils/rspec/spec_helper"
|
3
3
|
require 'logstash/outputs/sns'
|
4
4
|
require 'logstash/event'
|
5
|
+
require "logstash/plugin_mixins/aws_config"
|
6
|
+
|
7
|
+
require "aws-sdk" # TODO: Why is this not automatically brought in by the aws_config plugin?
|
5
8
|
|
6
9
|
describe LogStash::Outputs::Sns do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
10
|
+
let(:arn) { "arn:aws:sns:us-east-1:999999999:logstash-test-sns-topic" }
|
11
|
+
let(:sns_subject) { "The Plain in Spain" }
|
12
|
+
let(:sns_message) { "That's where the rain falls, plainly." }
|
13
|
+
let(:mock_client) { double("Aws::SNS::Client") }
|
14
|
+
let(:instance) {
|
15
|
+
allow(Aws::SNS::Client).to receive(:new).and_return(mock_client)
|
16
|
+
inst = LogStash::Outputs::Sns.new
|
17
|
+
allow(inst).to receive(:publish_boot_message_arn).and_return(nil)
|
18
|
+
inst.register
|
19
|
+
inst
|
20
|
+
}
|
21
|
+
|
22
|
+
describe "receiving an event" do
|
23
|
+
let(:expected_subject) { double("expected_subject")}
|
24
|
+
subject {
|
25
|
+
inst = instance
|
26
|
+
allow(inst).to receive(:send_sns_message).with(any_args)
|
27
|
+
allow(inst).to receive(:event_subject).
|
28
|
+
with(any_args).
|
29
|
+
and_return(expected_subject)
|
30
|
+
inst.receive(event)
|
31
|
+
inst
|
32
|
+
}
|
33
|
+
|
34
|
+
shared_examples("publishing correctly") do
|
35
|
+
it "should send a message to the correct ARN if the event has 'arn' set" do
|
36
|
+
expect(subject).to have_received(:send_sns_message).with(arn, anything, anything)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should send the message" do
|
40
|
+
expect(subject).to have_received(:send_sns_message).with(anything, anything, expected_message)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should send the subject" do
|
44
|
+
expect(subject).to have_received(:send_sns_message).with(anything, expected_subject, anything)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "with an explicit message" do
|
49
|
+
let(:expected_subject) { sns_subject }
|
50
|
+
let(:expected_message) { sns_message }
|
51
|
+
let(:event) { LogStash::Event.new("sns" => arn, "sns_subject" => sns_subject,
|
52
|
+
"sns_message" => sns_message) }
|
53
|
+
include_examples("publishing correctly")
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "without an explicit message" do
|
57
|
+
# Testing codecs sucks. It'd be nice if codecs had to implement some sort of encode_sync method
|
58
|
+
let(:expected_message) {
|
59
|
+
c = subject.codec.clone
|
60
|
+
result = nil;
|
61
|
+
c.on_event {|event, encoded| result = encoded }
|
62
|
+
c.encode(event)
|
63
|
+
result
|
64
|
+
}
|
65
|
+
let(:event) { LogStash::Event.new("sns" => arn, "sns_subject" => sns_subject) }
|
66
|
+
|
67
|
+
include_examples("publishing correctly")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "determining the subject" do
|
72
|
+
it "should return 'sns_subject' when set" do
|
73
|
+
event = LogStash::Event.new("sns_subject" => "foo")
|
74
|
+
expect(subject.send(:event_subject, event)).to eql("foo")
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should return the sns subject as JSON if not a string" do
|
78
|
+
event = LogStash::Event.new("sns_subject" => ["foo", "bar"])
|
79
|
+
expect(subject.send(:event_subject, event)).to eql(LogStash::Json.dump(["foo", "bar"]))
|
11
80
|
end
|
12
81
|
|
13
|
-
it
|
14
|
-
event = LogStash::Event.new(
|
15
|
-
expect(
|
82
|
+
it "should return the host if 'sns_subject' not set" do
|
83
|
+
event = LogStash::Event.new("host" => "foo")
|
84
|
+
expect(subject.send(:event_subject, event)).to eql("foo")
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should return 'NO SUBJECT' when subject cannot be determined" do
|
88
|
+
event = LogStash::Event.new("foo" => "bar")
|
89
|
+
expect(subject.send(:event_subject, event)).to eql(LogStash::Outputs::Sns::NO_SUBJECT)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "sending an SNS notification" do
|
94
|
+
let(:good_publish_args) {
|
95
|
+
{
|
96
|
+
:topic_arn => arn,
|
97
|
+
:subject => sns_subject,
|
98
|
+
:message => sns_message
|
99
|
+
}
|
100
|
+
}
|
101
|
+
let(:long_message) { "A" * (LogStash::Outputs::Sns::MAX_MESSAGE_SIZE_IN_BYTES + 1) }
|
102
|
+
let(:long_subject) { "S" * (LogStash::Outputs::Sns::MAX_SUBJECT_SIZE_IN_CHARACTERS + 1) }
|
103
|
+
subject { instance }
|
104
|
+
|
105
|
+
it "should raise an ArgumentError if no arn is provided" do
|
106
|
+
expect {
|
107
|
+
subject.send(:send_sns_message, nil, sns_subject, sns_message)
|
108
|
+
}.to raise_error(ArgumentError)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should send a well formed message through to SNS" do
|
112
|
+
expect(mock_client).to receive(:publish).with(good_publish_args)
|
113
|
+
subject.send(:send_sns_message, arn, sns_subject, sns_message)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should attempt to publish a boot message" do
|
117
|
+
expect(subject).to have_received(:publish_boot_message_arn).once
|
118
|
+
x = case "foo"
|
119
|
+
when "bar"
|
120
|
+
"hello"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should truncate long messages before sending" do
|
125
|
+
max_size = LogStash::Outputs::Sns::MAX_MESSAGE_SIZE_IN_BYTES
|
126
|
+
expect(mock_client).to receive(:publish) {|args|
|
127
|
+
expect(args[:message].bytesize).to eql(max_size)
|
128
|
+
}
|
129
|
+
|
130
|
+
subject.send(:send_sns_message, arn, sns_subject, long_message)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should truncate long subjects before sending" do
|
134
|
+
max_size = LogStash::Outputs::Sns::MAX_SUBJECT_SIZE_IN_CHARACTERS
|
135
|
+
expect(mock_client).to receive(:publish) {|args|
|
136
|
+
expect(args[:subject].bytesize).to eql(max_size)
|
137
|
+
}
|
138
|
+
|
139
|
+
subject.send(:send_sns_message, arn, long_subject, sns_message)
|
16
140
|
end
|
17
141
|
end
|
18
142
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-output-sns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logstash-core
|
@@ -36,26 +36,12 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - '>='
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
39
|
+
version: 1.0.0
|
40
40
|
requirement: !ruby/object:Gem::Requirement
|
41
41
|
requirements:
|
42
42
|
- - '>='
|
43
43
|
- !ruby/object:Gem::Version
|
44
|
-
version:
|
45
|
-
prerelease: false
|
46
|
-
type: :runtime
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: aws-sdk
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - '>='
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
54
|
-
requirement: !ruby/object:Gem::Requirement
|
55
|
-
requirements:
|
56
|
-
- - '>='
|
57
|
-
- !ruby/object:Gem::Version
|
58
|
-
version: '0'
|
44
|
+
version: 1.0.0
|
59
45
|
prerelease: false
|
60
46
|
type: :runtime
|
61
47
|
- !ruby/object:Gem::Dependency
|
@@ -111,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
97
|
version: '0'
|
112
98
|
requirements: []
|
113
99
|
rubyforge_project:
|
114
|
-
rubygems_version: 2.
|
100
|
+
rubygems_version: 2.1.9
|
115
101
|
signing_key:
|
116
102
|
specification_version: 4
|
117
103
|
summary: Send events to Amazon's Simple Notification Service a hosted pub/sub framework
|