/usr/local/CPAN/Nagios-Interface/Nagios/Interface/Logfile.pm



package Nagios::Interface::Logfile;

use Nagios::Interface::ConcreteTypes;
use Moose;

use IO::File;

use Carp;

has 'source' =>
	isa => "Str",
	is => "ro",
	required => 1,
	default => sub {
		require Sys::Hostname;
		&Sys::Hostname::hostname;
	},
	;

has 'filename' =>
	isa => "Str",
	is => "ro",
	;

has 'tail' =>
	isa => "File::Tail",
	is => "ro",
	;

sub parse_logline {
	my $self = shift;
	my $line = shift;

	#print STDERR "read: $line\n";
	my ($time, $type, $info, $fail)
		= $line =~ m{^\[(\d+)\] (?:([\w\s]+): (.*)|(.*))}g;

	if ( $fail ) {
		if ( $fail =~ m{Auto-save.*completed success}) {
			return Nagios::Interface::IgnorableLogMessage->new
				(source => $self->source,
				 when => $time,
				 message => $fail);
		}
		elsif ( $fail =~ m{Caught (\w+)} ) {
			return Nagios::Interface::SignalDeath->new
				(source => $self->source,
				 when => $time,
				 signal => $1,
				 message => $fail);
		}
		else {
			return undef;
		}
	}

	if ( $type eq "EXTERNAL COMMAND" ) {
		$info =~ s{^([\w]+);}{} or
			die "failed to strip external command out";
		$type = $1;
		$type =~ s{_}{ }g;
		$type =~ s{\bSVC\b}{SERVICE}g;
	}

	my $class = lc $type;
	$class =~ s{(\w+)\s*}{ucfirst($1)}eg;
	$class = "Nagios::Interface::$class";

	unless ( eval { $class->does("Nagios::Interface::LogMessage") } ) {
		die "unknown event type '$type'";
	}

	my @fields = $class->log_info_order;
	# limit the split to the number of expected fields, in case
	# the last one contains a literal ';'
	my @params = split ";", $info, scalar(@fields);

	if ( @fields > @params ) {
		die "Expected ".@fields." fields, saw ".@params;
	}
	my @source;
	(@source) = (source => $self->source)
		unless grep { $_ eq "source" } @fields;

	return $class->new
		(when => $time, @source,
		 map { shift(@fields) => shift(@params) }
		 0..$#fields);

}

has 'fh' =>
	isa => "IO::Handle",
	is => "rw",
	;

sub BUILD {
	my $self = shift;
	if ( $self->filename ) {
		my $handle = IO::File->new($self->filename, "r")
			or croak "Could not open '".$self->filename
				." for reading; $!";
		$self->fh($handle);
	}
}

sub get_message {
	my $self = shift;
	my $line = do {
		if ( $self->tail ) {
			$self->tail->read;
		}
		elsif ( $self->fh ) {
			$self->fh->getline;
		}
	};
	defined($line) or return undef;
	return $self->parse_logline($line) || $line;
}

1;