Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling

Logging Singleton

by Anonymous Monk
on Feb 18, 2013 at 16:45 UTC ( #1019364=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks, hoping you can advise. I created a logging singleton to use across various packages. Each time I want some logging done I check to see if there is an instance of the log already ($log = Log->new();) otherwise create the log. Then log what I want $log->log('Log This'); There are 30+ subroutines. Is the call to sub new in each sub an ok practice? Please let me know if there is a better way or a perferred method. Thanks
package Log; my $singleton; sub new { # Check to see if we have a Log instance # Otherwise return singleton unless ( $singleton ){ my ($class,$path) = @_; $singleton = {}; bless $singleton, 'Log'; $singleton->create_logfiles($path); } return $singleton; } sub create_logfile{ create logfile } sub log { print to logfile } # SUBS sub do_this{ my $log = Log->new(); $log->log('Log This'); } sub do_that{ my $log = Log->new(); $log->log('Log That'); }

Replies are listed 'Best First'.
Re: Logging Singleton
by tobyink (Abbot) on Feb 18, 2013 at 16:51 UTC

    It's probably overkill. You could do this...

    # SUBS my $log = Log->new(); sub do_this{ $log->log('Log This'); } sub do_that{ $log->log('Log That'); }

    Or even this...

    # SUBS my $log; sub do_this{ ($log||=Log->new)->log('Log This'); } sub do_that{ ($log||=Log->new)->log('Log That'); }
    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
Re: Logging Singleton
by 7stud (Deacon) on Feb 18, 2013 at 17:26 UTC

    Please let me know if there is a better way or a perferred method.

    1. Rename new() to get_logger()?
    2. Use a closure?
    3. use strict; use warnings; use 5.012; package Log; { my $logger; sub get_logger { if (not $logger) { my ($class, $path) = @_; say "Creating logger..."; $logger = {}; bless $logger, "Log"; $logger->create_logfile($path); } else { say "Logger already exists..." } return $logger; } } sub create_logfile { } sub do_stuff { #$logger = 'hello'; }
      use strict; use warnings; use 5.012; use Log; my $log = Log->get_logger(); #Creating logger... $log = Log->get_logger(); #Logger already exists... $log = Log->get_logger(); #Logger already exists... #$log->do_stuff;

      With a closure, you can't (mistakenly) change the $logger singleton in another subroutine:

      Global symbol "$logger" requires explicit package name at line +32. Compilation failed in require at line 5.

      The my variable $logger ceases to exist after the end of the block, and thereafter only the sub get_logger() can see the $logger variable.

      Thank you. Haven't implemented a closure before but I'll read up on them. Thanks!
Re: Logging Singleton
by blue_cowdawg (Monsignor) on Feb 18, 2013 at 18:45 UTC

    Do you really need a singleton? Consider the following:

    package Log; use strict; use warnings; require Exporter; our @ISA = qw(Exporter); our %EXPORT_TAGS = ( 'all' => [ qw( logit ) ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw( logit ); sub logit { # real stuff goes here. printf "%s\n",join("\n",@_); } 1;
    Using the above looks something like this:
    #!/usr/bin/perl -w use strict; use Log qw/ :all /; logit("This is something to log");
    Just another way of doing it I guess...

    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
Re: Logging Singleton
by manorhce (Beadle) on Feb 18, 2013 at 18:56 UTC

    Hi It will be easy if you will follow to Log::Log4perl module which cpan provides

    you can call the log method like Log->info($message)

    Create a module with using Log::Log4perl

    BEGIN { require Exporter; push @ISA, qw(Exporter); @EXPORT = ( @Data::Dumper::EXPORT, @Carp::EXPORT, qw($log get_logger); $conf_file="path to log4perl.conf"; eval { Log::Log4perl->init($conf_file); } if ($@) { die "Cann't open the file" if ($@ =~ m/Permission/gi); } Log::Log4perl->get_logger("My::MegaPackage"); } sub new { my $class = shift; return bless {}, $class; } sub info { my ($self, $message) = @_; my ($package, $filename, $line) = caller; my $_log = Log::Log4perl->get_logger($packa +ge); $log->info($message) if ($log->is_info()); } sub error { my ($self, $message) = @_; my ($package, $filename, $line) = caller; my $_log = Log::Log4perl->get_logger($packa +ge); $log->error( longmess($message) ) if ($log->is_error()); } sub debug { my ($self, $message) = @_; my ($package, $filename, $line) = caller; my $_log = Log::Log4perl->get_logger($packa +ge); $log->debug($message) if ($log->is_debug()); }

    and by using this module and calling get_logger() method your job will be easy

    Please let me know if you are unclear on this and I will suggest to follow Log::Log4perl for better logging messages

      Thanks. I would have used log4perl but unfortunately working with older version of Perl.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1019364]
Approved by Corion
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (10)
As of 2016-07-26 17:11 GMT
Find Nodes?
    Voting Booth?
    What is your favorite alternate name for a (specific) keyboard key?

    Results (238 votes). Check out past polls.