#!/usr/pkg/bin/perl -w
# -*- perl -*-
#
# Copyright (C) 2004 Dagfinn Ilmari Mannsaaker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 dated June, 1991.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.
#
#
# Counts the number of matching log lines
#
# Parameters:
#
# 	config   (required)
#
# Config variables:
#
#       logfile       - Files to grep (shellglob) (required)
#       regex         - Regex to look for (required)
#       label         - Label
#       regex_<key>   - Additional regexes
#       label_<key>   - Additional labels
#       title         - Graph title
#
# TODO: Handle rotated logs
#
# Magic markers (optional - used by munin-config and some installation
# scripts):
#
#%# family=manual
use strict;

my %regex;
my $logfile = $ENV{logfile};

(my $name = $0) =~ s|.*/||;

die("No log file specified") unless defined $logfile;

if (exists $ENV{'regex'}) {
    $regex{'count'}{'regex'} = qr/$ENV{'regex'}/;
    $regex{'count'}{'label'} = $ENV{'label'} || $ENV{'regex'};
    $regex{'count'}{'value'} = 0;
}

for my $key (map {/^regex_(.+)/} keys %ENV) {
    $regex{$key}{'regex'} = qr/$ENV{"regex_$key"}/;
    $regex{$key}{'label'} = $ENV{"label_$key"} || $ENV{"regex_$key"};
    $regex{$key}{'value'} = 0;
}

die("No regexes specified") unless keys %regex;

my $statefile = "/var/munin/plugin-state/$name.state";

if ($ARGV[0] and $ARGV[0] eq 'config') {
    my $title = $ENV{title} || "Entries in $logfile";
    print "graph_title $title\n";
    print "graph_args --base 1000 -l 0\n";
    print "graph_vlabel entries / \${graph_period}\n";
    print "graph_category other\n";
    for my $key (keys %regex) {
	print "$key.label $regex{$key}{'label'}\n";
	print "$key.type DERIVE\n";
	print "$key.min 0\n";
	print "$key.draw LINE2\n";
    }
    exit 0;
}

my %pos = map { $_ => undef } glob($logfile);

if (-f $statefile) {
    open(my $in, '<', $statefile) or die("Can't read $statefile: $!\n");
    while (<$in>) {
	chomp;
	if (/^([^=]+)=(\d+)$/ && exists $regex{$1}) {
	    $regex{$1}{'value'} = $2;
	} else {
	    last;
	}
    }
    do {
	chomp;
	if (<$in> =~ /^(\d+)$/ and exists $pos{$_}) {
	    $pos{$_} = $1
	}
    } while (<$in>);
    close $in;
}

for my $log (keys %pos) {
    $pos{$log} = parse_log($log, $pos{$log});
}

for my $key (keys %regex) {
    print "$key.value $regex{$key}{'value'}\n";
}

if(-l $statefile) {
 	die("$statefile is a symbolic link, refusing to touch it.\n");
}				
open(my $out, '>', $statefile) or die("Can't write $statefile: $!\n");
for my $key (keys %regex) {
    print $out "$key=$regex{$key}{'value'}\n";
}
for my $log (keys %pos) {
    print $out "$log\n$pos{$log}\n";
}
close $out;

sub parse_log {
    my ($fname, $start) = @_;
    open(my $logfh, $fname) or die ("Can't open log file $fname: $!\n");
    my $size = (stat $logfh)[7];

    # First encounter
    $start = $size unless defined $start;

    # The log has been rotated, start over
    $start = 0 if $size < $start;

    seek($logfh, $start, 0) or die ("Can't seek to $fname:$start: $!\n");

    while (tell($logfh) < $size) {
	my $line = <$logfh>;

	for my $match (values %regex) {
	    if ($line =~ $match->{'regex'}) {
		$match->{'value'}++;
	    }
	}
    }
    close($logfh);
    return $size;
}

# vim:syntax=perl
