cleaned up some debug prints
[urisagit/Stem.git] / lib / Stem / Log / Tail.pm
1 #  File: Stem/Log/Tail.pm
2
3 #  This file is part of Stem.
4 #  Copyright (C) 1999, 2000, 2001 Stem Systems, Inc.
5
6 #  Stem is free software; you can redistribute it and/or modify
7 #  it under the terms of the GNU General Public License as published by
8 #  the Free Software Foundation; either version 2 of the License, or
9 #  (at your option) any later version.
10
11 #  Stem is distributed in the hope that it will be useful,
12 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #  GNU General Public License for more details.
15
16 #  You should have received a copy of the GNU General Public License
17 #  along with Stem; if not, write to the Free Software
18 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 #  For a license to use the Stem under conditions other than those
21 #  described here, to purchase support for this software, or to purchase a
22 #  commercial warranty contract, please contact Stem Systems at:
23
24 #       Stem Systems, Inc.              781-643-7504
25 #       79 Everett St.                  info@stemsystems.com
26 #       Arlington, MA 02474
27 #       USA
28
29 package Stem::Log::Tail ;
30
31 use strict ;
32 use IO::Seekable ;
33 use Data::Dumper ;
34
35 use Stem::Trace 'log' => 'stem_status', 'sub' => 'TraceStatus' ;
36 use Stem::Trace 'log' => 'stem_error' , 'sub' => 'TraceError' ;
37
38 my $attr_spec = [
39
40         {
41                 'name'          => 'path',
42                 'required'      => 1,
43                 'help'          => <<HELP,
44 This is the full path to the file we want to tail.
45 HELP
46         },
47
48         {
49                 'name'          => 'data_log',
50                 'required'      => 1,
51                 'help'          => <<HELP,
52 This is the log which gets sent the data log entries.
53 HELP
54         },
55
56         {
57                 'name'          => 'status_log',
58                 'help'          => <<HELP,
59 This is the log which gets sent the status log entries.
60 These include things like: Log has been rotated, deleted, moved, etc...
61 HELP
62         },
63         {
64                 'name'          => 'label',
65                 'default'       => 'tail',
66                 'help'          => <<HELP,
67 Label to tag tailed log entry.
68 HELP
69         },
70         {
71                 'name'          => 'level',
72                 'default'       => '5',
73                 'help'          => <<HELP,
74 Severity level for this tailed log entry.
75 HELP
76         },
77         {
78                 'name'          => 'interval',
79                 'help'          => <<HELP,
80 This specifies (in seconds) how often we check the log file for new
81 data.  If this is not specified, you need to call the tail_cmd method
82 to check for new data.
83 HELP
84         },
85         {
86                 'name'          => 'delay',
87                 'default'       => 10,
88                 'help'          => <<HELP,
89 This specifies (in seconds) how long the delay is before the
90 first repeated checking of the log file for new data.
91 HELP
92         },
93 ] ;
94
95
96 sub new {
97
98         my( $class ) = shift ;
99
100         my $self = Stem::Class::parse_args( $attr_spec, @_ ) ;
101         return $self unless ref $self ;
102
103 #print "TAIL INT $self->{'interval'}\n" ;
104
105         if ( my $interval = $self->{'interval'} ) {
106
107                 $self->{'timer'} = Stem::Event::Timer->new(
108                                 'object'        => $self,
109                                 'method'        => 'tail_cmd',
110                                 'interval'      => $interval,
111                                 'delay'         => $self->{'delay'},
112                                 'repeat'        => 1,
113                                 'hard'          => 1,
114                 ) ;
115
116 #print "TIMER $self->{'timer'}\n" ;
117
118         }
119
120         $self->{'prev_size'} = 0 ;
121         $self->{'prev_mtime'} = 0 ;
122         $self->{'prev_inode'} = -1 ;
123
124         return( $self ) ;
125 }
126
127 sub tail_cmd {
128
129         my( $self ) = @_ ;
130
131 #print "TAILING\n" ;
132
133         local( *LOG ) ;
134
135         my $path = $self->{'path'} ;
136
137         unless( open( LOG, $path ) ) {
138
139                 return if $self->{'open_failed'} ;
140                 $self->{'open_failed'} = 1 ;
141
142                 if ( my $status_log = $self->{'status_log'} ) {
143
144                         Stem::Log::Entry->new(
145                                 'logs'  => $status_log,
146                                 'label' => 'LogTail status',
147                                 'text'  =>
148                                         "LogTail: missing log $path $!\n",
149                         ) ;
150                 }
151                 return ;
152         }
153
154         $self->{'open_failed'} = 0 ;
155
156         my( $inode, $size, $mtime ) = (stat LOG)[1, 7, 9] ;
157
158         TraceStatus "size $size mtime $mtime $inode" ;
159
160         my $prev_inode = $self->{'prev_inode'} ;
161         my $prev_size = $self->{'prev_size'} ;
162
163         if ( $prev_inode == -1 ) {
164
165                 $self->{'prev_inode'} = $inode ;
166
167                 if ( my $status_log = $self->{'status_log'} ) {
168
169                         Stem::Log::Entry->new(
170                                 'logs'  => $status_log,
171                                 'level' => 6,
172                                 'label' => 'LogTail status',
173                                 'text'  =>
174                                         "LogTail: first open of $path\n",
175                         ) ;
176                 }
177         }
178         elsif ( $inode != $prev_inode ) {
179
180                 $self->{'prev_inode'} = $inode ;
181
182                 if ( my $status_log = $self->{'status_log'} ) {
183
184                         Stem::Log::Entry->new(
185                                 'logs'  => $status_log,
186                                 'level' => 6,
187                                 'label' => 'LogTail status',
188                                 'text'  =>
189                                         "LogTail: $path has moved\n",
190                         ) ;
191                 }
192
193 # tail the entire file as it is new
194
195                 $prev_size = 0 ;
196
197         }
198         elsif ( $size < $prev_size ) {
199         
200                 if ( my $status_log = $self->{'status_log'} ) {
201
202                         Stem::Log::Entry->new(
203                                 'logs'  => $status_log,
204                                 'level' => 6,
205                                 'label' => 'LogTail status',
206                                 'text'  =>
207                                         "LogTail: $path has shrunk\n",
208                         ) ;
209                 }
210
211 # tail the entire file as it has shrunk
212
213                 $prev_size = 0 ;
214         }
215         elsif ( $size == $prev_size ) {
216
217                 TraceStatus "no changes" ;
218                 return ;
219         }
220
221         $self->{'prev_size'} = $size ;
222
223         my $delta_size = $size - $prev_size ;
224
225         return unless $delta_size ;
226
227         my $read_buf ;
228
229         sysseek( *LOG, $prev_size, SEEK_SET ) ;
230         sysread( *LOG, $read_buf, $delta_size ) ;
231
232         Stem::Log::Entry->new(
233                 'logs'  => $self->{'data_log'},
234                 'level' => $self->{'level'},
235                 'label' => $self->{'label'},
236                 'text'  => $read_buf,
237         ) ;
238
239         return ;
240 }
241
242 1 ;