# File: Stem/Log/Tail.pm # This file is part of Stem. # Copyright (C) 1999, 2000, 2001 Stem Systems, Inc. # Stem 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. # Stem 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 Stem; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # For a license to use the Stem under conditions other than those # described here, to purchase support for this software, or to purchase a # commercial warranty contract, please contact Stem Systems at: # Stem Systems, Inc. 781-643-7504 # 79 Everett St. info@stemsystems.com # Arlington, MA 02474 # USA package Stem::Log::Tail ; use strict ; use IO::Seekable ; use Data::Dumper ; use Stem::Trace 'log' => 'stem_status', 'sub' => 'TraceStatus' ; use Stem::Trace 'log' => 'stem_error' , 'sub' => 'TraceError' ; my $attr_spec = [ { 'name' => 'path', 'required' => 1, 'help' => < 'data_log', 'required' => 1, 'help' => < 'status_log', 'help' => < 'label', 'default' => 'tail', 'help' => < 'level', 'default' => '5', 'help' => < 'interval', 'help' => < 'delay', 'default' => 10, 'help' => <{'interval'}\n" ; if ( my $interval = $self->{'interval'} ) { $self->{'timer'} = Stem::Event::Timer->new( 'object' => $self, 'method' => 'tail_cmd', 'interval' => $interval, 'delay' => $self->{'delay'}, 'repeat' => 1, 'hard' => 1, ) ; print "TIMER $self->{'timer'}\n" ; } $self->{'prev_size'} = 0 ; $self->{'prev_mtime'} = 0 ; $self->{'prev_inode'} = -1 ; return( $self ) ; } sub tail_cmd { my( $self ) = @_ ; print "TAILING\n" ; local( *LOG ) ; my $path = $self->{'path'} ; unless( open( LOG, $path ) ) { return if $self->{'open_failed'} ; $self->{'open_failed'} = 1 ; if ( my $status_log = $self->{'status_log'} ) { Stem::Log::Entry->new( 'logs' => $status_log, 'label' => 'LogTail status', 'text' => "LogTail: missing log $path $!\n", ) ; } return ; } $self->{'open_failed'} = 0 ; my( $inode, $size, $mtime ) = (stat LOG)[1, 7, 9] ; TraceStatus "size $size mtime $mtime $inode" ; my $prev_inode = $self->{'prev_inode'} ; my $prev_size = $self->{'prev_size'} ; if ( $prev_inode == -1 ) { $self->{'prev_inode'} = $inode ; if ( my $status_log = $self->{'status_log'} ) { Stem::Log::Entry->new( 'logs' => $status_log, 'level' => 6, 'label' => 'LogTail status', 'text' => "LogTail: first open of $path\n", ) ; } } elsif ( $inode != $prev_inode ) { $self->{'prev_inode'} = $inode ; if ( my $status_log = $self->{'status_log'} ) { Stem::Log::Entry->new( 'logs' => $status_log, 'level' => 6, 'label' => 'LogTail status', 'text' => "LogTail: $path has moved\n", ) ; } # tail the entire file as it is new $prev_size = 0 ; } elsif ( $size < $prev_size ) { if ( my $status_log = $self->{'status_log'} ) { Stem::Log::Entry->new( 'logs' => $status_log, 'level' => 6, 'label' => 'LogTail status', 'text' => "LogTail: $path has shrunk\n", ) ; } # tail the entire file as it has shrunk $prev_size = 0 ; } elsif ( $size == $prev_size ) { TraceStatus "no changes" ; return ; } $self->{'prev_size'} = $size ; my $delta_size = $size - $prev_size ; return unless $delta_size ; my $read_buf ; sysseek( *LOG, $prev_size, SEEK_SET ) ; sysread( *LOG, $read_buf, $delta_size ) ; Stem::Log::Entry->new( 'logs' => $self->{'data_log'}, 'level' => $self->{'level'}, 'label' => $self->{'label'}, 'text' => $read_buf, ) ; return ; } 1 ;