#!/usr/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_ - Additional regexes # label_ - Additional labels # title - Graph title # # TODO: Handle rotated logs # # $Log$ # Revision 1.5 2005/01/05 16:44:02 ilmari # Fixed typo in generic/loggrep breaking implicit labeling. # # Revision 1.4 2004/12/10 18:51:43 jimmyo # linux/apt* has been forced to LANG=C, to get predictable output. # # Revision 1.3 2004/12/10 10:47:47 jimmyo # Change name from ${scale} to ${graph_period}, to be more consistent. # # Revision 1.2 2004/12/09 22:12:54 jimmyo # Added "graph_period" option, to make "graph_sums" usable. # # Revision 1.1 2004/11/20 05:59:25 ilmari # Added plugin generic/loggrep for generic log grepping. # # # 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/lib/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