Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I needed a super-simple way to have a log file for a script that uses some modules of mine, and I wanted the modules to write to the same log file as the script. Here's what I came up with.

In my script:

#!/opt/perl/bin/perl use strict; use warnings; use lib '.'; use MyModule; # ---------- open(my $logfile, '>>', 'blah.log') or die "Couldn't open log file."; sub my_logging_fn { my ($log_msg) = @_; print {$logfile} $log_msg, "\n"; } # ---------- # Set up MyModule to use our logging function. MyModule::set_logger_fn(\&my_logging_fn); # ---------- # main my_logging_fn("Doing something in the script."); MyModule::do_some_work(); my_logging_fn("Ok, that's all for now.");

And in MyModule.pm:

package MyModule; # Before calling any functions in this module, # be sure to first call `set_logger_fn(...)`. my $log_fn_ref; sub set_logger_fn { my ($fn_ref) = @_; $log_fn_ref = $fn_ref; } # ---------- sub do_some_work { # ... # write a log message. $log_fn_ref->("Doing some work in MyModule::do_some_work()"); # ... } 1;

If you see any ways this is broken, please let me know!

  • Comment on my homemade solution to logging (module writes to same log file as the script). What do you think?
  • Select or Download Code

Replies are listed 'Best First'.
Re: my homemade solution to logging (module writes to same log file as the script). What do you think?
by ikegami (Patriarch) on Feb 25, 2010 at 18:53 UTC
    That's fine, although the logging module usually handles the formatting. It saves you from writing the formating code in every script.
    use My::Logger; open(my $log_fh, '>>', 'blah.log') or die "Couldn't open log file."; My::Logger->set_handle($log_fh); My::Logger->log("Processing..."); ... My::Logger->log("done.");
    package My::Logger; my $fh = *STDERR; sub set_handle { my ($class, $new_fh) = @_; $fh = $new_fh; } sub log { my $msg = join('', @_); $msg =~ s/\n+\z/\n/; print $fh $msg; } 1;

    You might want to let the module handle opening the file too (passing it a file name).

      Ah! I don't know why I didn't see that. I could just use a separate MyLoggingModule.pm:

      package MyLoggingModule; use strict; use warnings; # ---------- my $logfile; # ---------- sub init { my ($logfile_name) = @_; open($logfile, '>>', $logfile_name) or die "Couldn't open log file."; } sub loggit { my ($log_msg) = @_; print {$logfile} $log_msg, "\n"; } # ---------- 1;

      and then my script looks like this:

      #!/opt/perl/bin/perl use strict; use warnings; use lib '.'; use MyLoggingModule; use MyModule; use MyOtherModule; # ---------- MyLoggingModule::init('blah.log'); MyLoggingModule::loggit("Doing something in the script..."); MyModule::foo(); MyOtherModule::bar(); MyLoggingModule::loggit("My work here is done.");

      and my modules look like this:

      package MyModule; use strict; use warnings; use lib '.'; use MyLoggingModule; # ---------- sub foo { # ... # write a log message. MyLoggingModule::loggit("Doing some work in MyModule::foo()"); # ... } 1;

      and this:

      package MyOtherModule; use strict; use warnings; use lib '.'; use MyLoggingModule; # ---------- sub bar { # ... # write a log message. MyLoggingModule::loggit("Doing some work in MyOtherModule::bar()") +; # ... } 1;

      Thanks!