logstash-output-email 0.1.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,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MGExYjgwYzBlYTE4OGRjY2I1YjQ0MzdkZjNjZjliNWEwNDM4OTcxZg==
5
+ data.tar.gz: !binary |-
6
+ OTQ5MWUwNjhjNzNjMDQ5OTk5YzAyOWE4MzRkMzIwNWJiYTJmYzEwNQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NzRiYmFjMjM5MjliYzVmZDQwNzQ3Mjk0NDBlMjg3ZGJkZGY4YjkwZDQ2Zjkw
10
+ MDc1OGQ2Mzc4N2U4NTM0ODVlMGQ5MTQzMjE2ZDc1NTM4NWIwYThjMjU4OWUw
11
+ NGM1YmNmYTVmM2U1ZjVlYTIwYzk1ZmI4ZjY3YTJjODQyMjg3YTA=
12
+ data.tar.gz: !binary |-
13
+ MGE4Y2U3ZjM2M2QyNzIxNDcxYWUwNmFlNThlMjZlNGEzZDA2M2Q4ZTMyMzQw
14
+ MTljZmMzYzJmZDA5Y2M4ZjRiY2U4MzIzYWM5YjNlNThkZDM4NGFlNWY3Nzk2
15
+ MTc2ZTRlYThhYjU2MjhjNjllZTcxMmI1MDQ3ODAzZjkxNGVkZDg=
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ Gemfile.lock
3
+ .bundle
4
+ vendor
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+ gem 'rake'
3
+ gem 'gem_publisher'
4
+ gem 'archive-tar-minitar'
@@ -0,0 +1,6 @@
1
+ @files=[]
2
+
3
+ task :default do
4
+ system("rake -T")
5
+ end
6
+
@@ -0,0 +1,303 @@
1
+ # encoding: utf-8
2
+ require "logstash/outputs/base"
3
+ require "logstash/namespace"
4
+
5
+ # Send email when an output is received. Alternatively, you may include or
6
+ # exclude the email output execution using conditionals.
7
+ class LogStash::Outputs::Email < LogStash::Outputs::Base
8
+
9
+ config_name "email"
10
+ milestone 1
11
+
12
+ # This setting is deprecated in favor of Logstash's "conditionals" feature
13
+ # If you were using this setting previously, please use conditionals instead.
14
+ #
15
+ # If you need help converting your older 'match' setting to a conditional,
16
+ # I welcome you to join the #logstash irc channel on freenode or to email
17
+ # the logstash-users@googlegroups.com mailling list and ask for help! :)
18
+ config :match, :validate => :hash, :deprecated => true
19
+
20
+ # The fully-qualified email address to send the email to.
21
+ #
22
+ # This field also accepts a comma-separated string of addresses, for example:
23
+ # "me@host.com, you@host.com"
24
+ #
25
+ # You can also use dynamic fields from the event with the %{fieldname} syntax.
26
+ config :to, :validate => :string, :required => true
27
+
28
+ # The fully-qualified email address for the From: field in the email.
29
+ config :from, :validate => :string, :default => "logstash.alert@nowhere.com"
30
+
31
+ # The fully qualified email address for the Reply-To: field.
32
+ config :replyto, :validate => :string
33
+
34
+ # The fully-qualified email address(es) to include as cc: address(es).
35
+ #
36
+ # This field also accepts a comma-separated string of addresses, for example:
37
+ # "me@host.com, you@host.com"
38
+ config :cc, :validate => :string
39
+
40
+ # How Logstash should send the email, either via SMTP or by invoking sendmail.
41
+ config :via, :validate => :string, :default => "smtp"
42
+
43
+ # Specify the options to use:
44
+ #
45
+ # Via SMTP: smtpIporHost, port, domain, userName, password, authenticationType, starttls
46
+ #
47
+ # Via sendmail: location, arguments
48
+ #
49
+ # If you do not specify any `options`, you will get the following equivalent code set in
50
+ # every new mail object:
51
+ #
52
+ # Mail.defaults do
53
+ # delivery_method :smtp, { :smtpIporHost => "localhost",
54
+ # :port => 25,
55
+ # :domain => 'localhost.localdomain',
56
+ # :userName => nil,
57
+ # :password => nil,
58
+ # :authenticationType => nil,(plain, login and cram_md5)
59
+ # :starttls => true }
60
+ #
61
+ # retriever_method :pop3, { :address => "localhost",
62
+ # :port => 995,
63
+ # :user_name => nil,
64
+ # :password => nil,
65
+ # :enable_ssl => true }
66
+ #
67
+ # Mail.delivery_method.new #=> Mail::SMTP instance
68
+ # Mail.retriever_method.new #=> Mail::POP3 instance
69
+ # end
70
+ #
71
+ # Each mail object inherits the defaults set in Mail.delivery_method. However, on
72
+ # a per email basis, you can override the method:
73
+ #
74
+ # mail.delivery_method :sendmail
75
+ #
76
+ # Or you can override the method and pass in settings:
77
+ #
78
+ # mail.delivery_method :sendmail, { :address => 'some.host' }
79
+ #
80
+ # You can also just modify the settings:
81
+ #
82
+ # mail.delivery_settings = { :address => 'some.host' }
83
+ #
84
+ # The hash you supply is just merged against the defaults with "merge!" and the result
85
+ # assigned to the mail object. For instance, the above example will change only the
86
+ # `:address` value of the global `smtp_settings` to be 'some.host', retaining all other values.
87
+ config :options, :validate => :hash, :default => {}
88
+
89
+ # Subject: for the email.
90
+ config :subject, :validate => :string, :default => ""
91
+
92
+ # Body for the email - plain text only.
93
+ config :body, :validate => :string, :default => ""
94
+
95
+ # HTML Body for the email, which may contain HTML markup.
96
+ config :htmlbody, :validate => :string, :default => ""
97
+
98
+ # Attachments - specify the name(s) and location(s) of the files.
99
+ config :attachments, :validate => :array, :default => []
100
+
101
+ # contenttype : for multipart messages, set the content-type and/or charset of the HTML part.
102
+ # NOTE: this may not be functional (KH)
103
+ config :contenttype, :validate => :string, :default => "text/html; charset=UTF-8"
104
+
105
+ public
106
+ def register
107
+ require "mail"
108
+
109
+ # Mail uses instance_eval which changes the scope of self so @options is
110
+ # inaccessible from inside 'Mail.defaults'. So set a local variable instead.
111
+ options = @options
112
+
113
+ if @via == "smtp"
114
+ Mail.defaults do
115
+ delivery_method :smtp, {
116
+ :address => options.fetch("smtpIporHost", "localhost"),
117
+ :port => options.fetch("port", 25),
118
+ :domain => options.fetch("domain", "localhost"),
119
+ :user_name => options.fetch("userName", nil),
120
+ :password => options.fetch("password", nil),
121
+ :authentication => options.fetch("authenticationType", nil),
122
+ :enable_starttls_auto => options.fetch("starttls", false),
123
+ :debug => options.fetch("debug", false)
124
+ }
125
+ end
126
+ elsif @via == 'sendmail'
127
+ Mail.defaults do
128
+ delivery_method :sendmail
129
+ end
130
+ else
131
+ Mail.defaults do
132
+ delivery_method :@via, options
133
+ end
134
+ end # @via tests
135
+ @logger.debug("Email Output Registered!", :config => @config)
136
+ end # def register
137
+
138
+ public
139
+ def receive(event)
140
+ return unless output?(event)
141
+ @logger.debug("Event being tested for Email", :tags => @tags, :event => event)
142
+ # Set Intersection - returns a new array with the items that are the same between the two
143
+ if !@tags.empty? && (event["tags"] & @tags).size == 0
144
+ # Skip events that have no tags in common with what we were configured
145
+ @logger.debug("No Tags match for Email Output!")
146
+ return
147
+ end
148
+
149
+ @logger.debug? && @logger.debug("Match data for Email - ", :match => @match)
150
+ successful = false
151
+ matchName = ""
152
+ operator = ""
153
+
154
+ # TODO(sissel): Delete this once match support is removed.
155
+ @match && @match.each do |name, query|
156
+ if successful
157
+ break
158
+ else
159
+ matchName = name
160
+ end
161
+ # now loop over the csv query
162
+ queryArray = query.split(',')
163
+ index = 1
164
+ while index < queryArray.length
165
+ field = queryArray.at(index -1)
166
+ value = queryArray.at(index)
167
+ index = index + 2
168
+ if field == ""
169
+ if value.downcase == "and"
170
+ operator = "and"
171
+ elsif value.downcase == "or"
172
+ operator = "or"
173
+ else
174
+ operator = "or"
175
+ @logger.error("Operator Provided Is Not Found, Currently We Only Support AND/OR Values! - defaulting to OR")
176
+ end
177
+ else
178
+ hasField = event[field]
179
+ @logger.debug? and @logger.debug("Does Event Contain Field - ", :hasField => hasField)
180
+ isValid = false
181
+ # if we have maching field and value is wildcard - we have a success
182
+ if hasField
183
+ if value == "*"
184
+ isValid = true
185
+ else
186
+ # we get an array so we need to loop over the values and find if we have a match
187
+ eventFieldValues = event[field]
188
+ @logger.debug? and @logger.debug("Event Field Values - ", :eventFieldValues => eventFieldValues)
189
+ eventFieldValues = [eventFieldValues] if not eventFieldValues.respond_to?(:each)
190
+ eventFieldValues.each do |eventFieldValue|
191
+ isValid = validateValue(eventFieldValue, value)
192
+ if isValid # no need to iterate any further
193
+ @logger.debug("VALID CONDITION FOUND - ", :eventFieldValue => eventFieldValue, :value => value)
194
+ break
195
+ end
196
+ end # end eventFieldValues.each do
197
+ end # end value == "*"
198
+ end # end hasField
199
+ # if we have an AND operator and we have a successful == false break
200
+ if operator == "and" && !isValid
201
+ successful = false
202
+ elsif operator == "or" && (isValid || successful)
203
+ successful = true
204
+ else
205
+ successful = isValid
206
+ end
207
+ end
208
+ end
209
+ end # @match.each do
210
+
211
+ # The 'match' setting is deprecated and optional. If not set,
212
+ # default to success.
213
+ successful = true if @match.nil?
214
+
215
+ @logger.debug? && @logger.debug("Email Did we match any alerts for event : ", :successful => successful)
216
+
217
+ if successful
218
+ # first add our custom field - matchName - so we can use it in the sprintf function
219
+ event["matchName"] = matchName unless matchName.empty?
220
+ @logger.debug? and @logger.debug("Creating mail with these settings : ", :via => @via, :options => @options, :from => @from, :to => @to, :cc => @cc, :subject => @subject, :body => @body, :content_type => @contenttype, :htmlbody => @htmlbody, :attachments => @attachments, :to => to, :to => to)
221
+ formatedSubject = event.sprintf(@subject)
222
+ formattedBody = event.sprintf(@body)
223
+ formattedHtmlBody = event.sprintf(@htmlbody)
224
+ # we have a match(s) - send email
225
+ mail = Mail.new
226
+ mail.from = event.sprintf(@from)
227
+ mail.to = event.sprintf(@to)
228
+ if @replyto
229
+ mail.reply_to = event.sprintf(@replyto)
230
+ end
231
+ mail.cc = event.sprintf(@cc)
232
+ mail.subject = formatedSubject
233
+ if @htmlbody.empty?
234
+ formattedBody.gsub!(/\\n/, "\n") # Take new line in the email
235
+ mail.body = formattedBody
236
+ else
237
+ mail.text_part = Mail::Part.new do
238
+ content_type "text/plain; charset=UTF-8"
239
+ formattedBody.gsub!(/\\n/, "\n") # Take new line in the email
240
+ body formattedBody
241
+ end
242
+ mail.html_part = Mail::Part.new do
243
+ content_type "text/html; charset=UTF-8"
244
+ body formattedHtmlBody
245
+ end
246
+ end
247
+ @attachments.each do |fileLocation|
248
+ mail.add_file(fileLocation)
249
+ end # end @attachments.each
250
+ @logger.debug? and @logger.debug("Sending mail with these values : ", :from => mail.from, :to => mail.to, :cc => mail.cc, :subject => mail.subject)
251
+ mail.deliver!
252
+ end # end if successful
253
+ end # def receive
254
+
255
+
256
+ private
257
+ def validateValue(eventFieldValue, value)
258
+ valid = false
259
+ # order of this if-else is important - please don't change it
260
+ if value.start_with?(">=")# greater than or equal
261
+ value.gsub!(">=","")
262
+ if eventFieldValue.to_i >= value.to_i
263
+ valid = true
264
+ end
265
+ elsif value.start_with?("<=")# less than or equal
266
+ value.gsub!("<=","")
267
+ if eventFieldValue.to_i <= value.to_i
268
+ valid = true
269
+ end
270
+ elsif value.start_with?(">")# greater than
271
+ value.gsub!(">","")
272
+ if eventFieldValue.to_i > value.to_i
273
+ valid = true
274
+ end
275
+ elsif value.start_with?("<")# less than
276
+ value.gsub!("<","")
277
+ if eventFieldValue.to_i < value.to_i
278
+ valid = true
279
+ end
280
+ elsif value.start_with?("*")# contains
281
+ value.gsub!("*","")
282
+ if eventFieldValue.include?(value)
283
+ valid = true
284
+ end
285
+ elsif value.start_with?("!*")# does not contain
286
+ value.gsub!("!*","")
287
+ if !eventFieldValue.include?(value)
288
+ valid = true
289
+ end
290
+ elsif value.start_with?("!")# not equal
291
+ value.gsub!("!","")
292
+ if eventFieldValue != value
293
+ valid = true
294
+ end
295
+ else # default equal
296
+ if eventFieldValue == value
297
+ valid = true
298
+ end
299
+ end
300
+ return valid
301
+ end # end validateValue()
302
+
303
+ end # class LogStash::Outputs::Email
@@ -0,0 +1,28 @@
1
+ Gem::Specification.new do |s|
2
+
3
+ s.name = 'logstash-output-email'
4
+ s.version = '0.1.0'
5
+ s.licenses = ['Apache License (2.0)']
6
+ s.summary = "Send email when an output is received."
7
+ s.description = "Send email when an output is received."
8
+ s.authors = ["Elasticsearch"]
9
+ s.email = 'richard.pijnenburg@elasticsearch.com'
10
+ s.homepage = "http://logstash.net/"
11
+ s.require_paths = ["lib"]
12
+
13
+ # Files
14
+ s.files = `git ls-files`.split($\)+::Dir.glob('vendor/*')
15
+
16
+ # Tests
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+
19
+ # Special flag to let us know this is actually a logstash plugin
20
+ s.metadata = { "logstash_plugin" => "true", "group" => "output" }
21
+
22
+ # Gem dependencies
23
+ s.add_runtime_dependency 'logstash', '>= 1.4.0', '< 2.0.0'
24
+
25
+ s.add_runtime_dependency 'mail'
26
+
27
+ end
28
+
@@ -0,0 +1,9 @@
1
+ require "gem_publisher"
2
+
3
+ desc "Publish gem to RubyGems.org"
4
+ task :publish_gem do |t|
5
+ gem_file = Dir.glob(File.expand_path('../*.gemspec',File.dirname(__FILE__))).first
6
+ gem = GemPublisher.publish_if_updated(gem_file, :rubygems)
7
+ puts "Published #{gem}" if gem
8
+ end
9
+
@@ -0,0 +1,169 @@
1
+ require "net/http"
2
+ require "uri"
3
+ require "digest/sha1"
4
+
5
+ def vendor(*args)
6
+ return File.join("vendor", *args)
7
+ end
8
+
9
+ directory "vendor/" => ["vendor"] do |task, args|
10
+ mkdir task.name
11
+ end
12
+
13
+ def fetch(url, sha1, output)
14
+
15
+ puts "Downloading #{url}"
16
+ actual_sha1 = download(url, output)
17
+
18
+ if actual_sha1 != sha1
19
+ fail "SHA1 does not match (expected '#{sha1}' but got '#{actual_sha1}')"
20
+ end
21
+ end # def fetch
22
+
23
+ def file_fetch(url, sha1)
24
+ filename = File.basename( URI(url).path )
25
+ output = "vendor/#{filename}"
26
+ task output => [ "vendor/" ] do
27
+ begin
28
+ actual_sha1 = file_sha1(output)
29
+ if actual_sha1 != sha1
30
+ fetch(url, sha1, output)
31
+ end
32
+ rescue Errno::ENOENT
33
+ fetch(url, sha1, output)
34
+ end
35
+ end.invoke
36
+
37
+ return output
38
+ end
39
+
40
+ def file_sha1(path)
41
+ digest = Digest::SHA1.new
42
+ fd = File.new(path, "r")
43
+ while true
44
+ begin
45
+ digest << fd.sysread(16384)
46
+ rescue EOFError
47
+ break
48
+ end
49
+ end
50
+ return digest.hexdigest
51
+ ensure
52
+ fd.close if fd
53
+ end
54
+
55
+ def download(url, output)
56
+ uri = URI(url)
57
+ digest = Digest::SHA1.new
58
+ tmp = "#{output}.tmp"
59
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => (uri.scheme == "https")) do |http|
60
+ request = Net::HTTP::Get.new(uri.path)
61
+ http.request(request) do |response|
62
+ fail "HTTP fetch failed for #{url}. #{response}" if [200, 301].include?(response.code)
63
+ size = (response["content-length"].to_i || -1).to_f
64
+ count = 0
65
+ File.open(tmp, "w") do |fd|
66
+ response.read_body do |chunk|
67
+ fd.write(chunk)
68
+ digest << chunk
69
+ if size > 0 && $stdout.tty?
70
+ count += chunk.bytesize
71
+ $stdout.write(sprintf("\r%0.2f%%", count/size * 100))
72
+ end
73
+ end
74
+ end
75
+ $stdout.write("\r \r") if $stdout.tty?
76
+ end
77
+ end
78
+
79
+ File.rename(tmp, output)
80
+
81
+ return digest.hexdigest
82
+ rescue SocketError => e
83
+ puts "Failure while downloading #{url}: #{e}"
84
+ raise
85
+ ensure
86
+ File.unlink(tmp) if File.exist?(tmp)
87
+ end # def download
88
+
89
+ def untar(tarball, &block)
90
+ require "archive/tar/minitar"
91
+ tgz = Zlib::GzipReader.new(File.open(tarball))
92
+ # Pull out typesdb
93
+ tar = Archive::Tar::Minitar::Input.open(tgz)
94
+ tar.each do |entry|
95
+ path = block.call(entry)
96
+ next if path.nil?
97
+ parent = File.dirname(path)
98
+
99
+ mkdir_p parent unless File.directory?(parent)
100
+
101
+ # Skip this file if the output file is the same size
102
+ if entry.directory?
103
+ mkdir path unless File.directory?(path)
104
+ else
105
+ entry_mode = entry.instance_eval { @mode } & 0777
106
+ if File.exists?(path)
107
+ stat = File.stat(path)
108
+ # TODO(sissel): Submit a patch to archive-tar-minitar upstream to
109
+ # expose headers in the entry.
110
+ entry_size = entry.instance_eval { @size }
111
+ # If file sizes are same, skip writing.
112
+ next if stat.size == entry_size && (stat.mode & 0777) == entry_mode
113
+ end
114
+ puts "Extracting #{entry.full_name} from #{tarball} #{entry_mode.to_s(8)}"
115
+ File.open(path, "w") do |fd|
116
+ # eof? check lets us skip empty files. Necessary because the API provided by
117
+ # Archive::Tar::Minitar::Reader::EntryStream only mostly acts like an
118
+ # IO object. Something about empty files in this EntryStream causes
119
+ # IO.copy_stream to throw "can't convert nil into String" on JRuby
120
+ # TODO(sissel): File a bug about this.
121
+ while !entry.eof?
122
+ chunk = entry.read(16384)
123
+ fd.write(chunk)
124
+ end
125
+ #IO.copy_stream(entry, fd)
126
+ end
127
+ File.chmod(entry_mode, path)
128
+ end
129
+ end
130
+ tar.close
131
+ File.unlink(tarball) if File.file?(tarball)
132
+ end # def untar
133
+
134
+ def ungz(file)
135
+
136
+ outpath = file.gsub('.gz', '')
137
+ tgz = Zlib::GzipReader.new(File.open(file))
138
+ begin
139
+ File.open(outpath, "w") do |out|
140
+ IO::copy_stream(tgz, out)
141
+ end
142
+ File.unlink(file)
143
+ rescue
144
+ File.unlink(outpath) if File.file?(outpath)
145
+ raise
146
+ end
147
+ tgz.close
148
+ end
149
+
150
+ desc "Process any vendor files required for this plugin"
151
+ task "vendor" do |task, args|
152
+
153
+ @files.each do |file|
154
+ download = file_fetch(file['url'], file['sha1'])
155
+ if download =~ /.tar.gz/
156
+ prefix = download.gsub('.tar.gz', '').gsub('vendor/', '')
157
+ untar(download) do |entry|
158
+ if !file['files'].nil?
159
+ next unless file['files'].include?(entry.full_name.gsub(prefix, ''))
160
+ out = entry.full_name.split("/").last
161
+ end
162
+ File.join('vendor', out)
163
+ end
164
+ elsif download =~ /.gz/
165
+ ungz(download)
166
+ end
167
+ end
168
+
169
+ end
@@ -0,0 +1,173 @@
1
+ require "spec_helper"
2
+ require "rumbster"
3
+ require "message_observers"
4
+
5
+ describe "outputs/email", :broken => true do
6
+
7
+
8
+ @@port=2525
9
+ let (:rumbster) { Rumbster.new(@@port) }
10
+ let (:message_observer) { MailMessageObserver.new }
11
+
12
+ before :each do
13
+ rumbster.add_observer message_observer
14
+ rumbster.start
15
+ end
16
+
17
+ after :each do
18
+ rumbster.stop
19
+ end
20
+
21
+ describe "use a list of email as mail.to (LOGSTASH-827)" do
22
+ config <<-CONFIG
23
+ input {
24
+ generator {
25
+ message => "hello world"
26
+ count => 1
27
+ type => "generator"
28
+ }
29
+ }
30
+ filter {
31
+ noop {
32
+ add_field => ["dummy_match", "ok"]
33
+ }
34
+ }
35
+ output{
36
+ email {
37
+ to => "email1@host, email2@host"
38
+ match => ["mymatch", "dummy_match,ok"]
39
+ options => ["port", #{@@port}]
40
+ }
41
+ }
42
+ CONFIG
43
+
44
+ agent do
45
+ insist {message_observer.messages.size} == 1
46
+ insist {message_observer.messages[0].to} == ["email1@host", "email2@host"]
47
+ end
48
+ end
49
+
50
+ describe "use an array of email as mail.to (LOGSTASH-827)" do
51
+ config <<-CONFIG
52
+ input {
53
+ generator {
54
+ message => "hello world"
55
+ count => 1
56
+ type => "generator"
57
+ }
58
+ }
59
+ filter {
60
+ noop {
61
+ add_field => ["dummy_match", "ok"]
62
+ add_field => ["to_addr", "email1@host"]
63
+ add_field => ["to_addr", "email2@host"]
64
+ }
65
+ }
66
+ output{
67
+ email {
68
+ to => "%{to_addr}"
69
+ match => ["mymatch", "dummy_match,ok"]
70
+ options => ["port", #{@@port}]
71
+ }
72
+ }
73
+ CONFIG
74
+
75
+ agent do
76
+ insist {message_observer.messages.size} == 1
77
+ insist {message_observer.messages[0].to} == ["email1@host", "email2@host"]
78
+ end
79
+ end
80
+
81
+ describe "multi-lined text body (LOGSTASH-841)" do
82
+ config <<-CONFIG
83
+ input {
84
+ generator {
85
+ message => "hello world"
86
+ count => 1
87
+ type => "generator"
88
+ }
89
+ }
90
+ filter {
91
+ noop {
92
+ add_field => ["dummy_match", "ok"]
93
+ }
94
+ }
95
+ output{
96
+ email {
97
+ to => "me@host"
98
+ subject => "Hello World"
99
+ body => "Line1\\nLine2\\nLine3"
100
+ match => ["mymatch", "dummy_match,*"]
101
+ options => ["port", #{@@port}]
102
+ }
103
+ }
104
+ CONFIG
105
+
106
+ agent do
107
+ insist {message_observer.messages.size} == 1
108
+ insist {message_observer.messages[0].subject} == "Hello World"
109
+ insist {message_observer.messages[0].body.raw_source} == "Line1\r\nLine2\r\nLine3"
110
+ end
111
+ end
112
+
113
+ describe "use nil authenticationType (LOGSTASH-559)" do
114
+ config <<-CONFIG
115
+ input {
116
+ generator {
117
+ message => "hello world"
118
+ count => 1
119
+ type => "generator"
120
+ }
121
+ }
122
+ filter {
123
+ noop {
124
+ add_field => ["dummy_match", "ok"]
125
+ }
126
+ }
127
+ output{
128
+ email {
129
+ to => "me@host"
130
+ subject => "Hello World"
131
+ body => "Line1\\nLine2\\nLine3"
132
+ match => ["mymatch", "dummy_match,*"]
133
+ options => ["port", #{@@port}, "authenticationType", "nil"]
134
+ }
135
+ }
136
+ CONFIG
137
+
138
+ agent do
139
+ insist {message_observer.messages.size} == 1
140
+ insist {message_observer.messages[0].subject} == "Hello World"
141
+ insist {message_observer.messages[0].body.raw_source} == "Line1\r\nLine2\r\nLine3"
142
+ end
143
+ end
144
+
145
+ describe "match on source and message (LOGSTASH-826)" do
146
+ config <<-CONFIG
147
+ input {
148
+ generator {
149
+ message => "hello world"
150
+ count => 1
151
+ type => "generator"
152
+ }
153
+ }
154
+ output{
155
+ email {
156
+ to => "me@host"
157
+ subject => "Hello World"
158
+ body => "Mail body"
159
+ match => ["messageAndSourceMatch", "message,*hello,,and,source,*generator"]
160
+ options => ["port", #{@@port}, "authenticationType", "nil"]
161
+ }
162
+ }
163
+ CONFIG
164
+
165
+ agent do
166
+ insist {message_observer.messages.size} == 1
167
+ insist {message_observer.messages[0].subject} == "Hello World"
168
+ insist {message_observer.messages[0].body.raw_source} == "Mail body"
169
+ end
170
+ end
171
+ end
172
+
173
+
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-output-email
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Elasticsearch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: logstash
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.4.0
20
+ - - <
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.0
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: mail
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ description: Send email when an output is received.
48
+ email: richard.pijnenburg@elasticsearch.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - Gemfile
55
+ - Rakefile
56
+ - lib/logstash/outputs/email.rb
57
+ - logstash-output-email.gemspec
58
+ - rakelib/publish.rake
59
+ - rakelib/vendor.rake
60
+ - spec/outputs/email_spec.rb
61
+ homepage: http://logstash.net/
62
+ licenses:
63
+ - Apache License (2.0)
64
+ metadata:
65
+ logstash_plugin: 'true'
66
+ group: output
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.4.1
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Send email when an output is received.
87
+ test_files:
88
+ - spec/outputs/email_spec.rb