logstash-output-sns 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|