http://qs321.pair.com?node_id=114485
Category: Miscellaneous
Author/Contact Info Michael Joyce, coolmichael
Description: This module uses the DBI and DBD::CSV to handle all the file locking necessary for a simple logging facility.

I needed something like this for some of my CGI scripts. Appending to a table was a problem, as the file would sometimes loose some. I couldn't get flock to work, wanted to try writing object oriented perl.

Sample useage:

my $log=Logger->new("logfile", "/home/michael/logs"); open FILE, "myfile" or { $log->logger("something bad happened: $!"); die; }
I found it useful to have two log files open at the same time, one for fatal errors and one for warnings generated by bad input, or other non-fatal (recoverable) problems.

Please comment.

#!perl -w

# Log.pm -- a simple logger which uses DBI and DBD::CSV to
# handle all the file locking. All log entries are kept in
# a text file, to make reading it much easier than if they
# had been put into a real database.
# copyright September 23, 2001 by Michael S. Joyce
# michaeljoyce@telus.net
# This code may be used and distributed under the same terms
# as Perl.
# TODO:
# add an option to make database connections
# happen with each call to logger(), instead of
# maintaining the connection for the lifetime of
# the program

use DBI;
use strict;

package Logger;

use vars qw($tbldefault $dbdefault);

# default name for the log file
$tbldefault="errlog";

# default directory for the log files
$dbdefault='E:\\\\log';

# check to see if a log file exists,
# and create it if it doesn't.
sub tblexists {
  my $dbh = shift;
  my $tblname = shift;

# $dbh->tables() is a new method in DBI version 1.09
  unless (scalar grep {$_ eq $tblname} $dbh->tables())
  {
    my $crtstr=<<ENDQ;
      CREATE TABLE $tblname(
        date      CHAR(24),
        filename  CHAR(24),
        lineno    CHAR(8),
        message   VARCHAR(256)
       )
ENDQ
    $dbh->do($crtstr) or die "creating table: $!\n$dbh->errstr";
  }
}

# initialize the logger
# put a statement handle and database handle
# into self, as well as other potentially useful information
sub initialize {
  my $self = shift;
  
  $self->{'tblname'}=shift || $tbldefault;
  $self->{'dbname'}=shift || $dbdefault;
  $self->{'constr'}="DBI:CSV:f_dir=$self->{'dbname'}";

  my $dbh = DBI->connect($self->{'constr'})
    or die "No Database Connection Made: $!\n $DBI::errstr\n";
  $self->{'dbhandle'}=$dbh;

  tblexists($dbh, $self->{'tblname'});

  my $instr="INSERT INTO $self->{'tblname'} VALUES (?,?,?,?)";
  my $sth=$dbh->prepare($instr);
  $self->{'sthandle'}=$sth;
}

# simple constructor
# most of the work is done in initialize()
sub new {
  my $class = shift;
  my $self = {};
  bless $self, $class;
  $self->initialize(@_);
  return $self;
}

# member function to log a message
sub logger {
  my $self = shift;
  my $sth = $self->{'sthandle'};
  my $time=localtime();
  my $message = shift;

  my ($package, $filename, $line) = caller;
  
  $sth->execute($time, $filename, "line $line", $message);
}

# Destructor to cleanup database connections
sub DESTROY {
  my $self = shift;
  my $dbh = $self->{'dbhandle'};
  $dbh->disconnect();
}

1;