Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

"Global" filehandle without using global variables

by Anonymous Monk
on Jun 18, 2012 at 20:52 UTC ( [id://976898]=perlquestion: print w/replies, xml ) Need Help??

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

Perl Monks, i'm somewhat a of Perl Rookie and i'm looking to write a program where I need to maintain a log file. The program will be farily long, and i'd like to simply be able to call a subroutine with a message and have it timestamp it and output it to the log file. For example:

sub log_it { my $fh = shift; my $message = shift; my $timestamp = time; print $fh $timestamp . ": " . $message . "\n"; }

I'd like to be able to call log_it from anywhere without having to pass $fh (the filehandle for the logfile) though every subroutine in the entire program just so I can log to that file. I know one solution would be open and close the log file every single time, but that dosn't seem that practical to me (or a very good practice). I realize there a numerous logging modules in CPAN, most of which are overkill for what I want to do, but i'd rather learn the best (object oriented?) method for doing this without using a global filehandle.

Thanks!

Replies are listed 'Best First'.
Re: "Global" filehandle without using global variables
by tobyink (Canon) on Jun 18, 2012 at 21:22 UTC
    sub log_it { state $fh = do { open my $x, '>>', 'mylog.txt'; $x }; my $message = shift; my $timestamp = time; print $fh $timestamp . ": " . $message . "\n"; }

    The above opens the file handle inside the sub. But because it uses a state variable, it keeps the filehandle open between calls.

    One object oriented way would be something like this:

    { package Logger; use Any::Mo; has handle => (is => 'ro'); sub log_it { my ($self, $message) = @_; my $timestamp = time; print {$self->handle} $timestamp . ": " . $message . "\n"; } } my $logger = Logger->new(handle => $fh); $logger->log_it("Hello"); $logger->log_it("World");

    A little overload magic can make things more concise...

    { package Logger; use Any::Mo; use overload '&{}' => sub { my $self = shift; return sub { $self->log_it(@_) }; }; has handle => (is => 'ro'); sub log_it { my ($self, $message) = @_; my $timestamp = time; print {$self->handle} $timestamp . ": " . $message . "\n"; } } my $logger = Logger->new(handle => $fh); $logger->("Hello"); $logger->("World");
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      Thanks for that. The OO method is very interesting (and educational) but using state within the subroutine is probably the best solution for me and does exactly what I was looking for.

Re: "Global" filehandle without using global variables
by BrowserUk (Patriarch) on Jun 18, 2012 at 21:03 UTC

    Why not have the subroutine write to STDERR.

    Then just redirect STDERR to wherever you want the logged information to go. Either at the top of the main program or via the command line when you run it.

    It's kinda what STDERR is for.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

Re: "Global" filehandle without using global variables
by fishmonger (Chaplain) on Jun 18, 2012 at 22:06 UTC
    IMO, the better approach would be to use Log::Log4perl http://search.cpan.org/~mschilli/Log-Log4perl-1.37/lib/Log/Log4perl.pm
Re: "Global" filehandle without using global variables
by ikegami (Patriarch) on Jun 18, 2012 at 21:15 UTC
    If you want a value to be seen everywhere, it is global by definition. Yet you say you don't want to use a global variable. That makes no sense.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://976898]
Approved by ikegami
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (3)
As of 2024-04-25 17:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found