Initial check-in.
[monitoring/munin.git] / thh_exim_mailstats
CommitLineData
b2f0d2f3
TH
1#!/usr/bin/perl
2#
3# Plugin to monitor the number of mails received and delivered by exim.
4#
5# Usage: copy or link into /etc/munin/node.d/
6#
7# Parameters:
8#
9# config (required)
10# autoconf (optional - used by munin-config)
11#
12# Config variables:
13#
14# logdir - Override what exim says
15# exim - Where's exim?
16#
17# $Log$
18# Revision 1.7.2.2 2005/03/12 23:07:17 jimmyo
19# Avoid negative spike in generic/exim_mailstats.
20#
21# Revision 1.7.2.1 2005/03/09 19:24:12 jimmyo
22# Thanks to Stephen Gran, generic/exim_mailstats now graphs rejects (Deb#295799).
23#
24# Revision 1.7 2004/12/10 18:51:43 jimmyo
25# linux/apt* has been forced to LANG=C, to get predictable output.
26#
27# Revision 1.6 2004/12/10 10:47:47 jimmyo
28# Change name from ${scale} to ${graph_period}, to be more consistent.
29#
30# Revision 1.5 2004/12/09 22:12:54 jimmyo
31# Added "graph_period" option, to make "graph_sums" usable.
32#
33# Revision 1.4 2004/11/21 00:16:56 jimmyo
34# Changed a lot of plugins so they use DERIVE instead of COUNTER.
35#
36# Revision 1.3 2004/11/10 15:54:49 jimmyo
37# Applied patch from Torstein T. Svendsen to generic/exim_mailstats, to handle logfiles with timestamps in the name (SF#1055214)
38#
39# Revision 1.2 2004/05/20 13:57:12 jimmyo
40# Set categories to some of the plugins.
41#
42# Revision 1.1 2004/01/02 18:50:00 jimmyo
43# Renamed occurrances of lrrd -> munin
44#
45# Revision 1.1.1.1 2004/01/02 15:18:07 jimmyo
46# Import of LRRD CVS tree after renaming to Munin
47#
48# Revision 1.7 2003/11/15 11:10:28 jimmyo
49# Various fixes
50#
51# Revision 1.6 2003/11/07 17:43:16 jimmyo
52# Cleanups and log entries
53#
54#
55#
56# Magic markers (optional - used by munin-config and some installation
57# scripts):
58#
59#%# family=auto
60#%# capabilities=autoconf
61
62
63sub get_exim_logfile {
64 my ($spec, $type, $time) = @_;
65 chomp($spec);
66 $time = time() unless $time;
67 my $logfile = $spec;
68 $logfile =~ s/^log_file_path = //;
69 $logfile =~ s/\%s/$type/;
70
71 if( $logfile =~ /\%D/ ) {
72 my @t=localtime($time);
73 my $ts = sprintf("%04d%02d%02d",$t[5]+1900, $t[4]+1, $t[3]);
74 $logfile =~ s/\%D/$ts/g;
75 }
76 my @lfiles = split(/\s?:\s?/, $logfile);
77 foreach (@lfiles) {
78 return $_ unless /^syslog/;
79 }
80}
81
82
83
84$statefile = "/var/lib/munin/plugin-state/plugin-exim_mailstats.state";
85$pos = undef;
86$received = 0;
87$completed = 0;
88$rejected = 0;
89$greylisted = 0;
90$rbl = 0;
91$spam = 0;
92$sender = 0;
93$user = 0;
94$protocol = 0;
95$helo = 0;
96$virus = 0;
97$fakemx = 0;
98($dirname = $0) =~ s/[^\/]+$//;
99$EXIM = "/usr/sbin/exim";
100$EXIM = "/usr/sbin/exim4" if (-x "/usr/sbin/exim4"); # a Debianism
101$EXIM = $ENV{'exim'} if defined $ENV{'exim'};
102$EXIM = "/usr/exim/bin/exim";
103$LOGDIR = $ENV{'logdir'} || undef;
104
105if ( $ARGV[0] and $ARGV[0] eq "autoconf" )
106{
107 my $logfile;
108
109 if(defined($LOGDIR)) {
110 if(! -d $LOGDIR) {
111 print "no (logdir does not exist)\n";
112 exit(1);
113 }
114 $logfile = $LOGDIR . '/mainlog';
115 } else {
116 my $logfilespec = `$EXIM -bP log_file_path 2>/dev/null`;
117 if (! $?)
118 {
119 $logfile = get_exim_logfile( $logfilespec, 'main');
120 }
121 elsif ($? eq "127")
122 {
123 print "no (exim not found)\n";
124 }
125 else
126 {
127 print "no\n";
128 }
129 }
130
131 if ($logfile)
132 {
133 if (-r "$logfile")
134 {
135 print "yes\n";
136 exit 0;
137 }
138 else
139 {
140 print "no (logfile not readable)\n";
141 }
142 }
143 exit 1;
144}
145
146
147my $logfilespec;
148
149if(defined($LOGDIR)) {
150 $logfilespec = '';
151 $logfile = $LOGDIR . '/' . 'mainlog';
152} else {
153 $logfilespec = `$EXIM -bP log_file_path`;
154 $logfile = get_exim_logfile( $logfilespec, 'main');
155}
156
157exit 1 unless -r $logfile;
158
159if( $logfilespec =~ /\%D/ ) {
160 $rotlogfile = get_exim_logfile( $logfilespec, 'main', (time()-(24*60*60)));
161} else {
162if (-f "$logfile.0")
163{
164 $rotlogfile = $logfile . ".0";
165}
166elsif (-f "$logfile.1")
167{
168 $rotlogfile = $logfile . ".1";
169}
170elsif (-f "$logfile.01")
171{
172 $rotlogfile = $logfile . ".01";
173}
174else
175{
176 $rotlogfile = $logfile . ".0";
177}
178}
179
180if ( $ARGV[0] and $ARGV[0] eq "config" )
181{
182 print "graph_title Exim mail throughput\n";
183 print "graph_args --base 1000 -l 0\n";
184 print "graph_vlabel mails/\${graph_period}\n";
185 print "graph_scale no\n";
186 print "graph_category Mail\n";
187 print "received.label received\n";
188 print "received.type DERIVE\n";
189 print "received.min 0\n";
190 print "received.draw LINE\n";
191 print "completed.label completed\n";
192 print "completed.type DERIVE\n";
193 print "completed.min 0\n";
194# print "completed.draw AREA\n";
195 print "rejected.label rejected (other)\n";
196 print "rejected.type DERIVE\n";
197 print "rejected.min 0\n";
198# print "rejected.draw STACK\n";
199 print "rbl.label rejected (RBL)\n";
200 print "rbl.type DERIVE\n";
201 print "rbl.min 0\n";
202# print "rbl.draw STACK\n";
203 print "spam.label rejected (spam)\n";
204 print "spam.type DERIVE\n";
205 print "spam.min 0\n";
206# print "spam.draw STACK\n";
207 print "greylisted.label greylisted\n";
208 print "greylisted.type DERIVE\n";
209 print "greylisted.min 0\n";
210# print "greylisted.draw STACK\n";
211 print "sender.label rejected (sender verify)\n";
212 print "sender.type DERIVE\n";
213 print "sender.min 0\n";
214# print "sender.draw STACK\n";
215 print "user.label rejected (user unknown)\n";
216 print "user.type DERIVE\n";
217 print "user.min 0\n";
218# print "user.draw STACK\n";
219 print "protocol.label rejected (protocol violation)\n";
220 print "protocol.type DERIVE\n";
221 print "protocol.min 0\n";
222# print "protocol.draw STACK\n";
223 print "helo.label rejected (helo/ehlo)\n";
224 print "helo.type DERIVE\n";
225 print "helo.min 0\n";
226# print "helo.draw STACK\n";
227 print "virus.label rejected (virus)\n";
228 print "virus.type DERIVE\n";
229 print "virus.min 0\n";
230# print "virus.draw STACK\n";
231 print "fakemx.label rejected (fakeMX)\n";
232 print "fakemx.type DERIVE\n";
233 print "fakemx.min 0\n";
234# print "fakemx.draw STACK\n";
235 exit 0;
236}
237
238if (! -f $logfile and ! -f $rotlogfile)
239{
240 print "completed.value U\n";
241 print "received.value U\n";
242 print "rejected.value U\n";
243 print "greylisted.value U\n";
244 print "rbl.value U\n";
245 print "spam.value U\n";
246 print "sender.value U\n";
247 print "user.value U\n";
248 print "protocol.value U\n";
249 print "helo.value U\n";
250 print "virus.value U\n";
251 print "fakemx.value U\n";
252 exit 0;
253}
254
255if (-f "$statefile")
256{
257 open (IN, "$statefile") or exit 4;
258 my $in = <IN>;
259 if ($in =~ /^(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+)/)
260 {
261 ($pos, $received, $completed, $rejected, $greylisted, $rbl, $spam, $sender, $user, $protocol, $helo, $virus, $fakemx) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);
262 }
263 elsif ($in =~ /^(\d+):(\d+):(\d+):(\d+):(\d+):(\d+):(\d+)/)
264 {
265 ($pos, $received, $completed, $rejected, $greylisted, $rbl, $spam) = ($1, $2, $3, $4, $5, $6, $7);
266 }
267 elsif ($in =~ /^(\d+):(\d+):(\d+):(\d+)/)
268 {
269 ($pos, $received, $completed, $rejected) = ($1, $2, $3, $4);
270 }
271
272 elsif ($in =~ /^(\d+):(\d+):(\d+)/)
273 {
274 ($pos, $received, $completed) = ($1, $2, $3);
275 $rejected = 0;
276 }
277 close IN;
278}
279
280$startsize = (stat $logfile)[7];
281
282if (!defined $pos)
283{
284 # Initial run.
285 $pos = $startsize;
286}
287
288if ($startsize < $pos)
289{
290 # Log rotated
291 parseEximfile ($rotlogfile, $pos, (stat $rotlogfile)[7]);
292 $pos = 0;
293}
294
295parseEximfile ($logfile, $pos, $startsize);
296$pos = $startsize;
297
298print "received.value $received\n";
299print "completed.value $completed\n";
300print "rejected.value $rejected\n";
301print "rbl.value $rbl\n";
302print "spam.value $spam\n";
303print "greylisted.value $greylisted\n";
304print "sender.value $sender\n";
305print "user.value $user\n";
306print "protocol.value $protocol\n";
307print "helo.value $helo\n";
308print "virus.value $virus\n";
309print "fakemx.value $fakemx\n";
310
311if(-l $statefile) {
312 die("$statefile is a symbolic link, refusing to touch it.");
313}
314open (OUT, ">$statefile") or exit 4;
315print OUT "$pos:$received:$completed:$rejected:$greylisted:$rbl:$spam:$sender:$user:$protocol:$helo:$virus:$fakemx\n";
316close OUT;
317
318sub parseEximfile
319{
320 my ($fname, $start, $stop) = @_;
321 open (LOGFILE, $fname) or exit 3;
322 seek (LOGFILE, $start, 0) or exit 2;
323
324 while (tell (LOGFILE) < $stop)
325 {
326 my $line =<LOGFILE>;
327 chomp ($line);
328
329 if (substr ($line, 37,2 ) eq '<=')
330 {
331 $received++;
332 }
333 elsif (substr ($line, 37,9) eq 'Completed')
334 {
335 $completed++;
336 }
337 elsif ($line=~/greylisted\.$/)
338 {
339 $greylisted++;
340 }
341 elsif ($line=~/in a RBL/)
342 {
343 $rbl++;
344 }
345 elsif ($line=~/considered spam/)
346 {
347 $spam++;
348 }
349 elsif ($line=~/sender verify/)
350 {
351 $sender++;
352 }
353 elsif ($line=~/Unknown user/)
354 {
355 $user++;
356 }
357 elsif ($line=~/synchronization error/)
358 {
359 $protocol++;
360 }
361 elsif ($line=~/HELO\/EHLO/)
362 {
363 $helo++;
364 }
365 elsif ($line=~/contains a virus/)
366 {
367 $virus++;
368 }
369 elsif ($line=~/fakemx for/)
370 {
371 $fakemx++;
372 }
373 elsif ($line=~/rejected/)
374 {
375 $rejected++;
376 }
377 }
378 close(LOGFILE);
379}
380
381# vim:syntax=perl
This page took 0.026764 seconds and 4 git commands to generate.