File Coverage

blib/lib/Mail/Log/Parse.pm
Criterion Covered Total %
statement 168 170 98.8
branch 41 50 82.0
condition 16 16 100.0
subroutine 31 32 96.8
pod 10 10 100.0
total 266 278 95.6


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package Mail::Log::Parse;
4             {
5             =head1 NAME
6              
7             Mail::Log::Parse - Parse and return info in maillogs
8              
9             =head1 SYNOPSIS
10              
11             use Mail::Log::Parse;
12              
13             $object = Mail::Log::Parse->new({ log_file => '/path/to/logfile' });
14             %line_info = %{object->next()};
15              
16             $line_num = $object->get_line_number();
17              
18             if ( $object->go_forward($amount) ) {
19             ...
20             }
21              
22             if ( $object->go_backward($amount) ) {
23             ...
24             }
25              
26             %line_info = %{object->previous()};
27              
28             =head1 DESCRIPTION
29              
30             This is the root-level module for a generic mail log file parser. It is capable
31             of opening either a compressed or uncompressed logfile, and either stepping
32             through it line by line, or seeking around in it based on the logical lines.
33             (Lines not pertaining to the type of log currently being searched are skipped,
34             as if they don't exist.)
35              
36             On it's own it doesn't actually do much: You'll need a subclass that can
37             parse a particular program's log entries. But such subclasses are designed to
38             be easy to write and use.
39              
40             =head1 USAGE
41              
42             This is an object-oriented module. Available object methods are below.
43              
44             In a string context, it will return a string specifying the path to the file
45             and the current line number. In a boolean context, it will return whether it
46             has been correctly initialized. (Whether it has a file.) Numeric context throws
47             an error.
48              
49             Oh, and iterator context ('<>') returns the same as 'next'...
50              
51             =cut
52              
53 4     4   105816 use strict;
  4         10  
  4         151  
54 4     4   54 use warnings;
  4         9  
  4         127  
55 4     4   22 use Scalar::Util qw(refaddr blessed);
  4         10  
  4         368  
56 4     4   24 use File::Basename;
  4         17  
  4         2528  
57 4     4   4678 use IO::File;
  4         59362  
  4         590  
58 4     4   4371 use Mail::Log::Exceptions;
  4         78709  
  4         152  
59 4     4   36 use base qw(Exporter);
  4         8  
  4         386  
60              
61             BEGIN {
62 4     4   25 use Exporter ();
  4         9  
  4         79  
63 4     4   22 use vars qw($VERSION);
  4         6  
  4         186  
64 4     4   1454 $VERSION = '1.0401';
65             }
66              
67             #
68             # Define class variables. Note that they are hashes...
69             #
70              
71             my %log_info;
72             my %parse_buffer;
73             my %parse_buffer_start_line;
74             my %parse_buffer_size;
75             my %debug;
76             my %current_line;
77              
78             #
79             # DESTROY class variables.
80             #
81             ### IF NOT DONE THERE IS A MEMORY LEAK. ###
82              
83             sub DESTROY {
84 10     10   2138 my ($self) = @_;
85              
86 10 100       125 $log_info{refaddr $self}{filehandle}->close() if defined($log_info{refaddr $self}{filehandle});
87              
88 10         415 delete $log_info{refaddr $self};
89 10         1279 delete $parse_buffer{refaddr $self};
90 10         32 delete $parse_buffer_start_line{refaddr $self};
91 10         33 delete $parse_buffer_size{refaddr $self};
92 10         36 delete $debug{refaddr $self};
93 10         26 delete $current_line{refaddr $self};
94              
95 10         185 return;
96             }
97              
98             #
99             # Set the coercions to something useful.
100             #
101              
102             use overload (
103             # Strings overload to the path and line number.
104 2     2   7 qw{""} => sub { my ($self) = @_;
105 2         35 return blessed($self)
106             .' File: '
107             .$log_info{$$self}{'filename'}
108             .' Line: '
109             .$current_line{$$self};
110             },
111              
112             # Boolean overloads to if we are usable. (Have a filehandle.)
113 4     4   234 qw{bool} => sub { my ($self) = @_;
114 4         36 return defined($log_info{$$self}{'filehandle'});
115             },
116              
117             # Numeric context just doesn't mean anything. Throw an error.
118 2     2   329 q{0+} => sub { Mail::Log::Exceptions->throw(q{Can't get a numeric value of a Mail::Log::Parse.} );
119             },
120              
121             # Heh. Iterator context is the same as 'next'...
122 2     2   17 q{<>} => sub { return $_[0]->next(); },
123              
124             # Perl standard for everything else.
125 4         64 fallback => 1,
126 4     4   23 );
  4         9  
127              
128             =head2 new (constructor)
129              
130             The base constructor for the Mail::Log::Parse classes. It takes an (optional)
131             hash containing path to the logfile as an argument, and returns the new object.
132              
133             Example:
134              
135             $object = Mail::Log::Parse->new({ log_file => '/path/to/logfile' });
136              
137             Note that it is an error to call any method other than C if you
138             have not passed it in the constructor.
139              
140             Optional keys in the hash are 'buffer_length' and 'debug'. The buffer length
141             is the number of lines to read at a time (and store in the internal buffer).
142             Default is 128. Setting debug to a true value will result in some debugging
143             information being printed to STDERR. (I reserve the right to remove or change
144             the debug info at any time.)
145              
146             =cut
147              
148             sub new
149             {
150 10     10 1 928 my ($class, $parameters_ref) = @_;
151              
152 10         16 my $self = bless \do{my $anon}, $class;
  10         39  
153 10         536 $$self = refaddr $self;
154              
155             # Log info.
156 10 100       81 if ( defined($parameters_ref->{'log_file'}) ) {
157 4         33 $self->set_logfile($parameters_ref->{'log_file'}); # Better to keep validation together.
158             }
159              
160 8         34 $debug{$$self} = defined($parameters_ref->{debug});
161              
162             #$debug{refaddr $self} = 1;
163              
164             # Init the buffer.
165 8         16 $current_line{$$self} = 0;
166 8         18 $parse_buffer_start_line{$$self} = 0;
167 8         15 $parse_buffer{$$self} = undef;
168 8 100       42 $parse_buffer_size{$$self} = defined($parameters_ref->{buffer_length}) ? $parameters_ref->{buffer_length} : 128;
169              
170              
171 8         29 return $self;
172             }
173              
174             =head2 set_logfile
175              
176             Sets the logfile that this object will attempt to parse. It will throw
177             exceptions if it can't open the file for any reason, and will return true on
178             success.
179              
180             Files can be compressed or uncompressed: If they are compressed, then
181             C must be installed with the relevant
182             decompression libraries. (As well as version 0.17 or better of File::Temp.)
183             Currently only 'tgz', 'zip', 'gz', and 'bz2' archives are supported, but
184             there is no technical reason not to support more. (It just keeps a couple
185             of lines of code shorter.)
186              
187             Note that to support seeking in the file the log will be uncompressed to disk
188             before it is read: If there is insufficient space to do so, we may have trouble.
189             It also means this method may take a while to return for large compressed logs.
190              
191             Example:
192              
193             $object->set_logfile('path/to/file');
194              
195             =cut
196              
197             sub set_logfile {
198 6     6 1 67 my ($self, $new_name) = @_;
199              
200             # Check to make sure the file exists,
201             # and then that we can read it, before accpeting the filename.
202 6 100       160 if ( -e $new_name ) {
203 4 50       70 if ( -r $new_name ) {
204 4         20 $log_info{$$self}{'filename'} = $new_name;
205              
206             # We'll check the extension to see if it is compressed.
207 4         489 my (undef, undef, $suffix) = fileparse($new_name, qw(tgz zip gz bz2));
208 4 100       16 if ( $suffix ) {
209              
210             # Since we only need uncompress symantics right here, we'll
211             # only load them if we need them. Neat, huh?
212 1 50       12 eval { require IO::Uncompress::AnyUncompress } or Mail::Log::Exceptions->throw("Need IO::Uncompress::AnyUncompress for compressed files.\n");
  1         186  
213 1         74 IO::Uncompress::AnyUncompress->import( qw(anyuncompress) );
214              
215             # Same with File::Temp;
216 1 50       3 eval { require File::Temp } or Mail::Log::Exceptions->throw("Need File::Temp version 0.17 or better for compressed files.\n");
  1         9  
217 1 50       57 File::Temp->VERSION( 0.17 ) # Minimum version check.
218             or Mail::Log::Exceptions->throw("Need File::Temp version 0.17 or better for compressed files.\n");
219              
220             # If it is compressed, uncompress to a temp file and use that.
221 1         12 my $temp = new File::Temp();
222 1 50       1784 anyuncompress($new_name, $temp)
223             or Mail::Log::Exceptions::LogFile->throw("Unable to uncompress logfile $new_name: ". $IO::Uncompress::AnyUncompress::AnyUncompressError ."\n");
224 1 50       15578 $temp->seek(0,0)
225             or Mail::Log::Exceptions::LogFile->throw("Unable to seek to beginning of temp file.\n");
226 1         21 $log_info{$$self}{'filehandle'} = $temp;
227             }
228             else {
229             # If it wasn't compressed, open it direct.
230 3 50       26 $log_info{$$self}{'filehandle'} = IO::File->new($new_name, '<')
231             or Mail::Log::Exceptions::LogFile->throw("Unable to open file $new_name: $!\n");
232             }
233              
234             # Init some location information on the file.
235 4         356 $current_line{$$self} = 0;
236 4         11 delete $log_info{$$self}->{'line_positions'};
237 4         41 ${$log_info{$$self}{'line_positions'}}[$current_line{$$self}] = $log_info{$$self}{'filehandle'}->getpos();
  4         32  
238             }
239             else {
240 0         0 Mail::Log::Exceptions::LogFile->throw("Log file $new_name is not readable.\n");
241             }
242             }
243             else {
244 2         39 Mail::Log::Exceptions::LogFile->throw("Log file $new_name does not exist.\n");
245             }
246              
247 4         13 return 1;
248             }
249              
250             =head2 next
251              
252             Returns a reference to a hash of the next parsable line of the log, or 'undef' on
253             end of file/failure.
254              
255             There are a couple of required keys that any parser must implement:
256              
257             timestamp, program, id, text.
258              
259             Where C must the the unix timestamp, C must be the name of
260             the program that reported the logline (Sub-programs are recommended to be listed,
261             if possible), C is the tracking ID for that message, as reported by the
262             program, and C is the text following any 'standard' headers. (Usually,
263             minus those already required keys.)
264              
265             This version is just a placeholder: It will return a
266             'Mail::Log::Exceptions::Unimplemented' exception if called. Subclasses are
267             expected to override the C<_parse_next_line> method to get an operable parser.
268             (And that is the only method needed to be overridden for a working subclass.)
269              
270             Other 'standard' fields that are expected in a certain format (but are not
271             required to always be present) are 'from', 'to', 'size', 'subject', delay. 'to'
272             should point to an array of addresses. (As listed in the log. That includes
273             angle brackets, usually.)
274              
275             Example:
276              
277             while $hash_ref ( $object->next() ) {
278             ...
279             }
280              
281             or...
282              
283             while $hash_ref ( <$object> ) {
284             ...
285             }
286              
287             =cut
288              
289             sub next {
290 53     53 1 21164 my ($self) = @_;
291              
292             # This is the same as $self->get_current_line();
293             # (Or at least it should be. Done for speed.)
294 53         126 my $current_line = $current_line{$$self};
295              
296 53 100 100     327 if ( defined($parse_buffer{$$self})
  49   100     469  
297             and ( ($current_line+1) <= ($parse_buffer_start_line{$$self} + $#{$parse_buffer{$$self}}) )
298             and ( ($current_line+1) >= $parse_buffer_start_line{$$self})
299             ) {
300              
301             # Increment where we are.
302 18         51 $current_line{$$self} = $current_line{$$self} + 1;
303              
304             # print STDERR 'Returning line number '. $self->get_line_number() ." from buffer.\n" if $debug{$selfref};
305              
306             # Return the data we were asked for.
307 18         92 return $parse_buffer{$$self}->[($current_line - $parse_buffer_start_line{$$self}+1)];
308             }
309             else {
310             # Move the actual read postition to where we are.
311             # (But only if we've acutally ever read anything.)
312 35 100       157 if ( defined($log_info{$$self}->{line_positions}->[$current_line]) ) {
313 32 50       907 $log_info{$$self}{filehandle}->setpos($log_info{$$self}->{line_positions}->[$current_line])
314             or Mail::Log::Exceptions::LogFile->throw("Error seeking to position: $!\n");
315             }
316              
317             # print STDERR 'Reading buffer for line '. $current_line .".\n" if $debug{refaddr $self};
318              
319             # Check if we've reached the end of the file.
320             # (And that we haven't gone back...)
321 35 100 100     197 if ( defined($parse_buffer{$$self}->[0])
  26   100     176  
322             and $#{$parse_buffer{$$self}} < $parse_buffer_size{$$self}
323             and $current_line >= $parse_buffer_start_line{$$self}
324             ) {
325 4         18 return $parse_buffer{$$self}->[-1];
326             }
327              
328             # Clear the buffer.
329 31         50 @{$parse_buffer{$$self}} = ();
  31         6797  
330              
331             # Read in the buffer.
332 31         114 READ_LOOP: for my $i (0...$parse_buffer_size{$$self}) {
333 2409         11429 $parse_buffer{$$self}->[$i] = $self->_parse_next_line();
334 2406 100       7205 last READ_LOOP unless defined $parse_buffer{$$self}->[$i];
335 2404         5947 $self->_set_position_as_next_line;
336             }
337              
338             #use Data::Dumper;
339             #print STDERR Data::Dumper->Dump($parse_buffer{refaddr $self});
340              
341             # Move the indexes back to the line we are reading.
342             # (Note the 'current line' direct access again...)
343 28         68 $parse_buffer_start_line{$$self} = $current_line{$$self} - $#{$parse_buffer{$$self}};
  28         94  
344 28         175 $self->go_to_line_number($parse_buffer_start_line{$$self});
345              
346             # Return the data.
347 28         146 return $parse_buffer{$$self}->[0];
348             }
349             }
350              
351             =head2 previous
352              
353             Returns a reference to a hash of the previous line of the log, or undef on
354             failure/beginning of file.
355              
356             See C for details: It works nearly exactly the same. (In fact, it calls
357             next as a parser.)
358              
359             =cut
360              
361             sub previous {
362 4     4 1 8481 my ($self) = @_;
363              
364             # Check if we can.
365 4 100       25 if ( $current_line{$$self} <= 1 ) {
366 2         8 return undef;
367             }
368              
369             # Go back two lines
370 2         16 $self->go_backward(2);
371              
372             # And read forward one, returning that.
373 2         11 return $self->next();
374             }
375              
376             =head2 go_forward
377              
378             Goes forward a specified number of (logical) lines, or 1 if unspecified. It will
379             throw an error if it fails to seek as requested.
380              
381             Returns true on success.
382              
383             Example:
384              
385             $object->go_forward(4);
386              
387             =cut
388              
389             sub go_forward {
390 21     21 1 43324 my $self = shift;
391 21         54 my $lines = shift;
392              
393             # Just because I'm paranoid.
394 21   100     92 $lines ||= 1;
395              
396             # If we've read the line before, go straight to it.
397 21 100       41 if ( ${$log_info{$$self}{line_positions}}[($current_line{$$self}+$lines)] ) {
  21         131  
398 12         28 $current_line{$$self} = $current_line{$$self} + $lines;
399 12         83 return 1;
400             }
401             else {
402             # Work out where we are.
403 9         41 my $start_pos = $self->get_line_number();
404 9         19 my $end_known_pos = $#{$log_info{$$self}{line_positions}}; # zero-indexed.
  9         28  
405 9         17 my $lines_remaining = $lines - ($end_known_pos - $start_pos);
406              
407             # Go to the last line we have.
408 9         13 $current_line{$$self} = $#{$log_info{$$self}{line_positions}};
  9         27  
409              
410             # Then read until we get to the line we want.
411 9 100       40 if ( $self->next() ) {
412 7         22 unshift @_, ($self, $lines_remaining - 1 );
413 7         25 goto &go_forward;
414             }
415             else {
416 2         18 return 0;
417             }
418             }
419             }
420              
421             =head2 go_backward
422              
423             Goes backward a specified number of (logical) lines, or 1 if unspecified. It will
424             throw an error if it fails to seek as requested.
425              
426             If the seek would go beyond the beginning of the file, it will go to the
427             beginning of the file.
428              
429             Returns true on success.
430              
431             Example:
432              
433             $object->go_backward(4);
434              
435             =cut
436              
437             sub go_backward {
438 40     40 1 16562 my ($self, $lines) = @_;
439              
440             # Just because I'm paranoid.
441 40   100     133 $lines ||= 1;
442              
443             # If the line exits, go straight to it.
444 40 100       138 if ( ($current_line{$$self} - $lines ) > 0 ) {
445 36         76 $current_line{$$self} -= $lines;
446             }
447             else {
448             #If they've asked us to go beyond the beginning of the file, just go to the beginning.
449 4         8 $current_line{$$self} = 0;
450 4         20 return 0;
451             }
452 36         88 return 1;
453             }
454              
455             =head2 go_to_beginning
456              
457             Goes to the beginning of the file, no matter how far away that is.
458              
459             Returns true on success.
460              
461             =cut
462              
463             sub go_to_beginning {
464 2     2 1 1485 my ($self) = @_;
465              
466 2         9 $current_line{$$self} = 0;
467              
468 2         8 return 1;
469             }
470              
471             =head2 go_to_end
472              
473             Goes to the end of the file, no matter where it is.
474              
475             This attempts to be efficient about it, skipping where it can.
476              
477             Returns true on success.
478              
479             =cut
480              
481             sub go_to_end {
482 13     13 1 4878 my ($self) = @_;
483              
484             # Go to the end of what we have.
485 13         23 $current_line{$$self} = $#{$log_info{$$self}{line_positions}};
  13         58  
486              
487 13 100       58 if ( !$self->next() ) {
488 2         10 return 1;
489             }
490             else {
491 11         48 goto &go_to_end;
492             }
493             }
494              
495             =head2 get_line_number
496              
497             Returns the current logical line number.
498              
499             Note that line numbers start at zero, where 0 is the absolute beginning of the
500             file.
501              
502             Example:
503              
504             $line_num = $object->get_line_number();
505              
506             =cut
507              
508             sub get_line_number () {
509             # This method gets called a lot: speed is an issue.
510             # This is as fast as I could make it.
511 55     55 1 61030 return $current_line{${$_[0]}};
  55         455  
512             }
513              
514             =head2 go_to_line_number
515              
516             Goes to a specific logical line number. (Preferably one that exits...)
517              
518             =cut
519              
520             sub go_to_line_number {
521 34     34 1 4480 my ($self, $line_number) = @_;
522              
523             # my $current_line_number = $self->get_line_number();
524              
525 4     4   6952 no warnings qw(uninitialized);
  4         14  
  4         1895  
526 34 100       116 if ( $current_line{$$self} >= $line_number ) {
527 32         171 return $self->go_backward($current_line{$$self} - $line_number);
528             }
529             else {
530 2         11 return $self->go_forward($line_number - $current_line{$$self});
531             }
532             }
533              
534             #
535             # To be overrridden by subclasses.
536             #
537              
538             sub _parse_next_line {
539 1     1   2 my ($self) = @_;
540              
541 1         20 Mail::Log::Exceptions::Unimplemented->throw("Method '_parse_next_line' needs to be implemented by the subclass.\n");
542             }
543              
544             #
545             # These are semi-private methods: They are for the use of subclasses only.
546             #
547             =for readme stop
548              
549             =head1 SUBCLASSING
550              
551             This class is useless without subclasses to handle specific file formats. As
552             such, attempts have been made to make subclassing as painless as possible. In
553             general, you should only ever have to implement one method: C<_parse_next_line>.
554              
555             C<_parse_next_line> will be called whenever another line of the log needs to be
556             read. Its responsibility is to identify the next line, report where that is
557             in the actual file, and to parse that line.
558              
559             Specifically, it should I assume that every line in the input file is a
560             valid log line. It is expected to check first.
561              
562             Mail::Log::Parse is (as of v1.3) a cached inside-out object. If you don't know
563             what that means, ignore it: just writing C<_parse_next_line> correctly is enough.
564             However, if you find you need to store sub-class object info for some reason,
565             and want to use an inside-out object syntax yourself, C<$$self == refaddr $self>.
566             Which is useful and fast.
567              
568             Speed I important. It is not unlikely for someone to try to parse through
569             a week's worth of logs from a dozen boxes, where each day's log is hundreds of
570             megabytes worth of data. Be as good as you can.
571              
572             One other thing: Realize that you may also be subclassed. Even if you parse
573             every possible option of some log format, someone somewhere will probably have
574             a customized version with a slightly different format. If you've done your job
575             well, they'll be able to use your parser and just extend it slightly. Key to
576             this is to leave the I line in the return hash under the 'text' key.
577              
578             =head2 Suggested usage:
579              
580             Suggestion on how to use the above two methods to implement a '_parse_next_line' routine in
581             a subclass:
582              
583             sub _parse_next_line {
584             my ($self) = @_;
585              
586             # The hash we will return.
587             my %line_info = ( program => '' );
588              
589             # Some temp variables.
590             my $line;
591              
592             # In a mixed-log enviornment, we can't count on any
593             # particular line being something we can parse. Keep
594             # going until we can.
595             while ( $line_info{program} !~ m/$program_name/ ) {
596             # Read the line, using the Mail::Log::Parse utilty method.
597             $line = $self->_get_data_line() or return undef;
598              
599             # Program name. (We trust the logs. ;) )
600             $line_info{program} = $line ~= m/$regrex/;
601             }
602              
603             # Continue parsing
604             ...
605              
606             return \%line_info;
607             }
608              
609             =head1 UTILITY METHODS
610              
611             The following methods are not for general consumption: They are specifically
612             provided for use in implementing subclasses. Using them incorrectly, or
613             outside a subclass, can get the object into an invalid state.
614              
615             B
616              
617             =head2 _set_current_position_as_next_line
618              
619             Depreciated: No longer needed. An empty stub exists for backwards-compatibility.
620              
621             =cut
622              
623 0     0   0 sub _set_current_position_as_next_line () { }
624              
625              
626             # Sets the current positition as the next 'line' of logical data.
627             # Purely internal at this point.
628             # Optimized for speed over clarity, since we potentially use this a lot.
629             # (At least once per log line read.)
630             sub _set_position_as_next_line {
631 2404     2404   2400 $current_line{${$_[0]}} += 1;
  2404         4608  
632 2404 50       2855 ${$log_info{${$_[0]}}}{line_positions}[$current_line{${$_[0]}}] = $log_info{${$_[0]}}{'filehandle'}->getpos()
  2404         10266  
  2404         2539  
  2404         5216  
  2404         8965  
633             or Mail::Log::Exceptions::LogFile->throw("Unable to get current file position: $!\n");
634             }
635              
636             =head2 _get_data_line
637              
638             Returns the next line of data, as a string, from the logfile. This is raw data
639             from the logfile, separated by the current input separator.
640              
641             =cut
642              
643             # Optimized for speed over clarity, since we potentially use this a lot.
644             # (At least once per log line read.)
645              
646             sub _get_data_line {
647 2408 100   2408   2710 if ( defined($log_info{${$_[0]}}{'filehandle'}) ){
  2408         6624  
648 2406         2960 return $log_info{${$_[0]}}{'filehandle'}->getline()
  2406         83684  
649             }
650             else {
651 2         23 Mail::Log::Exceptions::LogFile->throw("Trying to read without a valid logfile: $!\n");
652             }
653             }
654              
655             =head2 _clear_buffer
656              
657             Clears the internal buffer of any data that may have been read into it so far.
658             Normally you should never need to use this: It is provided only for those rare
659             cases where something that has already been read may be changed because of
660             outside input. (For instance: You can change the year dates are assumed to be
661             in during mid-read on Postfix.)
662              
663             Avoid using unless actually needed.
664              
665             =cut
666              
667             sub _clear_buffer {
668 5     5   11 my ($self) = @_;
669 5         13 @{$parse_buffer{$$self}} = undef;
  5         2126  
670 5         15 $parse_buffer_start_line{$$self} = -1;
671 5         17 return;
672             }
673              
674             #
675             # Fully private methods.
676             #
677             =for readme continue
678              
679             =head1 BUGS
680              
681             C and C at the moment don't test for negative
682             numbers. They may or may not work with a negative number of lines: It depends
683             where you are in the file and what you've read so far.
684              
685             Those two methods should do slightly better on 'success' testing, to return
686             better values. (They basically always return true at the moment.)
687              
688             C will return one less than the true line number if you are
689             at the end of the file, and the buffer was completely filled. (So that the
690             end of the file is the last space of the buffer.) Changing the buffer size or
691             just going back and re-reading so that the buffer is restarted at a different
692             location will allow you to retrieve the correct file length.
693              
694             =head1 REQUIRES
695              
696             L, L, L, L
697              
698             =head1 RECOMMENDS
699              
700             L, L
701              
702             =head1 AUTHOR
703              
704             Daniel T. Staal
705              
706             DStaal@usa.net
707              
708             =head1 SEE ALSO
709              
710             L, which does some of what this module does. (This module
711             is a result of running into what that module I support. Namely
712             seeking through a file, both forwards and back.)
713              
714             =for readme stop
715              
716             =head1 HISTORY
717              
718             February 8, 2014 (1.4.1) - Switched to using Perl-standard environment variables
719             for checking to run author tests. (Should now test cleanly on Windows.)
720              
721             April 17, 2009 (1.4.0) - Simplified subclassing: No longer need to call
722             C<_set_current_position_as_next_line> in subclass. (A stub exists for backwards
723             compatibility.)
724              
725             April 9, 2009 (1.3.1) - Documentation fixes, better handling of trying to work
726             without a valid logfile.
727              
728             Dec 23, 2008 (1.3.0) - Further code speedups. Now stores a cache of the refaddr
729             for easy and quick access.
730              
731             Dec 09, 2008 (1.2.10) - Profiled and sped up code. (Cut processing time in half
732             for some cases.)
733              
734             Nov 28, 2008 - Documentation fixes.
735              
736             Nov 18, 2008 - Now buffers reading, and prefers data from the buffer.
737              
738             Oct 24, 2008 - File::Temp now optional; only required for uncompressed files.
739             Added go_to_line_number for slightly better functionality.
740              
741             Oct 14, 2008 - Found that I need File::Temp of at least version 0.17.
742              
743             Oct 13, 2008 - Fixed tests so they do a better job of checking if they
744             need to skip.
745              
746             Oct 6, 2008 - Initial version.
747              
748             =for readme continue
749              
750             =head1 COPYRIGHT and LICENSE
751              
752             Copyright (c) 2008 Daniel T. Staal. All rights reserved.
753             This program is free software; you can redistribute it and/or
754             modify it under the same terms as Perl itself.
755              
756             This copyright will expire in 30 years, or 5 years after the author's
757             death, whichever is longer.
758              
759             =cut
760             } # End Package.
761             1;