Micheal
Micheal

Reputation: 2322

perl log db query errors into a log file

So I started to get familiar with Perl and I wrote my first Db script.

Now I am trying to select data from atable which is huge and trying to insert into a summary table based on some criteria.

Now there are chances , that select query may fail or the insert query may fail due to timeout or other database issues that is beyond my control.

Eventually my script is going to be cron script.

Can I log just the errors that i encounter for the connection,inserts and selects into a file generated in the script?

$logfile = $path.'logs/$currdate.log';

here is my code:

my $SQL_handled="SELECT  division_id,region_id, NVL(COUNT(*),0) FROM super_tab GROUP BY division_id,region_id;";
my $result_handled = $dbh->prepare($SQL_handled);
$result_handled->execute();
while (my ($division_id,$region_id,$count ) = $result_handled->fetchrow_array()){
    my $InsertHandled="INSERT INTO summary_tab (date_hour, division_id, region_id,volume) VALUES ('$current',$division_id,$region_id,$market_id,'$service_type','$handled',$count);";
    my $result_insert_handled = $dbh->prepare($InsertHandled);

    $result_insert_handled->execute();

}

something like

if(DBI-query failed ) { // log the error onto the above logpath }

Upvotes: 1

Views: 3791

Answers (2)

Anjan Biswas
Anjan Biswas

Reputation: 7932

Its usually done like this

my $SQL_handled="SELECT  division_id,region_id, NVL(COUNT(*),0) FROM super_tab GROUP BY division_id,region_id;";
my $result_handled = $dbh->prepare($SQL_handled);
my $retval = $result_handled->execute();
if(!$retval){
    #open a log file and write errors 
    writelog();
    die "Error executing SQL SELECT - $dbh->errstr";
}
while(my ($division_id,$region_id,$count ) = $result_handled->fetchrow_array()){....
 }

---------------------------------

sub writelog{
   my $path = "/path/to/logfile";
   my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
   $year += 1900; 
   $mon++;
   my $currdate = "$mon$mday$year";

   $logfile = $path . "/$currdate.log";
   open (OUT, ">>$logfile");
   print OUT "There was an error encountered while executing SQL- $dbh->errstr \n";
   close(OUT);
}

You can also use $dbh->err; which returns the native Oracle error code to trap the error and exit accordingly.

The above, basic exception handling can be performed for every execute() method call in your script. Remember, DBI will have AutoCommit set to 1 (enabled) by default, unless explicitly disabled. So your transactions would be auto committed per insert, in order to handle the ATOMICITY of the entire transaction, you can disable autocommit and use $dbh->commit and $dbh->rollback to handle when you want to commit, or may be use some custom commit point (for larger sets of data).

Or the below can be used while connecting to the DB

$dbh = DBI->connect( "dbi:Oracle:abcdef", "username", "password" , {
  PrintError => 0,   ### Don't report errors via warn(  )
  RaiseError => 1    ### Do report errors via die(  )
} );

this would automatically report all errors via die. The RaiseError is usually turned off by default.

Also if I understand you correctly then, by cron you mean you would be calling it from a shell cron job. In that case, call to your perl script from the cron itself can be redirected to log files something like below

perl your_perl.pl >> out.log 2>> err.log

out.log will contain regular logs and err.log will contain errors (specifically thrown by DBI prepare() or execute() methods too). In this case, you also need to make sure you use proper verbiage in print or die so that the logs look meaningful.

Upvotes: 2

bohica
bohica

Reputation: 5990

First, bear in mind that if you put an email address at the top of your crontab file any output from the cron job will be emailed to you:

[email protected]

Second, if you set DBI's RaiseError to 1 when you connect you do not need to check every call, DBI will raise an error whenever one happens.

Third, DBI has an error handler callback. You register a handler and it is called whenever an error occurs with the handle in error and error text etc. If you return false from the error handler, DBI works as it would without the handler and goes on to die or warn. As a result, it is easier to set RaiseError and create an error handler than as Annjawn suggested.

Lastly, if you don't want to do this yourself, you can use something like DBIx::Log4perl and simply ask for it to log errors and nothing else. Any errors will be written to your Log4perl file and they include the SQL being executed, parameters etc.

Upvotes: 1

Related Questions