SYNOPSIS use Mail::Log::Parse; $object = Mail::Log::Parse->new({ log_file => '/path/to/logfile' }); %line_info = %{object->next()}; $line_num = $object->get_line_num(); if ( $object->go_forward($amount) ) { ... } if ( $object->go_backward($amount) ) { ... } %line_info = %{object->previous()}; DESCRIPTION This is the root-level module for a generic mail log file parser. It is capable of opening either a compressed or uncompressed logfile, and either stepping through it line by line, or seaking around in it based on the logical lines. (Lines not pertaining to the type of log currently being searched are skipped, as if they don't exist.) On it's own it doesn't actually do much: You'll need a subclass that can parse a particular program's log entries. But such subclasses are designed to be easy to write and use. USAGE This is an object-oriented module. Avalible object methods are below. In a string context, it will return a string specifying the path to the file and the current line number. In a boolean context, it will return whether it has been correctly initilized. (Whether it has a file.) Numeric context throws an error. Oh, and interator context ('<>') returns the same as 'next'... new (constructor) The base constructor for the Mail::Log::Parse classes. It takes an (optional) hash containing path to the logfile as an arugment, and returns the new object. Example: $object = Mail::Log::Parse->new({ log_file => '/path/to/logfile' }); Note that it is an error to call any method other than `set_logfile' if you have not passed it in the constructor. set_logfile Sets the logfile that this object will attempt to parse. It will throw exceptions if it can't open the file for any reason, and will return true on success. Files can be compressed or uncompressed: If they are compressed, then `IO::Uncompress::AnyUncompress' must be installed with the relevant decompression libraries. (As well as version 0.17 or better of File::Temp.) Currently only 'tgz', 'zip', 'gz', and 'bz2' archives are supported, but there is no technical reason not to support more. (It just keeps a couple of lines of code shorter.) Note that to support seeking in the file the log will be uncompressed to disk before it is read: If there is insufficent space to do so, we may have trouble. It also means this method may take a while to return for large compressed logs. Example: $object->set_logfile('path/to/file'); next Returns a reference to a hash of the next parsable line of the log, or undef on end of file/failure. There are a couple of required keys that any parser must implement: timestamp, program, id, text. Where `timestamp' must the the unix timestamp, `program' must be the name of the program that reported the logline (Sub-programs are recommened to be listed, if possible), `id' is the tracking ID for that message, as reported by the program, and `text' is the text following any 'standard' headers. (Usually, minus those already required keys.) This version is just a placeholder: It will return a 'Mail::Log::Exceptions::Unimplemented' exception if called. It is expected to be overridden by the subclass. (And is the only method needed to be overridden.) Other 'standard' fields that are expected in a certain format (but are not required to always be present) are 'from', 'to', 'size', 'subject'. 'to' should point to an array of addresses. (As listed in the log. That includes angle brackets, usually.) Example: while $hash_ref ( $object->next() ) { ... } or... while $hash_ref ( <$object> ) { ... } previous Returns a reference to a hash of the previous line of the log, or undef on failure/beginning of file. See `next' for details: It works nearly exactly the same. (In fact, it calls next as a parser.) go_forward Goes forward a specifed number of (logical) lines, or 1 if unspecified. It will throw an error if it fails to seek as requested. Returns true on success. Example: $object->go_forward(4); go_backward Goes backward a specifed number of (logcial) lines, or 1 if unspecified. It will throw an error if it fails to seek as requested. If the seek would go beyond the beginning of the file, it will go to the beginning of the file. Returns true on success. Example: $object->go_backward(4); go_to_beginning Goes to the beginning of the file, no matter how far away that is. Returns true on success. go_to_end Goes to the end of the file, no matter where it is. This attempts to be efficient about it, skipping where it can. Returns true on success. get_line_number Returns the current logical line number. Note that line numbers start at zero, where 0 is the absolute beginning of the file. Example: $line_num = $object->get_line_number(); go_to_line_number Goes to a specific logical line number. (Preferably one that exits...) UTLITY METHODS The following methods are not for general consumption: They are specifically provided for use in implementing subclasses. Using them incorrectly, or outside a subclass, can get the object into an invalid state. ONLY USE IF YOU ARE IMPLEMENTING A SUBCLASS. _set_current_position_as_next_line Sets the current position in the file as the next 'line' position in sequence. Call once you have determined that the current line of data (as returned from `_get_data_line') is parsable in the currently understood format. _get_data_line Returns the next line of data, as a string, from the logfile. This is raw data from the logfile, seperated by the current input seperator. Suggested usage: Suggestion on how to use the above two methods to implement a 'next' routine in a subclass: sub next { my ($self) = @_; # The hash we will return. my %line_info = ( program => '' ); # Some temp variables. my $line; # In a mixed-log enviornment, we can't count on any # particular line being something we can parse. Keep # going until we can. while ( $line_info{program} !~ m/$program_name/ ) { # Read the line. $line = $self->_get_data_line() or return undef; # Program name. $line_info{program} = $line ~= m/$regrex/; } # Ok, let's update our info. $self->_set_current_position_as_next_line(); # Continue parsing ... BUGS `go_forward' and `go_backward' at the moment don't test for negative numbers. They may or may not work with a negative number of lines: It depends where you are in the file and what you've read so far. Those two methods should do slightly better on 'success' testing, to return better values. (They basically always return true at the moment.) REQUIRES Scalar::Util, File::Basename, IO::File, Mail::Log::Exceptions RECOMMENDS IO::Uncompress::AnyUncompress AUTHOR Daniel T. Staal DStaal@usa.net SEE ALSO Parse::Syslog::Mail, which does some of what this module does. (This module is a result of running into what that module doesn't support. Namely seeking through a file, both forwards and back.) HISTORY Oct 24, 2008 - File::Temp now optional; only required for uncompressed files. Added go_to_line_number for slightly better functionality. Oct 14, 2008 - Found that I need File::Temp of at least version 0.17. Oct 13, 2008 - Fixed tests so they do a better job of checking if they need to skip. Oct 6, 2008 - Inital version. COPYRIGHT and LICENSE Copyright (c) 2008 Daniel T. Staal. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. This copyright will expire in 30 years, or 5 years after the author's death, whichever is longer.