File Coverage

blib/lib/Mail/Log/Parse.pm
Criterion Covered Total %
statement 168 169 99.4
branch 41 50 82.0
condition 16 16 100.0
subroutine 31 32 96.8
pod 10 10 100.0
total 266 277 96.0


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   49123 use strict;
  4         8  
  4         97  
54 4     4   19 use warnings;
  4         6  
  4         108  
55 4     4   20 use Scalar::Util qw(refaddr blessed);
  4         9  
  4         315  
56 4     4   26 use File::Basename;
  4         11  
  4         350  
57 4     4   3193 use IO::File;
  4         41047  
  4         646  
58 4     4   3207 use Mail::Log::Exceptions;
  4         62528  
  4         116  
59 4     4   24 use base qw(Exporter);
  4         6  
  4         245  
60              
61             BEGIN {
62 4     4   20 use Exporter ();
  4         8  
  4         80  
63 4     4   18 use vars qw($VERSION);
  4         6  
  4         148  
64 4     4   1318 $VERSION = '1.0402';
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   1733 my ($self) = @_;
85              
86 10 100       98 $log_info{refaddr $self}{filehandle}->close() if defined($log_info{refaddr $self}{filehandle});
87              
88 10         269 delete $log_info{refaddr $self};
89 10         947 delete $parse_buffer{refaddr $self};
90 10         30 delete $parse_buffer_start_line{refaddr $self};
91 10         26 delete $parse_buffer_size{refaddr $self};
92 10         26 delete $debug{refaddr $self};
93 10         26 delete $current_line{refaddr $self};
94              
95 10         91 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   6 qw{""} => sub { my ($self) = @_;
105             return blessed($self)
106             .' File: '
107             .$log_info{$$self}{'filename'}
108             .' Line: '
109 2         25 .$current_line{$$self};
110             },
111              
112             # Boolean overloads to if we are usable. (Have a filehandle.)
113 4     4   46 qw{bool} => sub { my ($self) = @_;
114 4         22 return defined($log_info{$$self}{'filehandle'});
115             },
116              
117             # Numeric context just doesn't mean anything. Throw an error.
118 2     2   113 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   10 q{<>} => sub { return $_[0]->next(); },
123              
124             # Perl standard for everything else.
125 4         52 fallback => 1,
126 4     4   20 );
  4         8  
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 528 my ($class, $parameters_ref) = @_;
151              
152 10         17 my $self = bless \do{my $anon}, $class;
  10         24  
153 10         310 $$self = refaddr $self;
154              
155             # Log info.
156 10 100       39 if ( defined($parameters_ref->{'log_file'}) ) {
157 4         22 $self->set_logfile($parameters_ref->{'log_file'}); # Better to keep validation together.
158             }
159              
160 8         24 $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         15 $parse_buffer_start_line{$$self} = 0;
167 8         16 $parse_buffer{$$self} = undef;
168 8 100       33 $parse_buffer_size{$$self} = defined($parameters_ref->{buffer_length}) ? $parameters_ref->{buffer_length} : 128;
169              
170              
171 8         25 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 19 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       129 if ( -e $new_name ) {
203 4 50       49 if ( -r $new_name ) {
204 4         18 $log_info{$$self}{'filename'} = $new_name;
205              
206             # We'll check the extension to see if it is compressed.
207 4         284 my (undef, undef, $suffix) = fileparse($new_name, qw(tgz zip gz bz2));
208 4 100       15 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       2 eval { require IO::Uncompress::AnyUncompress } or Mail::Log::Exceptions->throw("Need IO::Uncompress::AnyUncompress for compressed files.\n");
  1         22  
213 1         44 IO::Uncompress::AnyUncompress->import( qw(anyuncompress) );
214              
215             # Same with File::Temp;
216 1 50       2 eval { require File::Temp } or Mail::Log::Exceptions->throw("Need File::Temp version 0.17 or better for compressed files.\n");
  1         7  
217 1 50       19 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         7 my $temp = new File::Temp();
222 1 50       798 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       10216 $temp->seek(0,0)
225             or Mail::Log::Exceptions::LogFile->throw("Unable to seek to beginning of temp file.\n");
226 1         54 $log_info{$$self}{'filehandle'} = $temp;
227             }
228             else {
229             # If it wasn't compressed, open it direct.
230 3 50       23 $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         284 $current_line{$$self} = 0;
236 4         10 delete $log_info{$$self}->{'line_positions'};
237 4         42 ${$log_info{$$self}{'line_positions'}}[$current_line{$$self}] = $log_info{$$self}{'filehandle'}->getpos();
  4         18  
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         34 Mail::Log::Exceptions::LogFile->throw("Log file $new_name does not exist.\n");
245             }
246              
247 4         10 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 13307 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         93 my $current_line = $current_line{$$self};
295              
296 53 100 100     198 if ( defined($parse_buffer{$$self})
      100        
297 49         312 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         33 $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         65 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       123 if ( defined($log_info{$$self}->{line_positions}->[$current_line]) ) {
313 32 50       252 $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     149 if ( defined($parse_buffer{$$self}->[0])
      100        
322 26         151 and $#{$parse_buffer{$$self}} < $parse_buffer_size{$$self}
323             and $current_line >= $parse_buffer_start_line{$$self}
324             ) {
325 4         17 return $parse_buffer{$$self}->[-1];
326             }
327              
328             # Clear the buffer.
329 31         52 @{$parse_buffer{$$self}} = ();
  31         3807  
330              
331             # Read in the buffer.
332 31         89 READ_LOOP: for my $i (0...$parse_buffer_size{$$self}) {
333 2409         6353 $parse_buffer{$$self}->[$i] = $self->_parse_next_line();
334 2406 100       6494 last READ_LOOP unless defined $parse_buffer{$$self}->[$i];
335 2404         4856 $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         52 $parse_buffer_start_line{$$self} = $current_line{$$self} - $#{$parse_buffer{$$self}};
  28         75  
344 28         94 $self->go_to_line_number($parse_buffer_start_line{$$self});
345              
346             # Return the data.
347 28         115 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 3551 my ($self) = @_;
363              
364             # Check if we can.
365 4 100       54 if ( $current_line{$$self} <= 1 ) {
366 2         7 return undef;
367             }
368              
369             # Go back two lines
370 2         6 $self->go_backward(2);
371              
372             # And read forward one, returning that.
373 2         5 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 23368 my $self = shift;
391 21         33 my $lines = shift;
392              
393             # Just because I'm paranoid.
394 21   100     58 $lines ||= 1;
395              
396             # If we've read the line before, go straight to it.
397 21 100       31 if ( ${$log_info{$$self}{line_positions}}[($current_line{$$self}+$lines)] ) {
  21         91  
398 12         24 $current_line{$$self} = $current_line{$$self} + $lines;
399 12         54 return 1;
400             }
401             else {
402             # Work out where we are.
403 9         24 my $start_pos = $self->get_line_number();
404 9         14 my $end_known_pos = $#{$log_info{$$self}{line_positions}}; # zero-indexed.
  9         22  
405 9         19 my $lines_remaining = $lines - ($end_known_pos - $start_pos);
406              
407             # Go to the last line we have.
408 9         12 $current_line{$$self} = $#{$log_info{$$self}{line_positions}};
  9         20  
409              
410             # Then read until we get to the line we want.
411 9 100       22 if ( $self->next() ) {
412 7         16 unshift @_, ($self, $lines_remaining - 1 );
413 7         18 goto &go_forward;
414             }
415             else {
416 2         12 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 9142 my ($self, $lines) = @_;
439              
440             # Just because I'm paranoid.
441 40   100     91 $lines ||= 1;
442              
443             # If the line exits, go straight to it.
444 40 100       103 if ( ($current_line{$$self} - $lines ) > 0 ) {
445 36         90 $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         7 $current_line{$$self} = 0;
450 4         17 return 0;
451             }
452 36         75 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 512 my ($self) = @_;
465              
466 2         5 $current_line{$$self} = 0;
467              
468 2         5 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 3624 my ($self) = @_;
483              
484             # Go to the end of what we have.
485 13         15 $current_line{$$self} = $#{$log_info{$$self}{line_positions}};
  13         37  
486              
487 13 100       32 if ( !$self->next() ) {
488 2         7 return 1;
489             }
490             else {
491 11         28 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 25617 return $current_line{${$_[0]}};
  55         248  
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 4387 my ($self, $line_number) = @_;
522              
523             # my $current_line_number = $self->get_line_number();
524              
525 4     4   6007 no warnings qw(uninitialized);
  4         11  
  4         1702  
526 34 100       94 if ( $current_line{$$self} >= $line_number ) {
527 32         92 return $self->go_backward($current_line{$$self} - $line_number);
528             }
529             else {
530 2         10 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         51 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     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   2571 $current_line{${$_[0]}} += 1;
  2404         4490  
632 2404 50       2929 ${$log_info{${$_[0]}}}{line_positions}[$current_line{${$_[0]}}] = $log_info{${$_[0]}}{'filehandle'}->getpos()
  2404         9232  
  2404         2685  
  2404         4726  
  2404         7922  
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   2891 if ( defined($log_info{${$_[0]}}{'filehandle'}) ){
  2408         6220  
648 2406         2927 return $log_info{${$_[0]}}{'filehandle'}->getline()
  2406         53957  
649             }
650             else {
651 2         15 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   7 my ($self) = @_;
669 5         10 @{$parse_buffer{$$self}} = undef;
  5         874  
670 5         11 $parse_buffer_start_line{$$self} = -1;
671 5         12 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             November 14, 2015 (1.4.2) - Switched from depreciated 'Module::Build::ModuleInfo
719             to it's replacement 'Module::Metadata' and included it in configure_requires.
720             (As it is no longer part of the Module::Build package.)
721              
722             February 8, 2014 (1.4.1) - Switched to using Perl-standard environment variables
723             for checking to run author tests. (Should now test cleanly on Windows.)
724              
725             April 17, 2009 (1.4.0) - Simplified subclassing: No longer need to call
726             C<_set_current_position_as_next_line> in subclass. (A stub exists for backwards
727             compatibility.)
728              
729             April 9, 2009 (1.3.1) - Documentation fixes, better handling of trying to work
730             without a valid logfile.
731              
732             Dec 23, 2008 (1.3.0) - Further code speedups. Now stores a cache of the refaddr
733             for easy and quick access.
734              
735             Dec 09, 2008 (1.2.10) - Profiled and sped up code. (Cut processing time in half
736             for some cases.)
737              
738             Nov 28, 2008 - Documentation fixes.
739              
740             Nov 18, 2008 - Now buffers reading, and prefers data from the buffer.
741              
742             Oct 24, 2008 - File::Temp now optional; only required for uncompressed files.
743             Added go_to_line_number for slightly better functionality.
744              
745             Oct 14, 2008 - Found that I need File::Temp of at least version 0.17.
746              
747             Oct 13, 2008 - Fixed tests so they do a better job of checking if they
748             need to skip.
749              
750             Oct 6, 2008 - Initial version.
751              
752             =for readme continue
753              
754             =head1 COPYRIGHT and LICENSE
755              
756             Copyright (c) 2008 Daniel T. Staal. All rights reserved.
757             This program is free software; you can redistribute it and/or
758             modify it under the same terms as Perl itself.
759              
760             This copyright will expire in 30 years, or 5 years after the author's
761             death, whichever is longer.
762              
763             =cut
764             } # End Package.
765             1;