Alex, short for Alexander, is a project I'm working on which involves a lot of batch processing jobs. The Boss wanted the logging information to go to the MySQL database instead of plain files, so I could make a pretty web interface for him to monitor the progress of various backend processes. (Yeah, I could have made a pretty web interface for flat files also, but such is The Boss.) Many log systems have different levels to indicate the severity of a message (or whether to even log it at all.) This system started out that way, but soon the "levels" really changed into "categories" which were not necessarily good or bad, so The Boss could run SQL queries against the log table to get information about a particular category of messages. I decided to experiment with closures and auto-generation of methods, and put all the categories into the database, so The Boss could add new ones himself. Upon instantiation, my log object would build a method for each category it found in the database. It works perfectly, but I'd like to hear any comments as this is the first time I've deployed something with dynamic methods on a large scale.
I'm sure there are also some CPAN modules that do this kind of thing, but I was in the mood for experimentation and it only took a few minutes to write. (And it worked right the first time, always a nice feeling.)
package Alex::Log;
use strict;
use warnings;
use lib '/usr/local/alex/lib';
use Carp qw(croak);
use Alex::DBI;
sub new {
my $class = shift;
my %args = @_;
croak "No program name given to constructor.
( program => 'foo' required )"
unless exists $args{program};
my $pname = $args{program};
my $dbh = Alex::DBI->new;
my ( $pid ) = $dbh->selectrow_array( "SELECT id FROM Log_Programs
WHERE name = '$pname'" );
croak "Program $pname not in database" unless $pid;
my $levels = $dbh->selectall_arrayref( "SELECT id, name
FROM Log_Levels" );
foreach my $lev( @$levels ) {
# install dynamic method
my $lid = $lev->[0];
my $name = $lev->[1];
no strict 'refs';
*{ "Alex::Log::$name" } = sub {
my $self = shift;
my $msg = shift;
# truncate msg if needed.
if ( length( $msg ) > 2048 ) {
$msg = substr $msg, 0, 2048;
}
$msg = "[PID:$$] " . $msg;
my $sth = $dbh->prepare( "INSERT INTO Logs
( log_level_id,
log_program_id,
message )
VALUES ( ?, ?, ? )" );
$sth->execute( $lid, $pid, $msg );
};
}
return bless { }, $class;
}
1;
Thanks for looking.
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.