7 usage: ratelimit.pl <period> <regex> logfile
9 The aim of this script is to compute clients' peak sending rates
10 from an Exim log file, using the same formula as Exim's ratelimit
11 ACL condition. This is so that you can get an idea of a reasonable
12 limit setting before you deploy the restrictions.
14 This script isn't perfectly accurate, because the time stamps in
15 Exim's log files are only accurate to a second whereas internally
16 Exim computes sender rates to the accuracy of your computer's clock
19 The log files to be processed can be specified on the command line
20 after the other arguments; if no filenames are specified the script
23 The first command line argument is the smoothing period, as defined by
24 the documentation for the ratelimit ACL condition. The second argumetn
25 is a regular expression.
27 Each line is matched against the regular expression. Lines that do not
28 match are ignored. The regex may contain 0, 1, or 2 () capturing
31 If there are no () sub-expressions, then every line that matches is
32 used to compute a single rate. Its maximum value is reported when the
35 If there is one () sub-expression, then the text matched by the
36 sub-expression is used to identify a rate lookup key, similar to the
37 lookup key used by the ratelimit ACL condition. For example, you might
38 write a regex to match the client IP address, or the authenticated
39 username. Separate rates are computed for each different client and
40 the maximum rate for each client is reported when the script finishes.
42 If there are two () sub-expressions, then the text matched by the
43 first sub-expression is used to identify a rate lookup key as above,
44 and the second is used to match the message size recorded in the log
45 line, e.g. " S=(\\d+) ". In this case the byte rate is computed instead
46 of the message rate, similar to the per_byte option of the ratelimit
53 my ($y,$m,$d,$H,$M,$S,$zs,$zh,$zm) = @_;
56 $m += $m < 3 ? 10 : -2;
57 my $z = defined $zs ? "${zs}1" * ($zh * 60 + $zm) : 0;
58 my $t = $y/400 - $y/100 + $y/4 + $y*365
59 + $m*367/12 + $d - 719499;
69 while (@ARGV && $ARGV[0] =~ /^-\w+$/) {
70 $debug = 1 if $ARGV[0] =~ s/(-\w*)d(\w*)/$1$2/;
71 $progress = 1 if $ARGV[0] =~ s/(-\w*)p(\w*)/$1$2/;
72 shift if $ARGV[0] eq "-";
82 my $re = qr{$re_txt}o;
90 printf "%s\t%12d %8s %5.2f %5.2f\n",
91 $_, $time{$key}, $key, $max{$key}, $rate{$key};
95 next unless $_ =~ $re;
99 ($_ =~ m{^(\d{4})-(\d\d)-(\d\d)[ ]
100 (\d\d):(\d\d):(\d\d)[ ]
101 (?:([+-])(\d\d)(\d\d)[ ])?
104 my $prog_now = substr $_, 0, 14;
105 if ($progtime ne $prog_now) {
106 $progtime = $prog_now;
110 if (not defined $time{$key}) {
114 debug $key if $debug;
117 # see acl_ratelimit() for details of the following
118 my $interval = $time - $time{$key};
119 $interval = 1e-9 if $interval <= 0.0;
120 my $i_over_p = $interval / $period;
121 my $a = exp(-$i_over_p);
123 $rate{$key} = $size * (1.0 - $a) / $i_over_p + $a * $rate{$key};
124 $max{$key} = $rate{$key} if $rate{$key} > $max{$key};
125 debug $key if $debug;
129 " " x (20 - length) .
132 $max{$a} <=> $max{$b}