use Time::Local; # ============================================== # # global state-of-the-module variables # # ============================================== # my $_logstarted=0; my $LOG; undef $LOG; my @_logstack=(); # ============================================== # # log 'stack' management # # ---------------------------------------------- # # Enables inclusion in logged messages of the # # name of the subroutine logging a particular # # message for diagnostics and debugging. # # ---------------------------------------------- # # usage: # # logstack('push', ) # # logstack('pop') # # logstack('clear') # # logstack() # # ---------------------------------------------- # # logstack('push', $caller), logstack('pop') # # and logstack() return the callstack as a # # string of colon-separated fields; # # logstack('clear') returns numeric 1. # # ---------------------------------------------- # # To work correctly, requires subroutines # # to call logstack('push', $callername) on # # entry and logstack('pop') on return # # ---------------------------------------------- # # EXPORTED # # ============================================== # # examples: # 16 Apr 2006 16:05:50 myfiles: process: catalog: found 35 file(s) # 02 Feb 2006 10:48:02 myfiles: process: archive: error moving todaysfiles.html: No such file or directory sub logstack { return if !$_logstarted; my $op=@_ ? shift : ""; @_logstack=(), return 1 if ($op eq 'clear'); push @_logstack, @_ if $op eq 'push'; pop @_logstack if $op eq 'pop'; return join (': ', @_logstack); } # ============================================== # # logstart -- initializes log service # # ---------------------------------------------- # # usage: # # logstart( # # directory => $logdirectory, # # filename => $logfilename, # # caller => $callername, # # path => $logpath, # # error => \$errmsg) # # # # The logfile must be specified with either # # or [, ], # # with used if both are passed. # # # # The logfile is the only required parameter. # # ---------------------------------------------- # # Returns numeric 1 or 0, respectively, # # on success or failure # # # # On error or failure, logstart() returns # # an error message via the optional error # # parameter. # # ---------------------------------------------- # # EXPORTED # # ============================================== # sub logstart { return if $_logstarted || (@_<2); my $logdir=""; my $logfile=""; my $msg=""; undef $msg; my $caller=""; my $logpath=""; my $error; undef $error; my %argh=(); # collect and validate function args while (@_) { my $key=shift; my $value=shift; $argh{$key}=$value; } $caller=$argh{caller} if exists($argh{caller}); $msg=$argh{message} if exists($argh{message}); $error=$argh{error} if exists($argh{error}); if (exists $argh{path}) { $logpath=$argh{path}; } elsif ((exists $argh{directory}) && (exists $argh{filename})) { $argh{directory}=~s/\\$//; $logdir=$argh{directory}; $logfile=$argh{filename}; $logpath=$logdir."\\".$logfile; } else { $$error="missing logfile directory and filename" if $error; return 0; } # create log subdirectory if necessary if (!(-e $logdir) && !(mkdir $logdir)) { $$error="couldn't create log directory ".$logdir.": ".$! if $error; return 0; } # open logfile if (!(open($LOG, "+>>:utf8", $logpath))) { $$error="error opening logfile ".$logpath.": ".$! if $error; return 0; } $LOG->autoflush(1); print $LOG "\n"; $_logstarted=1; logstack('clear'); logstack('push', $caller) if $caller; logstack('push', 'logstart'); logmsg($msg) if $msg; logstack('pop'); logstack('pop') if $caller; return 1; } # ============================================== # # logstop -- shuts down log service # # ---------------------------------------------- # # usage: # # logstop() # # logstop($lastwords) # # # # The optional parameter $lastwords is a # # message to log before closing the logfile # # ---------------------------------------------- # # EXPORTED # # ============================================== # sub logstop { return if !$_logstarted; my $msg=shift; $msg and logmsg($msg); close $LOG; undef $LOG; $_logstarted=0; logstack('clear'); return; } # ============================================== # # logstr -- composes formatted string of form # # where # # date & time is of form # #
:: # # ---------------------------------------------- # # usage: # # logstr() # # logstr($msg) # # ---------------------------------------------- # # logstr() with no parameters returns # # a formatted timestamp only # # ---------------------------------------------- # # EXPORTED # # ============================================== # sub logstr { my $msg=shift; $msg=$msg?$msg:""; my ($sec, $min, $hour, $day, $month, $year, $weekday, $yday, $dst)=localtime(time); $year+=1900; my $timestamp=sprintf("%02d", $day)." ".$mmm[$month]." ". $year." ".sprintf("%02d", $hour).":".sprintf("%02d", $min). ":".sprintf("%02d", $sec); $msg=$timestamp."\t".join (': ', @_logstack).": ".$msg; return $msg } # ============================================== # # logmsg -- writes formatted string of form # # # # to the logfile specified when the log # # service was started with logstart() # # # # The content of is # # managed using logstack() # # ---------------------------------------------- # # usage: # # logmsg($msg) # # ---------------------------------------------- # # Does nothing if $msg is missing or the log # # service wasn't previously started with # # logstart() # # ---------------------------------------------- # # EXPORTED # # ============================================== # sub logmsg { return if !$_logstarted || !(defined $LOG) || !@_; my $msg=logstr(shift()); print $LOG $msg."\n"; # print $msg."\n"; # optionally print duplicate message to STDOUT return $msg; }