1 #!/usr/bin/env python |
1 #!/usr/bin/env python |
2 # -*- coding: utf-8 -*- |
2 # -*- coding: utf-8 -*- |
3 # Copyright 2009 Pascal Volk |
3 # Copyright 2009 Pascal Volk |
4 |
4 |
5 __author__ = 'Pascal Volk' |
5 __author__ = 'Pascal Volk' |
6 __version__ = '0.1' |
6 __version__ = '0.1.1' |
7 __date__ = '2009-06-07' |
7 __date__ = '2009-06-07' |
8 |
8 |
9 import os |
9 import os |
10 import re |
10 import re |
11 |
11 |
12 class NiXSpamPlot: |
12 class NiXSapmSum: |
13 """Do sth ...""" |
13 """Do sth ...""" |
14 |
14 |
15 """Regular expression pattern for mail logs from Postfix""" |
15 """Regular expression pattern for mail logs from Postfix""" |
16 RE_PF = '''^[\w\s:-]{17,80}\spostfix\/smtpd\[[\d]{3,5}\]: NOQUEUE: reject:.*blocked using ix.dnsbl.manitu.net; Spam sent to the mailhost ((?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}) was detected by NiX Spam.*$''' |
16 RE_PF = '''^[\w\s:-]{17,80}\spostfix\/smtpd\[[\d]{3,5}\]: NOQUEUE: reject:.*blocked using ix.dnsbl.manitu.net; Spam sent to the mailhost ((?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}) was detected by NiX Spam.*$''' |
17 |
17 |
20 self._mxs = {} |
20 self._mxs = {} |
21 self._repo = None |
21 self._repo = None |
22 |
22 |
23 def setLogFormat(self, format='postfix'): |
23 def setLogFormat(self, format='postfix'): |
24 if format == 'postfix': |
24 if format == 'postfix': |
25 self._repo = re.compile(NiXSpamPlot.RE_PF) |
25 self._repo = re.compile(NiXSapmSum.RE_PF) |
26 else: |
26 else: |
27 raise Exception('MTA/Logformat not supported yet.') |
27 raise Exception('MTA/Logformat not supported yet.') |
28 |
28 |
29 def parseLog(self, filehandle): |
29 def parseLog(self, filehandle): |
30 for l in filehandle: |
30 for l in filehandle: |
53 def getTotal(self): |
53 def getTotal(self): |
54 return sum(self._mxs.values()) |
54 return sum(self._mxs.values()) |
55 |
55 |
56 def getOptionParser(): |
56 def getOptionParser(): |
57 from optparse import OptionParser |
57 from optparse import OptionParser |
|
58 description = 'do something ...' |
58 usage = 'usage: %prog [options] maillog [maillog [...]]' |
59 usage = 'usage: %prog [options] maillog [maillog [...]]' |
59 parser = OptionParser(usage=usage, description='do something ...') |
60 version = '%prog '+__version__ |
|
61 parser = OptionParser(description=description,usage=usage,version=version) |
60 parser.add_option('-d', action='store_true', dest='countByDom', |
62 parser.add_option('-d', action='store_true', dest='countByDom', |
61 default=False, help='summarize all MX by domain') |
63 default=False, help='summarize all MX by domain') |
62 parser.add_option('-m', action='store_false', dest='countByDom', |
64 parser.add_option('-m', action='store_false', dest='countByDom', |
63 help='count per MX host [default]') |
65 help='count per MX host [default]') |
64 parser.add_option('-o', dest='oFormat', default='table',metavar='FORMAT', |
66 parser.add_option('-o', dest='oFormat', default='table',metavar='FORMAT', |
77 return fh |
79 return fh |
78 except IOError, e: |
80 except IOError, e: |
79 os.sys.stderr.write('Warning: %s\nskipped file: %s\n' % (e.strerror, |
81 os.sys.stderr.write('Warning: %s\nskipped file: %s\n' % (e.strerror, |
80 fname)) |
82 fname)) |
81 |
83 |
82 def showResult(nixspamplot, options): |
84 def getDomLen(domainnames): |
|
85 dlen = 0 |
|
86 for d in domainnames: |
|
87 l = len(d) |
|
88 if l > dlen: |
|
89 dlen = l |
|
90 return dlen |
|
91 |
|
92 def showResult(nixspamsum, options): |
83 if options.countByDom: |
93 if options.countByDom: |
84 nixspamplot.countByDom() |
94 nixspamsum.countByDom() |
85 domains = nixspamplot.getDomains() |
95 domains = nixspamsum.getDomains() |
86 else: |
96 else: |
87 domains = nixspamplot.getMXs() |
97 domains = nixspamsum.getMXs() |
88 if options.percent: |
|
89 total = nixspamplot.getTotal() |
|
90 k = 0 if options.order == 'name' else 1 |
98 k = 0 if options.order == 'name' else 1 |
91 doms = sorted(domains.items(), lambda d,c: cmp(d[k],c[k]), reverse=k) |
99 doms = sorted(domains.items(), lambda d,c: cmp(d[k],c[k]), reverse=k) |
92 for d in doms: |
100 # print table |
93 print "%s -> %d" % d |
101 if options.oFormat == 'table': |
|
102 dlen = getDomLen(domains.keys())+1 |
|
103 clen = len(str(max(domains.values()))) |
|
104 if options.percent: |
|
105 total = nixspamsum.getTotal() |
|
106 format = '%%%ds %%%dd %%5.2f %%%%' % (dlen, clen) |
|
107 for d, c in doms: |
|
108 dfrac = 100./total*c |
|
109 print format % (d, c, dfrac) |
|
110 else: |
|
111 format = '%%%ds: %%%dd' % (dlen, clen) |
|
112 for d in doms: |
|
113 print format % d |
|
114 # print comma separated values |
|
115 elif options.oFormat == 'csv': |
|
116 for d in doms: |
|
117 print "'%s',%d" % d |
|
118 # print a hint ;-) |
|
119 else: |
|
120 print "Output format '%s' is not supported" % options.oFormat |
94 |
121 |
95 def main(): |
122 def main(): |
96 parser = getOptionParser() |
123 parser = getOptionParser() |
97 opts, args = parser.parse_args() |
124 opts, args = parser.parse_args() |
98 if len(args) < 1: |
125 if len(args) < 1: |
99 parser.error('No logfiles specified') |
126 parser.error('No logfiles specified') |
100 nsp = NiXSpamPlot() |
127 nixss = NiXSapmSum() |
101 nsp.setLogFormat(opts.format) |
128 nixss.setLogFormat(opts.format) |
102 for fn in args: |
129 for fn in args: |
103 fh = openLogFile(fn) |
130 fh = openLogFile(fn) |
104 if fh is not None: |
131 if fh is not None: |
105 nsp.parseLog(fh) |
132 nixss.parseLog(fh) |
106 fh.close() |
133 fh.close() |
107 showResult(nsp, opts) |
134 showResult(nixss, opts) |
108 |
135 |
109 if __name__ == '__main__': |
136 if __name__ == '__main__': |
110 main() |
137 main() |