Windows-Server-2003/tools/logmsg.pm

276 lines
7.2 KiB
Perl

#---------------------------------------------------------------------
package Logmsg;
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# Version:
# 2.00 07/20/2000 JeremyD: new version
# 2.01 12/27/2000 JeremyD: remove compatibility hooks
# 2.02 02/02/2001 JeremyD: add logfile_append function
#---------------------------------------------------------------------
use strict;
use vars qw(@ISA @EXPORT $VERSION $DEBUG);
use Carp;
use Exporter;
use Win32::Mutex;
use IO::File;
use File::Basename;
@ISA = qw(Exporter);
@EXPORT = qw(dbgmsg infomsg logmsg wrnmsg errmsg timemsg append_file);
$VERSION = '2.02';
sub timestamp() {
my ($sec,$min,$hour,$day,$mon,$year) = localtime;
$year %= 100;
$mon++;
return sprintf("%02d/%02d/%02d %02d:%02d:%02d",
$mon, $day, $year, $hour, $min, $sec);
}
sub scriptname() {
$ENV{SCRIPT_NAME} || basename($0);
}
sub sync_write {
my $data = shift;
my $filename = shift;
# validate data
return unless $data;
return unless $filename;
# get a global mutex for this file, this breaks down if
# relative paths are used, so don't use them
my $mutexname = $filename;
$mutexname =~ tr/A-Z\\/a-z\//;
$mutexname = "Global\\$mutexname";
my $mutex = Win32::Mutex->new(0, $mutexname);
if (defined $mutex) {
if ($mutex->wait(60000)) {
if (my $fh = IO::File->new($filename, "a")) {
$fh->print($data);
undef $fh;
} else {
carp "Failed to open $filename: $!";
}
$mutex->release;
} else {
carp "Timed out trying to get mutex for $filename, ".
"skipping";
}
} else {
carp "Failed to create mutex $mutexname for log access";
}
}
sub sync_write_multiple {
my $data = shift;
my @filenames = @_;
for my $filename (@filenames) {
sync_write($data, $filename);
}
}
sub dbgmsg {
my $message = shift;
return unless ($DEBUG or $ENV{DEBUG});
my $line = sprintf("(%s) [%s] %s\n",
scriptname(), timestamp(), $message);
print $line;
sync_write_multiple($line,
$ENV{LOGFILE},
$ENV{INTERLEAVE_LOG});
return $line;
}
sub infomsg {
my $message = shift;
my $line = sprintf("(%s) [%s] %s\n",
scriptname(), timestamp(), $message);
sync_write_multiple($line,
$ENV{LOGFILE},
$ENV{INTERLEAVE_LOG});
return $line;
}
sub logmsg {
my $message = shift;
my $line = sprintf("(%s) %s\n",
scriptname(), $message);
print $line;
sync_write_multiple($line,
$ENV{LOGFILE},
$ENV{INTERLEAVE_LOG});
return $line;
}
sub timemsg {
my $message = shift;
my $line = sprintf("(%s) [%s] %s\n",
scriptname(), timestamp(), $message);
print $line;
sync_write_multiple($line,
$ENV{LOGFILE},
$ENV{INTERLEAVE_LOG});
return $line;
}
sub wrnmsg {
my $message = shift;
my $line = sprintf("(%s) WARNING: %s\n",
scriptname(), $message);
print $line;
sync_write_multiple($line,
$ENV{LOGFILE},
$ENV{INTERLEAVE_LOG});
return $line;
}
sub errmsg {
my $message = shift;
my $line = sprintf("(%s) ERROR: %s\n",
scriptname(), $message);
print $line;
sync_write_multiple($line,
$ENV{ERRFILE},
$ENV{LOGFILE},
$ENV{INTERLEAVE_LOG});
$ENV{ERRORS}++;
return $line;
# maybe this should croak?
}
sub append_file {
my $filename = shift;
my $shortname = basename($filename);
my $content = sprintf("(%s) [%s] appending %s\n",
scriptname(), timestamp(), $filename);
open FILE, $filename or die $!;
while (<FILE>) {
$content .= "$shortname: $_";
}
close FILE;
sync_write_multiple($content,
$ENV{LOGFILE},
$ENV{INTERLEAVE_LOG});
return $filename;
}
1;
__END__
=head1 NAME
Logmsg - An interface for writing to log files
=head1 SYNOPSIS
use Logmsg;
logmsg "the text to be logged";
=head1 DESCRIPTION
The Logmsg module provides an interface for writing to log files.
The functions exported by Logmsg all take exactly one scalar, the
message to be logged and return the text that was logged.
The name of the running script is logged at the beginning of each
message. The script name is set to either the SCRIPT_NAME environment
variable or $0 if SCRIPT_NAME is not set.
If a filename is available but the file does not exist it will be
created.
If a logfile environment variable (LOGFILE, INTERLEAVE_LOG, ERRFILE)
is not set no attempt will be made to log to the file that it doesn't
specify. No error or warning is generated.
Any files that cannot be logged to (unable to obtain a lock within
timeout) are skipped printing a warning to STDERR.
=over 4
=item logmsg( $message )
Logs to STDOUT and the files specified by LOGFILE and INTERLEAVE_LOG.
=item errmsg( $message )
Logs to STDOUT and the files specified by ERRFILE, LOGFILE and
INTERLEAVE_LOG. The message text is preceeded by "ERROR: " and the
ERRORS environment variable is incremented.
=item wrnmsg( $message )
Logs to STDOUT and the files specified by LOGFILE and INTERLEAVE_LOG.
The message text is preceeded by "WARNING: ".
=item infomsg( $message )
Logs to files specified by LOGFILE and INTERLEAVE_LOG. infomsg is
similar to logmsg but can be used when output to STDOUT is not
desirable.
=item dbgmsg( $message )
Logs to STDOUT and the files specified by LOGFILE and INTERLEAVE_LOG
only if $Logmsg::DEBUG or the DEBUG environment variable is set.
=item timemsg( $message )
Logs to STDOUT and the files specified by LOGFILE and INTERLEAVE_LOG.
The message text is preceeded by a date/time stamp.
=item append_file( $filename )
The contents of $filename are appended to LOGFILE and INTERLEAVE_LOG.
The time and filename passed in are logged first followed by the
contents of the file. Each line is prefixed with the filename without
the path.
=back
=head1 ENVIRONMENT
The environment variable SCRIPT_NAME is used to determine the script
name to be logged with each message. The base filename of $0 is used
if this is not set.
If neither the DEBUG environment variable nor $Logfile::DEBUG is set
then dbgmsg returns immediately and does not log.
The environment variables LOGFILE, INTERLEAVE_LOG and ERRFILE specify
the filenames to be used for logging. Any or all of these may be left
unset without generating a warning or error.
The errmsg function increments the ERRORS environment variable each
time it is called.
=head1 NOTES
All file access is syncronized with a mutex based on the filename
given. If different relative paths are used for a single file then
locking protection will not work. In this case it is possible that
some data may be corrupted by simultaneous writes to the same file.
=head1 AUTHOR
Jeremy Devenport <JeremyD>
=head1 COPYRIGHT
Copyright (c) Microsoft Corporation. All rights reserved.
=cut