Re: removeheaders

Tom Metro <[email protected]>
Newsgroups gmane.comp.log.logwatch.devel
Message-ID <[email protected]>
Mike Cappella wrote:
>>> The diff below corrects these issues. I've only tested it with data 
>>> that matches the first expression.
> 
> I think the removeheaders optimization you posted can be further reduced...

Actually the patch I posted was broken, and a reflection of my limited 
test data. It incorrectly handles the Solaris format because it short 
circuits on the first match, which is the simpler expression to extract 
the date-host-service: portion.

(BTW, any thoughts on writing unit tests for these scripts?)


> potentially avoiding calling the RE generator twice for non-matching lines...

The only good way to answer these questions is to benchamark the 
variations, which I've done below.

Here are the subroutines and what they represent:

rh1 # original
rh2 # reduced (your version)
rh3 # consolidated (3 REs consolidated to 1)
rh4 # consolidated + validation
rh5 # optimized for speed (minimal use of RE)

They were ran against the 3 different log line formats, with a sample 
log line printed before the benchmark results (the left column is 
ordered from slowest to fastest):

Jun 24 06:58:11 host service[2531]: message
         Rate  rh2  rh4  rh1  rh3  rh5
rh2 207039/s   --  -4%  -8%  -8% -27%
rh4 214592/s   4%   --  -4%  -5% -24%
rh1 224215/s   8%   4%   --  -1% -21%
rh3 225734/s   9%   5%   1%   -- -21%
rh5 284091/s  37%  32%  27%  26%   --

Jun 24 06:48:54 host syslogd 1.4.1#18: restart (remote reception).
         Rate  rh2  rh4  rh1  rh3  rh5
rh2 211416/s   --  -3%  -4%  -7% -26%
rh4 218818/s   4%   --  -1%  -4% -23%
rh1 221239/s   5%   1%   --  -3% -22%
rh3 228311/s   8%   4%   3%   -- -20%
rh5 284900/s  35%  30%  29%  25%   --

Jun 24 06:48:54 host service[2531]: [ID 1234 word.word] Solaris message
         Rate rh2 rh5 rh3 rh4 rh1
rh2 165837/s  -- -1% -3% -3% -7%
rh5 168350/s  2%  -- -2% -2% -6%
rh3 171233/s  3%  2%  -- -0% -4%
rh4 171527/s  3%  2%  0%  -- -4%
rh1 178571/s  8%  6%  4%  4%  --


In all cases rh2 (reduced) actually ends up being the slowest.

In the first two (supposedly most common) cases, the original is the 
second slowest.

The overall speed winner, rh5, which is ~30% faster than the original on 
the most common log line format, takes a quick-and-dirty approach, and 
makes minimal use of regular expressions in exchange for performing the 
least validation of the data.

On the "no colon" data, rh5 also produces different results from the 
other methods:

Jun 24 06:48:54 host syslogd 1.4.1#18: restart (remote reception).
rh1:  restart (remote reception).
rh2:  restart (remote reception).
rh3:  restart (remote reception).
rh4:  restart (remote reception).
rh5:  1.4.1#18: restart (remote reception).

Note how it isn't stripping off the syslog version. I'm not entirely 
sure which way is actually more correct. It seems arguable to me that 
the version number is part of the log message and should be included.

The original code appeared to be somewhat sloppy in the validation it 
was performing. If you consider this RE:

s/^... .. ..:..:.. [^ ]* [^\[:]*(\[\d*\])?: //

it's saying that the dates can be composed of any characters, as long as 
they have the right number of characters and the spaces and colons in 
the right place, and that the host name and service name can be zero 
length. That doesn't seem right. But maybe things are checked more 
rigorously upstream.

I'd say if validation was happening upstream, I'd use rh5, otherwise I'd 
probably pick rh4, which maximizes validation, and I'd add in error 
handling code to warn about lines that don't match. Though this ends up 
being about the same performance as the original (+/-2%).

Benchmark script attached. Feel free to try your own variations.

Of course now that we've optimized this, I'd like to voice my agreement 
with a comment made recently that dates and other "header" information 
should probably not get stripped off before handing the data to the 
service filter. As I noted in another message, having a common 
intermediate log format would permit building an infrastructure for 
doing common things, like splitting a line into a standard set of 
components (date, host, service, PID, message), making the job of the 
service filter just as easy, wile still giving it access to the greater 
detail if it needs it.

  -Tom

-- 
Tom Metro
Venture Logic, Newton, MA, USA
"Enterprise solutions through open source."
Professional Profile: http://tmetro.venturelogic.com/

_______________________________________________
Logwatch-Devel mailing list
[email protected]
http://www2.list.logwatch.org:81/mailman/listinfo/logwatch-devel
removeheaders_bench (text/plain, 1.8 KB)
#!/usr/bin/perl

use Benchmark qw(:all);
#use strict;

my $line1 = 'Jun 24 06:58:11 host service[2531]: message';
my $line2 = 'Jun 24 06:48:54 host syslogd 1.4.1#18: restart (remote reception).';
my $line3 = 'Jun 24 06:48:54 host service[2531]: [ID 1234 word.word] Solaris message';


# original
sub rh1 {
    $_ = shift;

    s/^... .. ..:..:.. [^ ]* [^\[:]*(\[\d*\])?: \[ID \d+( \w+\.\w+)?] //;
    s/^... .. ..:..:.. [^ ]* [^\[:]*(\[\d*\])?: //;
    s/^... .. ..:..:.. [^ ]* //;
    return $_;
}

# reduced
sub rh2 {
    $_ = shift;

    if (s/^... .. ..:..:.. [^ ]* //) {     # Strip date, time, service
        if (s/^[^\[:]*(?:\[\d*\])?: //) {  # ":" after service name may not exist
            s/^\[ID \d+(?: \w+\.\w+)?] //; # Strip Solaris ID tag style -mgt
        }
    }
    return $_;
}

# consolidated
sub rh3 {
    $_ = shift;

    s/^... .. ..:..:.. [^ ]* ([^\[:]*(\[\d*\])?: )?(\[ID \d+( \w+\.\w+)?] )?//;
    return $_;
}

# consolidated + validation
sub rh4 {
    $_ = shift;

    s/^\w\w\w \d\d \d\d:\d\d:\d\d [^ ]+ ([^\[:]+(\[\d+\])?: )?(\[ID \d+( \w+\.\w+)?] )?//o;
    return $_;
}

# optimized for speed
sub rh5 {
    $_ = shift;

    $_ = substr($_,16);
    $_ = (split(' ',$_,3))[2];

    s/^\[ID \d+( \w+\.\w+)?] //;
    return $_;
}


# demo
foreach my $line ($line1,$line2,$line3) {
    print "$line\n";
    print "rh1:  ", rh1($line), "\n";
    print "rh2:  ", rh2($line), "\n";
    print "rh3:  ", rh3($line), "\n";
    print "rh4:  ", rh4($line), "\n";
    print "rh5:  ", rh5($line), "\n";
    print "\n";
}

# benchmark
my $count = 1000000;

foreach my $line ($line1,$line2,$line3) {
    print "$line\n";
    cmpthese($count, {
        'rh1' => sub {rh1($line)},
        'rh2' => sub {rh2($line)},
        'rh3' => sub {rh3($line)},
        'rh4' => sub {rh4($line)},
        'rh5' => sub {rh5($line)},
    });
    print "\n";
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.