#!/usr/bin/perl #----------------------------------------------------------------------------- # # xlog -- tools for handling xlog log files # #----------------------------------------------------------------------------- # # Copyright (C) 2001 Jochen Topf # # 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; either version 2 of the License, or # (at your option) any later version. # # 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 # #----------------------------------------------------------------------------- use strict; use Getopt::Long; use IO::File; use Time::Local; my $VERSION = "1.0"; my $session_grep = 0; my %sessions; my $subcommand = shift; if ($subcommand eq "sgrep") { $subcommand = "grep"; $session_grep = 1; } if ($subcommand eq "grep") { my %opts = (); GetOptions(\%opts, 'date=s', 'time=s', 'host=s', 'command=s', 'pid=i', 'sessionid=s', 'level=s@', 'id=s@', 'message=s@', 'x=s', 'v'); if (defined $opts{'date'}) { if ($opts{'date'} =~ /^\d{8}$/) { $opts{'startdate'} = $opts{'date'}; $opts{'enddate'} = $opts{'date'}; } elsif ($opts{'date'} =~ /^(\d{8})-$/) { $opts{'startdate'} = $1; $opts{'enddate'} = "99999999"; } elsif ($opts{'date'} =~ /^-(\d{8})$/) { $opts{'startdate'} = "00000000"; $opts{'enddate'} = $1; } elsif ($opts{'date'} =~ /^(\d{8})-(\d{8})$/) { if ($1 < $2) { $opts{'startdate'} = $1; $opts{'enddate'} = $2; } else { $opts{'startdate'} = $2; $opts{'enddate'} = $1; } } else { print STDERR "xlog: illegal date: $opts{'date'}\n"; exit 1; } } if (defined $opts{'time'}) { if ($opts{'time'} =~ /^\d{6}$/) { $opts{'starttime'} = $opts{'time'}; $opts{'endtime'} = $opts{'time'}; } elsif ($opts{'time'} =~ /^(\d{6})-$/) { $opts{'starttime'} = $1; $opts{'endtime'} = "235959"; } elsif ($opts{'time'} =~ /^-(\d{6})$/) { $opts{'starttime'} = "000000"; $opts{'endtime'} = $1; } elsif ($opts{'time'} =~ /^(\d{6})-(\d{6})$/) { if ($1 lt $2) { $opts{'starttime'} = $1; $opts{'endtime'} = $2; } else { $opts{'starttime'} = $2; $opts{'endtime'} = $1; } } else { print STDERR "xlog: illegal time: $opts{'time'}\n"; exit 1; } } if (defined $opts{'sessionid'} && $opts{'sessionid'} !~ /^(\d+\.\d+|-)$/) { print STDERR "xlog: illegal session id: $opts{'sessionid'}\n"; exit 1; } if (defined $opts{'level'}) { foreach (split(/,/, join(',', @{$opts{'level'}}))) { if (! /^(DBG|INF|ERR|ADM|SOS)$/) { print STDERR "xlog: illegal level: $_\n"; exit 1; } $opts{'Hlevel'}->{$_} = 1; } } if (defined $opts{'id'}) { foreach (split(/,/, join(',', @{$opts{'id'}}))) { if (! /^[0-9a-fA-F]+$/) { print STDERR "xlog: illegal message id: $_\n"; exit 1; } $opts{'Hid'}->{hex($_)} = 1; } } if (defined $opts{'message'}) { foreach (split(/,/, join(',', @{$opts{'message'}}))) { if (! /^[a-z_]+$/) { print STDERR "xlog: illegal message name: $_\n"; exit 1; } $opts{'Hmessage'}->{$_} = 1; } } @ARGV = map { /\.(gz|Z)$/ ? "gzip -dc < $_ |" : $_ } @ARGV; my @SAVEARGV = @ARGV; xlog_grep(\%opts); if ($session_grep) { @ARGV = @SAVEARGV; while (<>) { my ($date, $time, $host, $command, $pid, $sessionid, $level, $id, $message, $text) = split(/ /, $_, 10); print if ($sessions{$sessionid}); } } } elsif ($subcommand eq "join") { xlog_join(); } elsif ($subcommand eq "stime") { xlog_stime(); } elsif ($subcommand eq "stat") { xlog_stat(); } elsif ($subcommand eq "cut") { my %opts = (); GetOptions(\%opts, 'date', 'time', 'host', 'command', 'pid', 'sessionid', 'level', 'id', 'message', 'x'); xlog_cut(\%opts); } elsif ($subcommand eq "help") { print <<"EOF"; Usage: xlog [OPTIONS] ... Subcommands: xlog grep print only lines matching certain criteria xlog sgrep print all lines belonging to sessions matching certain criteria xlog join join several logfiles sorting the lines by date/time xlog stat display statistics on log file contents xlog cut display only some columns of a log file xlog version print version number xlog help this help text Options: xlog [s]grep [-date DATE] [-time TIME] [-host HOST] [-command COMMAND] [-pid PID] [-sessionid SESSIONID] [-level LEVEL] [-id ID] [-message MESSAGE] [-x TEXT] ... xlog cut [-date] [-time] [-host] [-command] [-pid] [-sessionid] [-level] [-id] [-message] [-x] All options can be abbreviated to the first letter. DATE and TIME can be ranges like '20010425-20010426'. LEVEL, ID, and MESSAGE can be comma separated lists. TEXT is a regular expression, all others are just strings. EOF exit 0; } elsif ($subcommand eq "version") { print "xlog $VERSION\n"; exit 0; } else { print STDERR "xlog: unknown or missing subcommand.\n"; exit 1; } #----------------------------------------------------------------------------- # # xlog_grep # #----------------------------------------------------------------------------- sub xlog_grep { my ($h) = @_; while (<>) { chomp; my ($date, $time, $host, $command, $pid, $sessionid, $level, $id, $message, $text) = split(/ /, $_, 10); if ((!defined $h->{'date'} || ($h->{'startdate'} le $date && $date le $h->{'enddate'})) && (!defined $h->{'time'} || ($h->{'starttime'} le $time && $time le $h->{'endtime'})) && (!defined $h->{'host'} || $h->{'host'} eq $host) && (!defined $h->{'command'} || $h->{'command'} eq $command) && (!defined $h->{'pid'} || $h->{'pid'} == $pid) && (!defined $h->{'sessionid'} || $h->{'sessionid'} eq $sessionid) && (!defined $h->{'level'} || $h->{'Hlevel'}->{$level}) && (!defined $h->{'id'} || $h->{'Hid'}->{hex($id)}) && (!defined $h->{'message'} || $h->{'Hmessage'}->{$message}) && (!defined $h->{'x'} || $text =~ /$h->{'x'}/)) { if (! $h->{'v'}) { if ($session_grep) { $sessions{$sessionid} = 1 unless ($sessionid eq '-'); } else { print "$_\n"; } } } else { if ($h->{'v'}) { if ($session_grep) { $sessions{$sessionid} = 1 unless ($sessionid eq '-'); } else { print "$_\n"; } } } } } #----------------------------------------------------------------------------- # # xlog_stat # #----------------------------------------------------------------------------- sub xlog_stat { my %count_level; my %count_id; my %count_msg; my $count; while (<>) { chomp; my ($date, $time, $host, $command, $pid, $sessionid, $level, $id, $message, $text) = split(/ /, $_, 10); $count_level{$level}++; $count_id{"$message $id $level"}++; $count_msg{"$message ---- $level"}++; $count++; } printf("%40s: %10d (100%)\n", "all messages", $count); print "------------------------------------------------------------------------------\n"; for my $lvl ("DBG", "INF", "ERR", "ADM", "SOS") { printf("%40s: %10d (%3d%)\n", $lvl, $count_level{$lvl}, 100*$count_level{$lvl} / $count); } printf("%40s: %10d\n", "ERR/INF", $count_level{'INF'} > 0 ? $count_level{'ERR'} / $count_level{'INF'} : 0); printf("%40s: %10d\n", "ADM/INF", $count_level{'INF'} > 0 ? $count_level{'ADM'} / $count_level{'INF'} : 0); print "------------------------------------------------------------------------------\n"; for my $msg (sort { $count_msg{$b} <=> $count_msg{$a} } keys(%count_msg)) { printf("%40s: %10d (%3d%)\n", $msg, $count_msg{$msg}, 100*$count_msg{$msg} / $count); } print "------------------------------------------------------------------------------\n"; for my $id (sort { $count_id{$b} <=> $count_id{$a} } keys(%count_id)) { printf("%40s: %10d (%3d%)\n", $id, $count_id{$id}, 100*$count_id{$id} / $count); } } #----------------------------------------------------------------------------- # # xlog_cut # #----------------------------------------------------------------------------- sub xlog_cut { my ($h) = @_; while (<>) { chomp; my ($date, $time, $host, $command, $pid, $sessionid, $level, $id, $message, $text) = split(/ /, $_, 10); my $out = ""; $out .= "$date " if ($h->{'date'}); $out .= "$time " if ($h->{'time'}); $out .= "$host " if ($h->{'host'}); $out .= "$command " if ($h->{'command'}); $out .= "$pid " if ($h->{'pid'}); $out .= "$sessionid " if ($h->{'sessionid'}); $out .= "$level " if ($h->{'level'}); $out .= "$id " if ($h->{'id'}); $out .= "$message " if ($h->{'message'}); $out .= "$text " if ($h->{'x'}); chop $out; print "$out\n" if ($out); } } #----------------------------------------------------------------------------- # # smallest # #----------------------------------------------------------------------------- sub smallest { my ($r) = @_; my $s; foreach my $file (keys(%$r)) { if (! defined $s) { $s = $file; } else { $s = $file if ($r->{$file} lt $r->{$s}); } } return $s; } #----------------------------------------------------------------------------- # # xlog_join # #----------------------------------------------------------------------------- sub xlog_join { my %fh; my %line; if (@ARGV < 1) { print "xlog: need at least one files for 'join' command\n"; exit 1; } foreach my $file (@ARGV) { $fh{$file} = new IO::File $file; if (! defined $fh{$file}) { print "xlog: open of file '$file' failed: $!\n"; exit 1; } $line{$file} = $fh{$file}->getline(); if (! defined $line{$file}) { $fh{$file}->close(); delete $fh{$file}; } } while (%fh) { my $file = smallest(\%line); print "$line{$file}"; $line{$file} = $fh{$file}->getline(); if (! defined $line{$file}) { $fh{$file}->close(); delete $fh{$file}; delete $line{$file}; } } } #----------------------------------------------------------------------------- # # iso2ar # #----------------------------------------------------------------------------- sub iso2ar { my ($date, $time) = @_; $date =~ /^(....)(..)(..)$/; my ($year, $mon, $mday) = ($1, $2, $3); $mon--; $time =~ /^(..)(..)(..)$/; my ($hours, $min, $sec) = ($1, $2, $3); return ($sec, $min, $hours, $mday, $mon, $year); } #----------------------------------------------------------------------------- # # xlog_stime # #----------------------------------------------------------------------------- sub xlog_stime { my %sids; while (<>) { chomp; my ($date, $time, $host, $command, $pid, $sessionid, $level, $id, $message, $text) = split(/ /, $_, 10); next if ($sessionid eq "-"); if (defined $sids{$sessionid}) { $sids{$sessionid} =~ s/:.*$//; $sids{$sessionid} .= ":$date $time $message"; } else { $sids{$sessionid} = "$date $time"; } } foreach (sort { substr($a, 15) cmp substr($b, 15) } keys(%sids)) { my ($date1, $time1, $date2, $time2, $message) = split(/[ :]/, $sids{$_}); my $diff = timelocal(iso2ar($date2, $time2)) - timelocal(iso2ar($date1, $time1)); print "$_ $date1 $time1 $date2 $time2 $diff $message\n"; } } #-- THE END ------------------------------------------------------------------