How to handle this situatiuon in Perl - perl

I am having a configuration INI file to store all configuration required for my script to run. I have a Logger.PM which uses Log4Perl, and ConfigReader.PM which reads the INI file and stores the value in global variable. My Start.PL is the entry point where i call the methods from Logger and configreader.
What I do currently
In Start.PL I hardcoded the INI file path
In Logger.Pm I harcoded the directory name where log files should be stored
What I want
I want the INI file path as configurable
I want the log folder path to be taken from the INI file
I could do this by following
Pass the INI file path as a parameter to the start.pl
Read the INI file and get the folder path from INI file
What I could face is that
I cannot use the Logger.PM in ConfigReader (partially) since the
folder name required for logger is part of INI file
I want to log every step of my script (for logging/debugging purpose in case of failure. )
I can use print but this will write to console and to capture i need to use >>log.txt. Then i will be forced to maintain 2 logs for my application which is not what I wanted
Anyone have a good solution for this scenario?

You can pass INI file path in command line using Getopt::Long, and command line switches for istance:
Start.pl --ini=/path/to/INI_file
Here is a code sample to show what changes are needed in Start.pl, in order to have switches:
#!/usr/bin/env perl
use v5.12;
use strict;
use Getopt::Long;
# That little tiny 's' after 'ini=' is for string
GetOptions ( 'ini=s' => \my $ini_file );
say $ini_file;
After this change, you can read all options from your INI file, including log folder path ( are you already using a module to manage INI files like Config::IniFiles? ).
There is something still unclear in your question about print: although one of my master said that print with a pair of square brackets is the best debugger in the world, why use print when you have set up Log::Log4perl?
When you say that Logger.PL can't be used in ConfigReader, are you referring to the log object?

Related

Perl Net::FTP not lists particular file

I am trying to list the file of remote host using Net::FTP Perl module. Later I want to download it using put command.
Will it possible to list the particular file using ls command
Syntax I am using is:
$remote_dir = "/home/user/test_dir/";
$ftp->cwd($remote_dir);
$file_name = "test.txt";
print $ftp->ls($file_name);
This file is exists in remote server when I tried checking it manually. But listing is not happening.
ftp->ls(); is used for only listing the directory contents or can it be used to list the particular file from a directory as I mentioned above?
ftp->ls(); is used for only listing the directory contents or can it be used to list the particular file from a directory
From the documentation:
ls ( [ DIR ] )
Get a directory listing of DIR, or the current directory.
Thus, it is clearly documented to list a directory, not a specific regular file.

Execute perl script using mason template

I have installed Mason module from cpan. Now i am executing my first program using mason template.
first_mason.mc
% my $name = "Mason";
Hello world! Welcome to <% $name %>.
first_mason.pl
#!/usr/local/bin/perl
use Mason;
my $mason = Mason->new(comp_root => '...');
print $mason->run('first_mason.mc')->output;
This throws an error as follows
first_mason.mc is not an absolute path at C:/Perl/site/lib/Mason/Request.pm line 256**
Note
I am placing both files in the path where mason is installed(to find an installation path ,i used perldoc -l Mason) and executed a program using perl first_mason.pl
There is no need to put your files in the directory where Mason is installed:
Perl should know where to find Mason when you import it with use (assuming your perl installation is correct).
Mason will know where to find the .mc file via the comp_root argument.
The component name needs to be specified as a path relative to comp_root, always beginning with /.
You need to leave out the .mc from the component name.
So, if you place the 2 files in your home directory, then the script should look like this:
#!/usr/local/bin/perl
use Mason;
my $mason = Mason->new(comp_root => $HOME_DIR); # where $HOME_DIR is `C:\User\your_name`
print $mason->run('/first_mason')->output;
From the documentation:
The component root and component paths
When you use Mason, you specify a component root that all component
files live under. Thereafter, any component will be referred to by its
virtual path relative to the root, rather than its full filename.
For example, if the component root is '/opt/web/comps', then the
component path '/foo/bar.mc' refers to the file
'/opt/web/comps/foo/bar.mc'.
#stevenl fully answers your question. Simply don't blindly copy the Synopsis from the Mason docs, need read the docs too. :) E.g. in the example code:
#!/usr/local/bin/perl
use Mason;
my $mason = Mason->new(comp_root => '...');
print $mason->run('/foo')->output;
you need replace
and the shebang line #!/usr/local/bin/perl with the real path to your perl interpreter
the '...' with the real path in the filesystem, where your component are, e.g.
comp_root => '/some/real/path/here/where/my/component/root/is'
However, I wrote this answer mainly with a reason: if you want use the Mason for the web-app development, check the Poet module too. It GREATLY simplifies the whole process, and you will not need care about many-many things. E.g. after installing the Poet you can simply:
poet new MyApp
myapp/bin/run.pl
and you will immediately get (without any configuration) an WORKING web-app, and you could access it in your browser at http://localhost:5000. Your component_root will be inside of the myapp directory as myapp/comps.

file for saving cookie data not found when using HTTP::Cookies in Perl script

all. I had some questions about the Perl module HTTP::Cookies. The example on CPAN is like below:
$cookie_jar = HTTP::Cookies->new( file => '$ENV{\'HOME\'}/lwp_cookies.dat', autosave => 1);
The lwp_cookies.dat file is used to save cookie data on my local machine as I understand. On my machine, '$ENV{\'HOME\'}' is an empty path. The script runs good, even after execution I can't find any file named "lwp_cookies.dat" on my machine. I changed '$ENV{\'HOME\'}' to '$ENV{\'TMP\'}', which is a path really exists after I verified by Perl print. Still I can't find the "lwp_cookies.dat" in my TEMP folder. My first question is how the HTTP::Cookies is working with the "lwp_cookies.dat" file.
On the other hand, on one of my systems(all're Windows system as mentioned here), the same code produce error message below:
Can't open $ENV{'HOME'}/lwp_cookies.dat: No such file or directory
So it's strange to me. On my good system, even file or path not exists, the script runs well, which I suppose the file is created on some temp memory instead; on bad system, the code example doesn't work at all.
If you want the $ENV{'HOME'} variable to interpolate into the string, you need double quotes; single quotes don't interpolate variables:
`file => "$ENV{'HOME'}/lwp_cookies.dat",`

Sphinx variables

I have a lot of filenames in my Sphinx config with name like /home/ubuntu/sites/sitename.dev/data/sphinx/searchd.pid with same path prefix.
Can I separate path /home/ubuntu/sites/sitename.dev/data/sphinx/ from that filename into variable to use it like $path/searchd.pid?
Its a little known feature, but the config file can actully be a script - such as PHP, perl or even plain old bash. Just uses a classic shebang line - if the first line begins with #! that intpreter is used to execute the script, and the output used as the conf file.
Example for PHP..
#!/usr/bin/php
<?php
$path = "/home/ubuntu/sites/sitename.dev/";
?>
searchd {
pid_file = <?php echo $path; ?>/searchd.pid
}
As a side note why are you having multiple pid files? Surely its best to have one single pid file - ie one single instance of searchd. A single instance can serve many indexes.
You can use this scripting capablity, to keep seperate 'files' for each index (for easy of use) - which the script consolidates into one file for use.

Log4Perl: How do I change the logger file used from running code? (After a fork)

I have an ETL process set up in perl to process a number of files, and load them to a database.
Recently, for performance reasons I set up the code to be multi-threaded, through use of a fork() call and a call to system("perl someOtherPerlProcess.pl $arg1 $arg2").
I end up with about 12 instances of someOtherPerlProcess.pl running with different arguments, and these processes each work through one directories worth of files (corresponding to a single table in our database).
The applications main functions work, but I am having issues with figuring out how to configure my logging.
Ideally, I would like to have all the someOtherPerlProcess.pl share the same $log_config value to initialize their loggers, but have each of those create a log file in the directory they are working on.
I haven't been able to figure out how to do that. I also noticed that in the directory I am calling these perl scripts from I see several files (ARRAY(0x260eec), ARRAY(0x313f8), etc) that contain all my logging messages!
Is there a simple way to change the log4perl.appender.A1.filename value from running code?
Or to otherwise dynamically configure the file name we use, but use all other values from a config file?
I came up with a less than ideal solution for this, which is to configure my logger from someOtherPerlProcess.pl directly.
my $FORKED_LOG_CONF = "log4perl.appender.A1.filename=$directory_to_load/log.txt
log4perl.rootLogger=WARN, A1
log4perl.appender.A1=Log::Log4perl::Appender::File
log4perl.appender.A1.mode=append
log4perl.appender.A1.autoflush=1
log4perl.appender.A1.layout=PatternLayout
log4perl.appender.A1.layout.ConversionPattern=[%p] %d{yyyy-MM-dd HH:mm:ss}: %m%n";
#Logger start up
Log::Log4perl::init( \$FORKED_LOG_CONF);
my $logger = get_logger();
The $directory_to_load is the process specific portion of the logger, which works in the context of the perl process that is running and has a (local) value for that variable, but that method will fail if used in an external config file.
I would be happy to hear of any alternative solutions.
In your config file:
log4perl.appender.A1.filename=__LOGFILE__
In your script:
use File::Slurp;
my $log_cfg = read_file( $log_cfgfile );
my $logfile = "$directory_to_load/log.txt";
$log_cfg =~ s/__LOGFILE__/$logfile/;
Log::Log4perl::init( \$log_cfg );