Logging module sometimes writes its file in the wrong directory
Anonymous Monk
created: 2006-05-03 11:38:16
Hi Monks,
I have this small Perl Module to trap warning error(s) to a text file, but it sometimes instead of creating like it supposed to a text file into the current directory where the program is running from, it is creating the text file to the root directory of the program calling it. I don't even know where to start looking for this bug, may be there is something on my module that should be done differently n order not to produce surprises like that.
any help or thoughts on that?
Thanks and here is a sample of this module:


package Log::Error;

use 5.008004;
use strict;
use Cwd;
use CGI::Carp qw(carpout);
use CGI qw(:standard);
use CGI::Carp qw(fatalsToBrowser);

use vars qw(@EXPORT @ISA $VERSION);

require Exporter;

@ISA = qw(Exporter);

@EXPORT = qw(
                   a_log
                   e_log
);

$VERSION = '0.01';

my $localtime     = localtime;

our $dir;

BEGIN
 {
  if ($::dir) {
	$dir = $::dir;
   }
  else {
    $0 =~ '(.*[\\\/])\w+\.\w+$'; 
    $dir = $1;
   }
 }

# Set up main error log file

my $log_file = "e_log.txt";

#Croak will get the line number of the calling program, not the library itself.

open(LOG, ">>$dir/$log_file") or croak "Unable to append to error log: $!";
carpout(*LOG);

##### ***subroutine who print in Appplication Specific Error***

sub a_log{

my $a_localtime = localtime;

my ($a_log, @data) = @_;

#To determine the name of the currently running function, including its package by using the built-in function "caller".
my $sub_al = (caller(0))[3];

#Make sure that the filename doesn't have spaces or extensions like exe or bat on it, 
#otherwise it will create file as app_log.txt instead.

unless($a_log=~/^[a-zA-Z_]+\.(?!bat$|exe$)[a-zA-Z_]{3}$/gi)
{
  
  $a_log="a_log.txt"

}
 open(LOGAPP, ">>$dir$a_log") 
      or croak "Unable to append to $a_log: $!";
 #print LOGAPP "[$localtime] $a_log : @data ::::: $!\n";
  print LOGAPP "[$a_localtime] $a_log : @data \n";
 close LOGAPP or die "Cannot close log file:: $a_log : $!\n"; 
 
} 

sub e_log{ 

my $e_localtime = localtime;
my ($e_log, @e_data) = @_;

#To determine the name of the currently running function, including its package by using the built-in function "caller".
my $sub_el = (caller(0))[3];

#Make sure that the filename doesn't have spaces or extensions like exe or bat on it, 
#otherwise it will create file as app_log.txt instead.

unless($e_log=~/^[a-zA-Z_]+\.(?!bat$|exe$)[a-zA-Z_]{3}$/gi)
{
  
  $e_log="errorapp_log.txt"

}
 open(ERRAPPLOG, ">>$dir$e_log") 
       or croak "Unable to append to $e_log: $!";
  print ERRAPPLOG "[$e_localtime] $e_log : @e_data\n";
 close ERRAPPLOG or die "Cannot close log file:: $e_log : $!\n"; 
 
} 


1;
__END__

=head1 DESCRIPTION
 
Errors trapped by -w (Warning) will issue a warning and report the line number of the error.
Die will cause the program to die and report the line number of the error.
All the errors will be printed to e_log.txt in the same directory where the program that caused the error is running.

Called like:
             &e_log('my_file.txt','Oh no, $hit hit the fan.');


2006-05-03 Retitled by [Arunbear], as per Monastery [id://341118|guidelines]
Original title: 'Module Question'

Re: Logging module sometimes writes its file in the wrong directory
created: 2006-05-03 11:56:41
I don't even know where to start looking for this bug,
It's opening in the "wrong" place, so let's start with the open call:
open(LOG, ">>$dir/$log_file") or croak "Unable to append to error log: $!";
So it uses $dir .. now to see where that's set, which is in BEGIN .. and has this snippet:
    $0 =~ '(.*[\\\/])\w+\.\w+$'; 
    $dir = $1;
Several important items here:
  • never use $1 w/o checking that the match actually succeeded .. if you don't, you'll get unexpected values.
      $dir = $1 if $0 =~ m#/.*[\\/])\w+\.\w+$#;
    
  • $0 is the program being run, so this is setting $dir to that path. Thus why that's where the log file is being opened.
  • Use something like [cpan://File::Basename] to parse the path instead of a regex. For example, if the script is /usr/local/bin/foo (instead of foo.pl) then your regex fails.
    use File::Basename;
    $dir = dirname($0);
    
Re^2: Logging module sometimes writes its file in the wrong directory
created: 2006-05-03 12:55:30
Do you think that I should just get rid of the
BEGIN
 {
  if ($::dir) {
	$dir = $::dir;
   }
  else {
    $0 =~ '(.*[\\\/])\w+\.\w+$'; 
    $dir = $1;
   }
 }

And just use
use File::Basename;

my $dir = dirname($0);

in the module?
Re^3: Logging module sometimes writes its file in the wrong directory
created: 2006-05-03 13:33:59
If you want to use the directory where your script is, then yes. You can also use:
use FindBin qw($Bin);
my $dir = $Bin;
-imran
Update: if you want to open the file in the current directory that you are in, don't use $dir, just do open with the filename. This is unless a chdir was done.
Re: Logging module sometimes writes its file in the wrong directory
created: 2006-05-04 10:56:59
You have a bizarre idea about what "current directory" means, IMO. It does not mean "the directory the script is in", it is the directory the user is in, as in what directory is used when you type "dir" or "ls". In Perl, you can get that path by using cwd from the module Cwd.

If you want to always use the directory the script is in, in theory you should be using FindBin, but it is rubbish. Instead, look at tye's mechanism to derive the directory from $0, in node 41213. rel2abs can be found in File::Spec as a class method, or in File::Spec::Functions as a function. (Both come with Perl.)

Using File::Basename, you can then extract the directory the script is in.

perlmonks.org content © perlmonks.org and Anonymous Monk, bart, CountOrlok, davidrw

prlmnks.org © 2006 edmund von der burg (eccles & toad)

v 0.03