fluent-plugin-sendmail 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 762057e467dfc06c0841eea887bd8e9fc72e8a75
4
+ data.tar.gz: 6a9091a8f37b174451ab2d988279914d608e215f
5
+ SHA512:
6
+ metadata.gz: f6da0f543c49864a99534a42576d6bb80e39be4f44b4b7a7a8473fcdd6357e217eb73e5a0b6b42de5ba8992190fea70f5a669172237c25ec10ee2f2cd9ee9619
7
+ data.tar.gz: ee3372514f3b16bbedcb1397256745066c048e5e233ffa0dba2d717204920f4e1511981d78758595d796b02230e7825b64eba1f8e3690d4a6c98eb3c6e568696
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1
7
+ - 2.2
8
+ - 2.3.0
9
+
10
+ script: bundle exec rake test
11
+ sudo: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ ## 0.0.0
2
+
3
+ First version
4
+
5
+ ## 0.1.0
6
+
7
+ added unit test
8
+ added unbundle mode
9
+
10
+
11
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-sendmail.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 muddydixon
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,246 @@
1
+ # Fluent::Plugin::Sendmail
2
+
3
+ Fluentd plugin to parse and merge sendmail syslog.
4
+
5
+ ## Configuration
6
+
7
+ ```
8
+ <source>
9
+ type sendmail
10
+ path ./syslog.log
11
+ pos_file ./syslog.log.pos
12
+ tag sendmail
13
+ </source>
14
+ ```
15
+
16
+ example of sendmail log
17
+
18
+ ```
19
+ Apr 2 00:15:25 mta001 sendmail[32300]: u31FFPtp032300: Milter: no active filter
20
+ Apr 2 00:15:25 mta001 sendmail[32300]: u31FFPtp032300: from=<grandeur09@gmail.com>, size=5938, class=0, nrcpts=5, msgid=<201604011515.u31FFIAj012911@gmail.com>, proto=ESMTP, daemon=MTA, relay=[64.233.187.27]
21
+ Apr 2 00:15:25 mta001 sendmail[32302]: u31FFPtp032300: SMTP outgoing connect on [192.168.198.81]
22
+ Apr 2 00:15:25 mta001 sendmail[32302]: u31FFPtp032300: to=<sent1@example.com>,<sent2@example.com>, 00:00:00, xdelay=00:00:00, mailer=esmtp, pri=245938, relay=[93.184.216.34] [93.184.216.34], dsn=2.0.0, stat=Sent (ok: Message 40279894 accepted)
23
+ Apr 2 00:15:25 mta001 sendmail[12566]: u31FFPtp032300: to=<deferred1@example.com>, delay=00:00:15, xdelay=00:00:15, mailer=esmtp, pri=34527, relay=[93.184.216.34] [93.184.216.34], dsn=4.3.5, stat=Deferred: 451 4.3.5 Server configuration problem
24
+ Apr 2 00:15:26 mta001 sendmail[32302]: u31FFPtp032300: to=<sent3@example2.com>,<sent4@example2.com>, delay=00:00:00, xdelay=00:00:00, mailer=esmtp, pri=245938, relay=[93.184.216.34] [93.184.216.34], dsn=2.0.0, stat=Sent (ok: Message 40279895 accepted)
25
+ Apr 2 00:18:50 mta001 sendmail[32302]: u31FFPtp032300: to=<deferred1@example.com>, delay=00:00:00, xdelay=00:00:00, mailer=esmtp, pri=245938, relay=[93.184.216.34] [93.184.216.34], dsn=2.0.0, stat=Sent (ok: Message 40279894 accepted)
26
+ Apr 2 00:15:25 mta001 sendmail[32302]: u31FFPtp032300: done; delay=00:00:00, ntries=2
27
+ ```
28
+
29
+ This plugin emit record like below:
30
+
31
+ ```
32
+ 2014-01-10 01:00:01 +0900 sendmail: {
33
+ "mta":"mta001",
34
+ "from":"<grandeur09@gmail.com>",
35
+ "relay":{
36
+ "ip":"64.233.187.27",
37
+ "host":null
38
+ },
39
+ "count":"5",
40
+ "size":"5938",
41
+ "msgid":"<201604011515.u31FFIAj012911@gmail.com>",
42
+ "popid":null,
43
+ "authid":null,
44
+ "to":[
45
+ {
46
+ "to":[
47
+ "<sent1@example.com>",
48
+ "<sent2@example.com>"
49
+ ],
50
+ "00:00:00":null,
51
+ "xdelay":"00:00:00",
52
+ "mailer":"esmtp",
53
+ "pri":"245938",
54
+ "relay":{
55
+ "ip":"93.184.216.34",
56
+ "host":null
57
+ },
58
+ "dsn":"2.0.0",
59
+ "stat":"Sent (ok: Message 40279894 accepted)"
60
+ },
61
+ {
62
+ "to":[
63
+ "<sent3@example2.com>",
64
+ "<sent4@example2.com>"
65
+ ],
66
+ "delay":"00:00:00",
67
+ "xdelay":"00:00:00",
68
+ "mailer":"esmtp",
69
+ "pri":"245938",
70
+ "relay":{
71
+ "ip":"93.184.216.34",
72
+ "host":null
73
+ },
74
+ "dsn":"2.0.0",
75
+ "stat":"Sent (ok: Message 40279895 accepted)"
76
+ },
77
+ {
78
+ "to":[
79
+ "<deferred1@example.com>"
80
+ ],
81
+ "delay":"00:00:00",
82
+ "xdelay":"00:00:00",
83
+ "mailer":"esmtp",
84
+ "pri":"245938",
85
+ "relay":{
86
+ "ip":"93.184.216.34",
87
+ "host":null
88
+ },
89
+ "dsn":"2.0.0",
90
+ "stat":"Sent (ok: Message 40279894 accepted)"
91
+ }
92
+ ]
93
+ }
94
+ ```
95
+
96
+ ### unbundle
97
+
98
+ unbundle mode
99
+
100
+ ```
101
+ <source>
102
+ type sendmail
103
+ path ./syslog.log
104
+ pos_file ./syslog.log.pos
105
+ tag sendmail
106
+ unbundle yes
107
+ </source>
108
+ ```
109
+
110
+ This plugin emit record like below:
111
+
112
+ ```
113
+ 2014-01-10 01:00:01 +0900 sendmail: {
114
+ "mta":"mta001",
115
+ "from":"<grandeur09@gmail.com>",
116
+ "relay":{
117
+ "ip":"93.184.216.34",
118
+ "host":null
119
+ },
120
+ "count":"5",
121
+ "size":"5938",
122
+ "msgid":"<201604011515.u31FFIAj012911@gmail.com>",
123
+ "popid":null,
124
+ "authid":null,
125
+ "to":"<sent1@example.com>",
126
+ "stat":"Sent (ok: Message 40279894 accepted)",
127
+ "dsn":"2.0.0",
128
+ "delay":null,
129
+ "xdelay":"00:00:00"
130
+ }
131
+
132
+ 2014-01-10 01:00:01 +0900 sendmail: {
133
+ "mta":"mta001",
134
+ "from":"<grandeur09@gmail.com>",
135
+ "relay":{
136
+ "ip":"93.184.216.34",
137
+ "host":null
138
+ },
139
+ "count":"5",
140
+ "size":"5938",
141
+ "msgid":"<201604011515.u31FFIAj012911@gmail.com>",
142
+ "popid":null,
143
+ "authid":null,
144
+ "to":"<sent2@example.com>",
145
+ "stat":"Sent (ok: Message 40279894 accepted)",
146
+ "dsn":"2.0.0",
147
+ "delay":null,
148
+ "xdelay":"00:00:00"
149
+ }
150
+
151
+ 2014-01-10 01:00:01 +0900 sendmail: {
152
+ "mta":"mta001",
153
+ "from":"<grandeur09@gmail.com>",
154
+ "relay":{
155
+ "ip":"93.184.216.34",
156
+ "host":null
157
+ },
158
+ "count":"5",
159
+ "size":"5938",
160
+ "msgid":"<201604011515.u31FFIAj012911@gmail.com>",
161
+ "popid":null,
162
+ "authid":null,
163
+ "to":"<deferred1@example.com>",
164
+ "stat":"Deferred: 451 4.3.5 Server configuration problem",
165
+ "dsn":"4.3.5",
166
+ "delay":"00:00:15",
167
+ "xdelay":"00:00:15"
168
+ }
169
+
170
+ 2014-01-10 01:00:01 +0900 sendmail: {
171
+ "mta":"mta001",
172
+ "from":"<grandeur09@gmail.com>",
173
+ "relay":{
174
+ "ip":"93.184.216.34",
175
+ "host":null
176
+ },
177
+ "count":"5",
178
+ "size":"5938",
179
+ "msgid":"<201604011515.u31FFIAj012911@gmail.com>",
180
+ "popid":null,
181
+ "authid":null,
182
+ "to":"<sent3@example2.com>",
183
+ "stat":"Sent (ok: Message 40279895 accepted)",
184
+ "dsn":"2.0.0",
185
+ "delay":"00:00:00",
186
+ "xdelay":"00:00:00"
187
+ }
188
+
189
+ 2014-01-10 01:00:01 +0900 sendmail: {
190
+ "mta":"mta001",
191
+ "from":"<grandeur09@gmail.com>",
192
+ "relay":{
193
+ "ip":"93.184.216.34",
194
+ "host":null
195
+ },
196
+ "count":"5",
197
+ "size":"5938",
198
+ "msgid":"<201604011515.u31FFIAj012911@gmail.com>",
199
+ "popid":null,
200
+ "authid":null,
201
+ "to":"<sent4@example2.com>",
202
+ "stat":"Sent (ok: Message 40279895 accepted)",
203
+ "dsn":"2.0.0",
204
+ "delay":"00:00:00",
205
+ "xdelay":"00:00:00"
206
+ }
207
+
208
+ 2014-01-10 01:00:01 +0900 sendmail: {
209
+ "mta":"mta001",
210
+ "from":"<grandeur09@gmail.com>",
211
+ "relay":{
212
+ "ip":"93.184.216.34",
213
+ "host":null
214
+ },
215
+ "count":"5",
216
+ "size":"5938",
217
+ "msgid":"<201604011515.u31FFIAj012911@gmail.com>",
218
+ "popid":null,
219
+ "authid":null,
220
+ "to":"<deferred1@example.com>",
221
+ "stat":"Sent (ok: Message 40279894 accepted)",
222
+ "dsn":"2.0.0",
223
+ "delay":"00:00:00",
224
+ "xdelay":"00:00:00"
225
+ }
226
+ ```
227
+
228
+ ## TODO
229
+
230
+ tracking bounce.
231
+
232
+ ## ChangeLog
233
+
234
+ See [CHANGELOG.md](CHANGELOG.md) for details.
235
+
236
+ ## Contributing
237
+
238
+ 1. Fork it
239
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
240
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
241
+ 4. Push to the branch (`git push origin my-new-feature`)
242
+ 5. Create new Pull Request
243
+
244
+ ## Copyright
245
+
246
+ Copyright (c) 2014 muddydixon. See [LICENSE](LICENSE) for details.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ test.pattern = 'test/**/test_*.rb'
7
+ test.verbose = true
8
+ end
9
+
10
+ task :default => :test
11
+
12
+ task :default => :spec
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "fluent-plugin-sendmail"
7
+ spec.version = "0.1.0"
8
+ spec.authors = ["muddydixon"]
9
+ spec.email = ["muddydixon@gmail.com"]
10
+ spec.summary = "Fluentd plugin to parse and merge sendmail syslog."
11
+ spec.description = spec.summary
12
+ spec.homepage = "https://github.com/muddydixon/fluent-plugin-sendmail"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+ spec.add_runtime_dependency("lru_redux", [">= 0.8.4"])
20
+ spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency 'test-unit'
22
+ spec.add_runtime_dependency "fluentd"
23
+ spec.add_development_dependency "rake"
24
+ end
@@ -0,0 +1,159 @@
1
+ # -*- coding: utf-8 -*-
2
+ class Fluent::SendmailInput < Fluent::TailInput
3
+ config_param :lrucache_size, :integer, :default => (1024*1024)
4
+
5
+ Fluent::Plugin.register_input('sendmail', self)
6
+
7
+ require_relative 'sendmailparser'
8
+ require 'pathname'
9
+ require 'lru_redux'
10
+
11
+ config_param :types, :string, :default => 'from,sent'
12
+ config_param :unbundle, :string, :default => 'no'
13
+
14
+ def initialize
15
+ super
16
+ @delivers = LruRedux::ThreadSafeCache.new(@lrucache_size)
17
+ end
18
+
19
+ def configure_parser(conf)
20
+ @parser = SendmailParser.new(conf)
21
+ if @unbundle == 'yes'
22
+ @do_unbundle = true
23
+ else
24
+ @do_unbundle = false
25
+ end
26
+ end
27
+
28
+ def receive_lines(lines)
29
+ es = Fluent::MultiEventStream.new
30
+ lines.each {|line|
31
+ begin
32
+ line.chomp! # remove \n
33
+ logline = parse_line(line)
34
+
35
+ if logline.nil?
36
+ next
37
+ end
38
+
39
+ type = logline["type"]
40
+ mta = logline["mta"]
41
+ qid = logline["qid"]
42
+ time = logline["time"]
43
+ # a qid is not uniq worldwide.
44
+ # make delivery id uniq even if multiple MTA's log are mixed.
45
+ deliveryid = mta + qid
46
+ type = logline["type"]
47
+ noncommon = logline["noncommon"]
48
+
49
+ case type
50
+ when :from
51
+ # new log
52
+ from = noncommon
53
+ record = from.record
54
+ @delivers[deliveryid] = SendmailLog.new(mta, time, record)
55
+ when :to
56
+ to = noncommon
57
+ status = to.status
58
+ record = noncommon.record
59
+ if @delivers.has_key?(deliveryid)
60
+ to = noncommon
61
+ status = to.status
62
+ case status
63
+ when :sent, :sent_local, :bounced
64
+ @delivers[deliveryid].dequeued(time, record)
65
+ if @do_unbundle
66
+ log_single(es, deliveryid, time, record)
67
+ end
68
+ # bulked queue in an attempt have been dequeued completely.
69
+ if @delivers[deliveryid].status == :all_dequeued
70
+ # bundled logs are outputed here
71
+ if not @do_unbundle
72
+ log_bundled(es, deliveryid, time)
73
+ end
74
+ # log.destroy
75
+ @delivers.delete(qid)
76
+ end
77
+ when :deferred
78
+ if @do_unbundle
79
+ log_single(es, deliveryid, time, record)
80
+ end
81
+ when :other
82
+ $log.warn "cannot find this kind of delivery status: " + line.dump
83
+ end
84
+ else
85
+ # cannot find any 'from' line corresponded to the 'to' line
86
+ end
87
+ end
88
+ rescue
89
+ $log.warn line.dump, :error=>$!.to_s
90
+ $log.debug_backtrace
91
+ end
92
+ }
93
+
94
+ unless es.empty?
95
+ begin
96
+ Fluent::Engine.emit_stream(@tag, es)
97
+ rescue
98
+ # ignore errors. Engine shows logs and backtraces.
99
+ end
100
+ end
101
+ end
102
+
103
+ def log_single(es, deliveryid, time, record)
104
+ log = @delivers[deliveryid]
105
+ records = log.record_unbundle(time, record)
106
+ for record in records do
107
+ es.add(time, record)
108
+ end
109
+ end
110
+
111
+ def log_bundled(es, deliveryid, time)
112
+ log = @delivers[deliveryid]
113
+ es.add(time, log.record)
114
+ end
115
+
116
+ end
117
+
118
+ class SendmailLog
119
+ attr_reader :status
120
+ attr_reader :time
121
+ def initialize(mta, time, record)
122
+ @mta = mta
123
+ @status = :init
124
+ @time = time
125
+ @tos = []
126
+ @from = record
127
+ @count = record["nrcpts"].to_i
128
+ end
129
+
130
+ def record
131
+ return {
132
+ "mta" => @mta,
133
+ "from" => @from,
134
+ "to" => @tos
135
+ }
136
+ end
137
+
138
+ def record_unbundle(time, record)
139
+ records_unbundled = []
140
+ for to in record["to"] do
141
+ record_single = record.dup
142
+ record_single["to"] = to
143
+ records_unbundled.push({
144
+ "mta" => @mta,
145
+ "from" => @from,
146
+ "to" => record_single
147
+ })
148
+ end
149
+ return records_unbundled
150
+ end
151
+
152
+ def dequeued(time, record)
153
+ @count = @count - record["to"].size
154
+ @tos.push(record)
155
+ if @count == 0
156
+ @status = :all_dequeued
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,133 @@
1
+ class SendmailParser
2
+ def initialize(conf)
3
+ @base_regexp = /^(?<time>\w+\s+\w+\s+\d+:\d+:\d+) (?<host>[^ ]+) (?<procowner>[^\[]+)\[(?<procid>\d+)\]: (?<qid>[^ ]+): (?<entry>(?<type>[^=]+).+)$/;
4
+ end
5
+
6
+ def parse(value)
7
+ m = @base_regexp.match(value)
8
+ unless m
9
+ # $log.warn "sendmail: pattern not match: #{value.inspect}"
10
+ return nil
11
+ end
12
+
13
+ logtype = m["type"]
14
+ entry = m["entry"]
15
+ mta = m["host"]
16
+ qid = m["qid"]
17
+ time = Time.parse(m["time"]).to_i || Fluent::Engine.now.to_i
18
+
19
+ logline = {
20
+ "type" => :from,
21
+ "mta" => mta,
22
+ "qid" => qid,
23
+ "time" => time,
24
+ "type" => nil,
25
+ "noncommon" => nil
26
+ }
27
+
28
+ case logtype
29
+ when "from"
30
+ fromline = self.from_parser(entry)
31
+ logline["type"] = :from
32
+ logline["noncommon"] = fromline
33
+ when "to"
34
+ toline = self.to_parser(entry)
35
+ logline["type"] = :to
36
+ logline["noncommon"] = toline
37
+ else
38
+ # not match
39
+ logline = nil
40
+ end
41
+
42
+ logline
43
+ end
44
+
45
+ def to_line(entry)
46
+ record = {}
47
+ status = nil
48
+
49
+ status = status_parser(entry)
50
+
51
+ entry.split(", ").each {|param|
52
+ key, val = param.split("=")
53
+ record[key] = val
54
+ }
55
+ record["to"] = record["to"].split(",")
56
+
57
+ if record.has_key?("relay")
58
+ record["relay"] = relay_parser(record["relay"])
59
+ end
60
+ ToLine.new(status, record)
61
+ end
62
+
63
+ def from_line(entry)
64
+ record = {}
65
+
66
+ entry.split(", ").each {|param|
67
+ key, val = param.split("=")
68
+ record[key] = val
69
+ }
70
+ if record.has_key?("relay")
71
+ record["relay"] = relay_parser(record["relay"])
72
+ end
73
+ FromLine.new(record)
74
+ end
75
+
76
+ def to_parser(entry)
77
+ to_line(entry)
78
+ end
79
+
80
+ def from_parser(entry)
81
+ from_line(entry)
82
+ end
83
+
84
+ def relay_parser(relays)
85
+ relay_host = nil
86
+ relay_ip = nil
87
+ relays.split(" ").each {|relay|
88
+ if relay.index("[") == 0
89
+ return {"ip" => trim_bracket(relay), "host" => relay_host}
90
+ else
91
+ relay_host = relay
92
+ end
93
+ }
94
+ return {"ip" => relay_ip, "host" => relay_host}
95
+ end
96
+
97
+ def trim_bracket(val)
98
+ val[1..-2]
99
+ end
100
+
101
+ def status_parser(entry)
102
+ if entry.include?("stat=Sent")
103
+ if entry.include?("mailer=local,")
104
+ return :sent_local
105
+ else
106
+ return :sent
107
+ end
108
+ elsif entry.include?("dsn=5.")
109
+ return :bounced
110
+ elsif entry.include?("stat=Deferred")
111
+ return :deferred
112
+ else
113
+ return :other
114
+ end
115
+ end
116
+ end
117
+
118
+ class FromLine
119
+ attr_reader :record
120
+ def initialize(record)
121
+ @record = record
122
+ end
123
+ end
124
+
125
+ class ToLine
126
+ attr_reader :status
127
+ attr_reader :record
128
+ def initialize(status, record)
129
+ @status = status
130
+ @record = record
131
+ @record["canonical_status"] = status.to_s
132
+ end
133
+ end
data/test/data/data1 ADDED
@@ -0,0 +1,9 @@
1
+ Apr 2 00:15:25 mta001 sendmail[32300]: u31FFPtp032300: Milter: no active filter
2
+ Apr 2 00:15:25 mta001 sendmail[32300]: u31FFPtp032300: from=<grandeur09@gmail.com>, size=5938, class=0, nrcpts=6, msgid=<201604011515.u31FFIAj012911@gmail.com>, proto=ESMTP, daemon=MTA, relay=[64.233.187.27]
3
+ Apr 2 00:15:25 mta001 sendmail[32302]: u31FFPtp032300: SMTP outgoing connect on [192.168.198.81]
4
+ Apr 2 00:15:25 mta001 sendmail[32302]: u31FFPtp032300: to=<sent1@example.com>,<sent2@example.com>, 00:00:00, xdelay=00:00:00, mailer=esmtp, pri=245938, relay=[93.184.216.34] [93.184.216.34], dsn=2.0.0, stat=Sent (ok: Message 40279894 accepted)
5
+ Apr 2 00:15:25 mta001 sendmail[12566]: u31FFPtp032300: to=<deferred1@example.com>, delay=00:00:15, xdelay=00:00:15, mailer=esmtp, pri=34527, relay=[93.184.216.34] [93.184.216.34], dsn=4.3.5, stat=Deferred: 451 4.3.5 Server configuration problem
6
+ Apr 2 00:15:26 mta001 sendmail[32302]: u31FFPtp032300: to=<sent3@example2.com>,<sent4@example2.com>, delay=00:00:00, xdelay=00:00:00, mailer=esmtp, pri=245938, relay=[93.184.216.34] [93.184.216.34], dsn=2.0.0, stat=Sent (ok: Message 40279895 accepted)
7
+ Apr 2 00:18:50 mta001 sendmail[32302]: u31FFPtp032300: to=<deferred1@example.com>, delay=00:00:00, xdelay=00:00:00, mailer=esmtp, pri=245938, relay=[93.184.216.34] [93.184.216.34], dsn=2.0.0, stat=Sent (ok: Message 40279894 accepted)
8
+ Apr 2 00:15:25 mta001 sendmail[32302]: u31FFPtp032300: done; delay=00:00:00, ntries=2
9
+ Apr 2 00:15:25 mta001 sendmail[32302]: u31FFPtp032300: to=root@localhost.localdomain, ctladdr=root@localhost.localdomain (0/0), delay=00:00:00, xdelay=00:00:00, mailer=local, pri=245938, dsn=2.0.0, stat=Sent
@@ -0,0 +1 @@
1
+ {"mta":"mta001","from": {"from":"<grandeur09@gmail.com>","size":"5938", "class":"0", "nrcpts":"6","msgid":"<201604011515.u31FFIAj012911@gmail.com>","proto":"ESMTP","daemon":"MTA","relay":{"ip":"64.233.187.27", "host":null}},"to":[{"to":["<sent1@example.com>", "<sent2@example.com>"],"00:00:00":null,"xdelay":"00:00:00","mailer":"esmtp","pri":"245938","relay":{"ip":"93.184.216.34", "host":null},"dsn":"2.0.0","stat":"Sent (ok: Message 40279894 accepted)","canonical_status":"sent"},{"to":["<sent3@example2.com>", "<sent4@example2.com>"],"delay":"00:00:00","xdelay":"00:00:00","mailer":"esmtp","pri":"245938","relay":{"ip":"93.184.216.34", "host":null},"dsn":"2.0.0","stat":"Sent (ok: Message 40279895 accepted)","canonical_status":"sent"},{"to":["<deferred1@example.com>"],"delay":"00:00:00","xdelay":"00:00:00","mailer":"esmtp","pri":"245938","relay":{"ip":"93.184.216.34", "host":null},"dsn":"2.0.0","stat":"Sent (ok: Message 40279894 accepted)","canonical_status":"sent"},{"to":["root@localhost.localdomain"],"ctladdr":"root@localhost.localdomain (0/0)","delay":"00:00:00","xdelay":"00:00:00","mailer":"local","pri":"245938","dsn":"2.0.0","stat":"Sent","canonical_status":"sent_local"}]}
@@ -0,0 +1,7 @@
1
+ {"mta":"mta001", "from":{"from":"<grandeur09@gmail.com>", "size":"5938", "class":"0", "nrcpts":"6", "msgid":"<201604011515.u31FFIAj012911@gmail.com>", "proto":"ESMTP", "daemon":"MTA", "relay":{"ip":"64.233.187.27", "host":null}}, "to":{"to":"<sent1@example.com>", "00:00:00":null, "xdelay":"00:00:00", "mailer":"esmtp", "pri":"245938", "relay":{"ip":"93.184.216.34", "host":null}, "dsn":"2.0.0", "stat":"Sent (ok: Message 40279894 accepted)", "canonical_status":"sent"}}
2
+ {"mta":"mta001", "from":{"from":"<grandeur09@gmail.com>", "size":"5938", "class":"0", "nrcpts":"6", "msgid":"<201604011515.u31FFIAj012911@gmail.com>", "proto":"ESMTP", "daemon":"MTA", "relay":{"ip":"64.233.187.27", "host":null}}, "to":{"to":"<sent2@example.com>", "00:00:00":null, "xdelay":"00:00:00", "mailer":"esmtp", "pri":"245938", "relay":{"ip":"93.184.216.34", "host":null}, "dsn":"2.0.0", "stat":"Sent (ok: Message 40279894 accepted)", "canonical_status":"sent"}}
3
+ {"mta":"mta001", "from":{"from":"<grandeur09@gmail.com>", "size":"5938", "class":"0", "nrcpts":"6", "msgid":"<201604011515.u31FFIAj012911@gmail.com>", "proto":"ESMTP", "daemon":"MTA", "relay":{"ip":"64.233.187.27", "host":null}}, "to":{"to":"<deferred1@example.com>", "delay":"00:00:15", "xdelay":"00:00:15", "mailer":"esmtp", "pri":"34527", "relay":{"ip":"93.184.216.34", "host":null}, "dsn":"4.3.5", "stat":"Deferred: 451 4.3.5 Server configuration problem", "canonical_status":"deferred"}}
4
+ {"mta":"mta001", "from":{"from":"<grandeur09@gmail.com>", "size":"5938", "class":"0", "nrcpts":"6", "msgid":"<201604011515.u31FFIAj012911@gmail.com>", "proto":"ESMTP", "daemon":"MTA", "relay":{"ip":"64.233.187.27", "host":null}}, "to":{"to":"<sent3@example2.com>", "delay":"00:00:00", "xdelay":"00:00:00", "mailer":"esmtp", "pri":"245938", "relay":{"ip":"93.184.216.34", "host":null}, "dsn":"2.0.0", "stat":"Sent (ok: Message 40279895 accepted)", "canonical_status":"sent"}}
5
+ {"mta":"mta001", "from":{"from":"<grandeur09@gmail.com>", "size":"5938", "class":"0", "nrcpts":"6", "msgid":"<201604011515.u31FFIAj012911@gmail.com>", "proto":"ESMTP", "daemon":"MTA", "relay":{"ip":"64.233.187.27", "host":null}}, "to":{"to":"<sent4@example2.com>", "delay":"00:00:00", "xdelay":"00:00:00", "mailer":"esmtp", "pri":"245938", "relay":{"ip":"93.184.216.34", "host":null}, "dsn":"2.0.0", "stat":"Sent (ok: Message 40279895 accepted)", "canonical_status":"sent"}}
6
+ {"mta":"mta001", "from":{"from":"<grandeur09@gmail.com>", "size":"5938", "class":"0", "nrcpts":"6", "msgid":"<201604011515.u31FFIAj012911@gmail.com>", "proto":"ESMTP", "daemon":"MTA", "relay":{"ip":"64.233.187.27", "host":null}}, "to":{"to":"<deferred1@example.com>", "delay":"00:00:00", "xdelay":"00:00:00", "mailer":"esmtp", "pri":"245938", "relay":{"ip":"93.184.216.34", "host":null}, "dsn":"2.0.0", "stat":"Sent (ok: Message 40279894 accepted)", "canonical_status":"sent"}}
7
+ {"mta":"mta001", "from":{"from":"<grandeur09@gmail.com>", "size":"5938", "class":"0", "nrcpts":"6", "msgid":"<201604011515.u31FFIAj012911@gmail.com>", "proto":"ESMTP", "daemon":"MTA", "relay":{"ip":"64.233.187.27", "host":null}}, "to":{"to":"root@localhost.localdomain", "ctladdr":"root@localhost.localdomain (0/0)", "delay":"00:00:00", "xdelay":"00:00:00", "mailer":"local", "pri":"245938", "dsn":"2.0.0", "stat":"Sent", "canonical_status":"sent_local"}}
data/test/helper.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+ require 'fluent/test'
15
+ unless ENV.has_key?('VERBOSE')
16
+ # nulllogger = Object.new
17
+ # nulllogger.instance_eval {|obj|
18
+ # def method_missing(method, *args)
19
+ # # pass
20
+ # end
21
+ # }
22
+ end
23
+
24
+ require 'fluent/plugin/in_tail'
25
+ require 'fluent/plugin/in_sendmail'
26
+
27
+ class Test::Unit::TestCase
28
+ end
@@ -0,0 +1,93 @@
1
+ require 'helper'
2
+ require 'json'
3
+
4
+ class SendmailInputTest < Test::Unit::TestCase
5
+ def setup
6
+ Fluent::Test.setup
7
+ end
8
+
9
+ TMP_DIR = File.dirname(__FILE__) + "/../tmp"
10
+ DATA_DIR = File.dirname(__FILE__) + "/../data"
11
+
12
+ CONFIG_UNBUNDLE = %[
13
+ path #{TMP_DIR}/sendmaillog
14
+ tag sendmail
15
+ unbundle yes
16
+ ]
17
+
18
+ CONFIG_BUNDLE = %[
19
+ path #{TMP_DIR}/sendmaillog
20
+ tag sendmail
21
+ unbundle no
22
+ ]
23
+
24
+ def setup
25
+ Fluent::Test.setup
26
+ FileUtils.rm_rf(TMP_DIR)
27
+ FileUtils.mkdir_p(TMP_DIR)
28
+ end
29
+
30
+ def create_driver(conf = CONFIG_UNBUNDLE, tag='test')
31
+ driver = Fluent::Test::InputTestDriver.new(Fluent::SendmailInput)
32
+ driver.configure(conf)
33
+ driver
34
+ end
35
+
36
+ def test_configure
37
+ #### set configurations
38
+ # d = create_driver %[
39
+ # path test_path
40
+ # compress gz
41
+ # ]
42
+ #### check configurations
43
+ # assert_equal 'test_path', d.instance.path
44
+ # assert_equal :gz, d.instance.compress
45
+ end
46
+
47
+ def test_unbundled
48
+ data_file = "#{DATA_DIR}/data1"
49
+ expect_file = "#{DATA_DIR}/data1_unbundle_result_expect"
50
+ driver = create_driver
51
+ do_test(driver, data_file, expect_file)
52
+ end
53
+
54
+ def test_bundled
55
+ data_file = "#{DATA_DIR}/data1"
56
+ expect_file = "#{DATA_DIR}/data1_bundle_result_expect"
57
+ driver = create_driver(conf=CONFIG_BUNDLE)
58
+ do_test(driver, data_file, expect_file)
59
+ end
60
+
61
+ def do_test(driver, data_file, expect_file)
62
+ lines = nil
63
+ path = driver.instance.paths[0].to_s
64
+
65
+ # touch tail file
66
+ File.open(path, "a") {}
67
+
68
+ # result_expect
69
+ expects = []
70
+ File.open(expect_file, "r") {|expectfile|
71
+ expectfile.each_line {|line|
72
+ expects.push(JSON.parse(line))
73
+ }
74
+ }
75
+
76
+ driver.run do
77
+ sleep 1
78
+ File.open(data_file, "r") {|srcfile|
79
+ File.open(path, "a") {|dstfile|
80
+ srcfile.each_line {|line|
81
+ dstfile.puts(line)
82
+ }
83
+ }
84
+ }
85
+ sleep 1
86
+ end
87
+
88
+ emits = driver.emits
89
+ emits.each_index {|i|
90
+ assert_equal(expects[i], emits[i][2])
91
+ }
92
+ end
93
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-sendmail
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - muddydixon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lru_redux
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: test-unit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: fluentd
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Fluentd plugin to parse and merge sendmail syslog.
84
+ email:
85
+ - muddydixon@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".travis.yml"
92
+ - CHANGELOG.md
93
+ - Gemfile
94
+ - LICENSE
95
+ - README.md
96
+ - Rakefile
97
+ - fluent-plugin-sendmail.gemspec
98
+ - lib/fluent/plugin/in_sendmail.rb
99
+ - lib/fluent/plugin/sendmailparser.rb
100
+ - test/data/data1
101
+ - test/data/data1_bundle_result_expect
102
+ - test/data/data1_unbundle_result_expect
103
+ - test/helper.rb
104
+ - test/plugin/test_in_sendmail.rb
105
+ homepage: https://github.com/muddydixon/fluent-plugin-sendmail
106
+ licenses:
107
+ - MIT
108
+ metadata: {}
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 2.4.8
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: Fluentd plugin to parse and merge sendmail syslog.
129
+ test_files:
130
+ - test/data/data1
131
+ - test/data/data1_bundle_result_expect
132
+ - test/data/data1_unbundle_result_expect
133
+ - test/helper.rb
134
+ - test/plugin/test_in_sendmail.rb