1 |
diff -Nur -x '*.orig' -x '*.rej' smeserver-qpsmtpd-1.2.1/root/var/service/qpsmtpd/log/run mezzanine_patched_smeserver-qpsmtpd-1.2.1/root/var/service/qpsmtpd/log/run |
2 |
--- smeserver-qpsmtpd-1.2.1/root/var/service/qpsmtpd/log/run 2005-04-20 22:35:31.000000000 -0600 |
3 |
+++ mezzanine_patched_smeserver-qpsmtpd-1.2.1/root/var/service/qpsmtpd/log/run 2007-06-07 09:41:00.000000000 -0600 |
4 |
@@ -24,4 +24,4 @@ |
5 |
exec \ |
6 |
/usr/local/bin/setuidgid smelog \ |
7 |
/usr/local/bin/multilog t s5000000 \ |
8 |
- /var/log/qpsmtpd |
9 |
+ !/usr/local/bin/qplogsumm.pl /var/log/qpsmtpd |
10 |
diff -Nur -x '*.orig' -x '*.rej' usr/local/bin/qplogsumm.pl mezzanine_patched_usr/local/bin/qplogsumm.pl |
11 |
--- usr/local/bin/qplogsumm.pl 1969-12-31 17:00:00.000000000 -0700 |
12 |
+++ mezzanine_patched_usr/local/bin/qplogsumm.pl 2007-06-07 09:37:09.000000000 -0600 |
13 |
@@ -0,0 +1,272 @@ |
14 |
+#!/usr/bin/perl |
15 |
+# |
16 |
+ |
17 |
+=pod |
18 |
+ |
19 |
+=head1 SUMMARY |
20 |
+ |
21 |
+Works with multilog to analyse and summarise log entries generated by the logterse plugin. It is designed |
22 |
+to be invoked by multilog at log-rotation time. This is specified by an argument to multilog similar to: |
23 |
+ |
24 |
+=over 4 |
25 |
+ |
26 |
+multilog t !/path/to/qplogsumm ./main |
27 |
+ |
28 |
+=back |
29 |
+ |
30 |
+When qplogsumm is invoked, each line will be echoed, meaning the stored log is unchanged, but summary |
31 |
+information will be written to fd 5 and so stored in the 'state' file by multilog. |
32 |
+ |
33 |
+This file is fed in on fd 4 at the beginning of the next log rotation, so running totals, etc can be maintained. |
34 |
+ |
35 |
+=head1 State file format: |
36 |
+ |
37 |
+One entry per line containing three fields separated by whitespace: |
38 |
+ |
39 |
+=over 4 |
40 |
+ |
41 |
+=item 1. Disposition (plugin) name. |
42 |
+ |
43 |
+=item 2. tai64n timestamp recording the first time it was seen in a log. |
44 |
+ |
45 |
+=item 3. long-term running total. |
46 |
+ |
47 |
+=back |
48 |
+ |
49 |
+A disposition is effectively the plugin name that called DENY or the string 'queued' for |
50 |
+messages that made it through. |
51 |
+ |
52 |
+A line containing a disposition name of LOGFILE_EPOCH and a timestamp for the earliest known log entry. |
53 |
+ |
54 |
+Other derived data, such as percentages etc. can also appear in the file, commented |
55 |
+by a # character. This will be ignored on the next intake. |
56 |
+ |
57 |
+=head1 AUTHOR |
58 |
+ |
59 |
+Charles Butcher |
60 |
+ |
61 |
+=head1 VERSION |
62 |
+ |
63 |
+This is release 1.0 |
64 |
+ |
65 |
+=cut |
66 |
+ |
67 |
+use strict; |
68 |
+use POSIX qw(strftime); |
69 |
+ |
70 |
+ |
71 |
+my $FS = "\t"; # field separator used by logterse plugin |
72 |
+my %disp; # hash of dispositions |
73 |
+ |
74 |
+if (open PREVIOUS, "<&4") |
75 |
+{ |
76 |
+ while (<PREVIOUS>) |
77 |
+ { |
78 |
+ chomp(); |
79 |
+ next if m/^#/; |
80 |
+ next if m/^\s*$/; |
81 |
+ my ($plug_name, $plug_epoch, $plug_cumulative) = split /\s/; |
82 |
+ my $c = { epoch => $plug_epoch, cum => $plug_cumulative, curr => 0 }; |
83 |
+ $disp{$plug_name} = $c; |
84 |
+ } |
85 |
+ |
86 |
+ close PREVIOUS; |
87 |
+} |
88 |
+ |
89 |
+my $first_timestamp = 0; |
90 |
+my $last_timestamp = 0; |
91 |
+ |
92 |
+ |
93 |
+while (<>) |
94 |
+{ |
95 |
+ print; |
96 |
+ chomp; |
97 |
+ next unless m/terse plugin/; |
98 |
+ |
99 |
+ my ($timestamp_part, $log_part) = split '`'; |
100 |
+ my ($current_timestamp) = split /\s/, $timestamp_part; |
101 |
+ $first_timestamp = $current_timestamp unless $first_timestamp; |
102 |
+ $last_timestamp = $current_timestamp; |
103 |
+ |
104 |
+ my (@log_items) = split $FS, $log_part; |
105 |
+ my $disposition = $log_items[5]; |
106 |
+ next unless defined $disposition; |
107 |
+ |
108 |
+ if ($disp{$disposition}) |
109 |
+ { |
110 |
+ $disp{$disposition}->{curr} = 1; |
111 |
+ } |
112 |
+ else # a new plugin -- make a note of when it first appeared |
113 |
+ { |
114 |
+ my $c = { epoch => $current_timestamp, cum => 0, curr => 1 }; |
115 |
+ $disp{$disposition} = $c; |
116 |
+ } |
117 |
+} |
118 |
+ |
119 |
+ |
120 |
+# |
121 |
+# Set overall epoch |
122 |
+# |
123 |
+if (!exists $disp{'LOGFILE_EPOCH'}) |
124 |
+{ |
125 |
+ my $c = { epoch => $first_timestamp, cum => 0, curr => 0}; |
126 |
+ $disp{'LOGFILE_EPOCH'} = $c; |
127 |
+} |
128 |
+ |
129 |
+my $current_total = 0; |
130 |
+my $cumulative_total = 0; |
131 |
+ |
132 |
+open HOLDOVER, ">&5" and select HOLDOVER; |
133 |
+ |
134 |
+# |
135 |
+# Output cumulative values for intake the next time a log is processed |
136 |
+# |
137 |
+for my $c (keys %disp) |
138 |
+{ |
139 |
+ $disp{$c}->{cum} = $disp{$c}->{curr}; |
140 |
+ $current_total = $disp{$c}->{curr}; |
141 |
+ $cumulative_total = $disp{$c}->{cum}; |
142 |
+ |
143 |
+ printf "%-30.30s %s %12d\n", $c, $disp{$c}->{epoch}, $disp{$c}->{cum}; |
144 |
+} |
145 |
+ |
146 |
+# |
147 |
+# Output current logfile stats |
148 |
+# |
149 |
+ |
150 |
+my $current_elapsed = tai64diff($last_timestamp, $first_timestamp); |
151 |
+ |
152 |
+printf "# |
153 |
+# Most recent logfile |
154 |
+# ------------------- |
155 |
+# |
156 |
+# Start : %s |
157 |
+# Finish : %s |
158 |
+# Elapsed: %s |
159 |
+# |
160 |
+# Total transactions : %9d |
161 |
+# Average tx per hour: %9d |
162 |
+", |
163 |
+ tai64utc($first_timestamp), |
164 |
+ tai64utc($last_timestamp), |
165 |
+ seconds_to_days($current_elapsed), |
166 |
+ $current_total, |
167 |
+ $current_total / ($current_elapsed / 3600), |
168 |
+ ; |
169 |
+ |
170 |
+# |
171 |
+# Output cumulative log stats |
172 |
+# |
173 |
+my $cumulative_elapsed = tai64diff($last_timestamp, $disp{'LOGFILE_EPOCH'}->{epoch}); |
174 |
+ |
175 |
+printf "# |
176 |
+# Cumulative Totals |
177 |
+# ----------------- |
178 |
+# |
179 |
+# Start : %s |
180 |
+# Finish : %s |
181 |
+# Elapsed: %s |
182 |
+# |
183 |
+# Total transactions : %12d |
184 |
+# Average tx per hour: %12d |
185 |
+", |
186 |
+ tai64utc($disp{'LOGFILE_EPOCH'}->{epoch}), |
187 |
+ tai64utc($last_timestamp), |
188 |
+ seconds_to_days($cumulative_elapsed), |
189 |
+ $cumulative_total, |
190 |
+ $cumulative_total / ($cumulative_elapsed / 3600), |
191 |
+ ; |
192 |
+ |
193 |
+ |
194 |
+# |
195 |
+# Output per-plugin stats |
196 |
+# |
197 |
+ |
198 |
+print "# |
199 |
+# Most Recent Logfile Cumulative Totals |
200 |
+# Disposition (plugin) Total Avg/Day Total Avg/Day |
201 |
+# ----------------------------------------------------------------------------\n"; |
202 |
+ |
203 |
+my $printf_format = "# %-30.30s %6d %3d%% %8d %10d %3d%% %8d\n"; |
204 |
+ |
205 |
+foreach my $c (sort { $disp{$b}->{curr} <=> $disp{$a}->{curr} } keys %disp) |
206 |
+{ |
207 |
+ next if ($c eq 'LOGFILE_EPOCH'); |
208 |
+ |
209 |
+ printf $printf_format, |
210 |
+ $c, |
211 |
+ $disp{$c}->{curr}, |
212 |
+ $disp{$c}->{curr} / $current_total * 100, |
213 |
+ $disp{$c}->{curr} / ($current_elapsed / 86400), |
214 |
+ $disp{$c}->{cum}, |
215 |
+ $disp{$c}->{cum} / $cumulative_total * 100, |
216 |
+ $disp{$c}->{cum} / (tai64diff($last_timestamp, $disp{$c}->{epoch}) / 86400), |
217 |
+ ; |
218 |
+} |
219 |
+ |
220 |
+print "# ----------------------------------------------------------------------------\n"; |
221 |
+printf $printf_format, |
222 |
+ 'TOTALS', |
223 |
+ $current_total, |
224 |
+ 100, |
225 |
+ $current_total / ($current_elapsed / 86400), |
226 |
+ $cumulative_total, |
227 |
+ 100, |
228 |
+ $cumulative_total / ($cumulative_elapsed / 86400), |
229 |
+ ; |
230 |
+ |
231 |
+exit 0; |
232 |
+ |
233 |
+ |
234 |
+sub tai64utc { |
235 |
+ my ($s) = @_; |
236 |
+ |
237 |
+ # @400000003f6c7bc5253bf98c |
238 |
+ # 0123456789012345678901234 |
239 |
+ # 0 1 2 |
240 |
+ # |-------------||------| |
241 |
+ if (substr($s, 0, 2) eq '@4') { |
242 |
+ my $ts = hex(substr($s, 2, 15)); |
243 |
+ $s = strftime('%Y-%m-%d %H:%M:%S', gmtime($ts)); |
244 |
+ } |
245 |
+ return $s; |
246 |
+} |
247 |
+ |
248 |
+# |
249 |
+# Return difference in seconds |
250 |
+# |
251 |
+sub tai64diff |
252 |
+{ |
253 |
+ my ($s1, $s2) = @_; |
254 |
+ |
255 |
+ # @400000003f6c7bc5253bf98c |
256 |
+ # 0123456789012345678901234 |
257 |
+ # 0 1 2 |
258 |
+ # |-------------||------| |
259 |
+ if (substr($s1, 0, 2) eq '@4' and substr($s2, 0, 2) eq '@4') |
260 |
+ { |
261 |
+ my $ts1 = hex(substr($s1, 2, 15)); |
262 |
+ my $ts2 = hex(substr($s2, 2, 15)); |
263 |
+ return $ts1 - $ts2; |
264 |
+ } |
265 |
+ else |
266 |
+ { |
267 |
+ return 0; |
268 |
+ } |
269 |
+} |
270 |
+ |
271 |
+ |
272 |
+# |
273 |
+# Return an english phrase representing a number of seconds |
274 |
+# |
275 |
+sub seconds_to_days |
276 |
+{ |
277 |
+ my ($secs) = @_; |
278 |
+ |
279 |
+ my $phrase = sprintf "%d days, ", ($secs / 86400); |
280 |
+ $secs %= 86400; |
281 |
+ $phrase .= sprintf "%d hours, ", ($secs / 3600); |
282 |
+ $secs %= 3600; |
283 |
+ $phrase .= sprintf "%d mins, %d secs", ($secs / 60), ($secs % 60); |
284 |
+} |
285 |
+ |