NAME

LogCarp - Error, log and debug streams, httpd style format

LogCarp redefines the STDERR stream and the defines the STDBUG and STDLOG streams in such a way that all messages are formatted similar to an HTTPD error log. Methods are defined for directing messages to the STDBUG and STDLOG streams. Each stream can be directed to its own location independent of the others.

SYNOPSIS

use LogCarp;

print "LogCarp version: ", LogCarp::VERSION;
DEBUGLEVEL 2;

croak "We're outta here!";
confess "It was my fault: $!";
carp "It was your fault!";
warn "I'm confused";
die "I'm dying.\n";


debug "Just for debugging: somevar=", $somevar, "\n";
logmsg "Just for logging: We're here.\n";
trace "detail=", $detail, "\n";

carpout \*ERRFILE;
debugout \*DEBUGFILE;
logmsgout \*LOGFILE;

is_STDOUT \*ERRFILE
is_STDERR \*LOGFILE
is_STDBUG \*LOGFILE
is_STDLOG \*ERRFILE

DESCRIPTION

LogCarp.pm is a Perl5 package defining methods for directing the existing STDERR stream as well as creating and directing two new messaging streams, STDBUG and STDLOG.

Their use was intended mainly for a CGI development environment, or where separate facilities for errors, logging, and debugging output are needed.

This is because CGI scripts have a nasty habit of leaving warning messages in the error logs that are neither time stamped nor fully identified. Tracking down the script that caused the error is a pain. This fixes that. Replace the usual

use Carp;

with

use LogCarp;

And the standard warn(), die(), croak(), confess() and carp() calls will automagically be replaced with methods that write out nicely time-, process-, program-, and stream-stamped messages to the STDERR, STDLOG, and STDBUG streams.

A new method to generate messages on the new STDLOG stream is logmsg(). Calls to logmsg() will write out the same nicely time-, process-, program-, and stream-stamped messages described above to both the STDLOG and the STDBUG streams.

Messages on multiple streams directed to the same location do not receive multiple copies.

New methods to generate messages on the new STDBUG stream are debug() and trace().

In addition, the process number (represented below as $$) and the stream on which the message appears is displayed to disambiguate multiple simultaneous executions as well as multiple streams directed to the same location.

For example:

[Mon Sep 15 09:04:55 1997] $$ test.pl ERR: I'm confused at test.pl line 3.
[Mon Sep 15 09:04:55 1997] $$ test.pl BUG: answer=42.
[Mon Sep 15 09:04:55 1997] $$ test.pl LOG: I did something.
[Mon Sep 15 09:04:55 1997] $$ test.pl ERR: Got a warning: Permission denied.
[Mon Sep 15 09:04:55 1997] $$ test.pl ERR: I'm dying.

REDIRECTING ERROR MESSAGES

By default, error messages are sent to STDERR. Most HTTPD servers direct STDERR to the server's error log. Some applications may wish to keep private error logs, distinct from the server's error log, or they may wish to direct error messages to STDOUT so that the browser will receive them (for debugging, not for public consumption).

The carpout() method is provided for this purpose.

For CGI programs that need to send something to the HTTPD server's real error log, the original STDERR stream has not been closed, it has been saved as _STDERR. The reason for this is twofold.

The first is that your CGI application might really need to write something to the server's error log, unrelated to your own error log. To do so, simply write directly to the _STDERR stream.

The second is that some servers, when dealing with CGI scripts, close their connection to the browser when the script closes either STDOUT or STDERR.

Saving the program's initial STDERR in _STDERR is used to prevent this from happening prematurely.

Do not manipulate the _STDERR filehandle in any other way other than writing to it. For CGI applications, the serverwarn() method formats and sends your message to the HTTPD error log (on the _STDERR stream).

REDIRECTING LOG MESSAGES

A new stream, STDLOG, has been defined for log messages. By default, STDLOG is routed to STDERR. Most HTTPD servers direct STDERR (and thus the default STDLOG also) to the server's error log. Some applications may wish to keep private activity logs, distinct from the server's log, or they may wish to direct log messages to STDOUT so that the browser will receive them (for debugging, not for public consumption).

The logmsgout() method is provided for this purpose.

REDIRECTING DEBUG MESSAGES

A new stream, STDBUG, has been defined for debugging messages. Since this stream is for producing debugging output, the default STDBUG is routed to STDOUT. Some applications may wish to keep private debug logs, distinct from the application output, or CGI applications may wish to leave debug messages directed to STDOUT so that the browser will receive them (only when debugging). Your program may also control the output by manipulating DEBUGLEVEL in the application.

The debugout() method is provided for this purpose.

REDIRECTING MESSAGES IN GENERAL

Each of these methods, carpout(), logmsgout(), and debugout(), requires one argument, which should be a reference to an open filehandle for writing. It should be called in a BEGIN block at the top of the application so that compiler errors will be caught. Example:

BEGIN {
use LogCarp;
open \*LOG, ">>/usr/local/cgi-logs/mycgi-log"
    or die "Unable to open mycgi-log: $!\n";
carpout \*LOG;
}

NOTE: carpout() does handle file locking on systems that support flock so multiple simultaneous CGIs are not an issue.

If you want to send errors to the browser, give carpout() a reference to STDOUT:

BEGIN {
  use LogCarp;
  carpout \*STDOUT;
}

If you do this, be sure to send a Content-Type header immediately -- perhaps even within the BEGIN block -- to prevent server errors.

You can pass filehandles to carpout() in a variety of ways. The "correct" way according to Tom Christiansen is to pass a reference to a filehandle GLOB:

carpout \*LOG;

This looks weird to mere mortals however, so the following syntaxes are accepted as well:

carpout(LOG);
carpout(\LOG);
carpout('LOG');
carpout(\'LOG');
carpout(main::LOG);
carpout('main::LOG');
carpout(\'main::LOG');

... and so on

Use of carpout() is not great for performance, so it is recommended for debugging purposes or for moderate-use applications. A future version of this module may delay redirecting STDERR until one of the LogCarp methods is called to prevent the performance hit.

EXPORTED PACKAGE METHODS

The following methods are for generating a message on the respective stream:

The STDERR stream: warn() and die()
The STDLOG stream: logmsg()
The STDBUG stream: debug() and trace()

The following methods are for generating a message on the respective stream, but will indicate the message location from the caller's perspective. See the standard Carp.pm module for details.

The STDERR stream: carp(), croak() and confess()

The following methods are for manipulating the respective stream:

The STDERR stream: carpout()
The STDLOG stream: logmsgout()
The STDBUG stream: debugout()

The following methods are for manipulating the amount (or level) of output filtering on the respective stream:

The STDBUG stream: DEBUGLEVEL()
The STDLOG stream: LOGLEVEL()

INTERNAL PACKAGE METHODS

The following methods are for comparing a filehandle to the respective stream:

is_STDOUT()
is_STDERR()
is_STDBUG()
is_STDLOG()

Each is explained in its own section below.

EXPORTED PACKAGE VARIABLES

No variables are exported into the caller's namespace.

INTERNAL PACKAGE VARIABLES

$DEBUGLEVEL

A number indicating the level of debugging output that is to occur. At each increase in level, additional debugging output is allowed.

Currently three levels are defined: 0 - No messages are output on the STDBUG stream. 1 - debug() messages are output on the STDBUG stream. 2 - debug() and trace() messages are output on the STDBUG stream.

It is recommended to use the DEBUGLEVEL method to get/set this value.

$LOGLEVEL

A number indicating the level of logging output that is to occur. At each increase in level, additional logging output is allowed.

Currently two levels are defined: 0 - No messages are output on the STDLOG stream. 1 - logmsg() messages are output on the STDLOG stream.

It is recommended to use the LOGLEVEL method to get/set this value.

RETURN VALUE

The value returned by executing the package is 1 (or true).

ENVIRONMENT

FILES

ERRORS

WARNINGS

carpout(), debugout(), and logmsgout() do not handle file locking for you at this point.

DIAGNOSTICS

BUGS

Check out what's left in the TODO file.

RESTRICTIONS

CPAN DEPENDENCIES

LOCAL DEPENDENCIES

SEE ALSO

Carp, CGI::Carp

NOTES

ACKNOWLEDGEMENTS

Based heavily on CGI::Carp by Lincoln D. Stein (lstein@genome.wi.mit.edu).

AUTHOR(S)

mak - Michael King (mike808@mo.net)

HISTORY

LogCarp.pm
v1.01 09/15/97 09:04:00 mak
v1.02 01/04/98 19:03:25 mak
v1.03 01/04/98 19:03:25 mak

MODIFICATIONS

COPYRIGHT

Copyright (C) 1997,1998 Michael King (mike808@mo.net)
Fenton, MO USA.

This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

AVAILABILITY

The latest version of this module is likely to be available from:

http://walden.mo.net/~mike808/LogCarp

The best place to discuss this code is via email with the author.

PACKAGE PUBLIC METHODS

DEBUGLEVEL $LEVEL

DEBUGLEVEL is a normal get/set method.

When the scalar argument LEVEL is present, the DEBUGLEVEL will be set to LEVEL. LEVEL is expected to be numeric, with the following case-insensitive character-valued translations:

NO,  FALSE, and OFF all equate to a value of 0 (ZERO).
YES, TRUE,  and ON  all equate to a value of 1 (ONE).
TRACE or TRACING equate to a value of 2 (TWO).

Values in scientific notation equate to their numeric equivalent.

NOTE:

All other character values of LEVEL equate to 0 (ZERO). This
will have the effect of turning off debug output.

After this translation to a numeric value is performed, the DEBUGLEVEL is set to LEVEL.

Whenever the DEBUGLEVEL is set to a non-zero value (i.e. ON or TRACE), the LOGLEVEL will be also set to 1 (ONE).

The value of DEBUGLEVEL is then returned to the caller, whether or not LEVEL is present.

LOGLEVEL $LEVEL

LOGLEVEL is a normal get/set method.

When the scalar argument LEVEL is present, the LOGLEVEL will be set to LEVEL. LEVEL is expected to be numeric, with the following case-insensitive character-valued translations:

NO,  FALSE, and OFF all equate to a value of 0 (ZERO).
YES, TRUE,  and ON  all equate to a value of 1 (ONE).

Values in scientific notation equate to their numeric equivalent.

NOTE:

All other character values of LEVEL equate to 0 (ZERO). This
will have the effect of turning off log output.

After this translation to a numeric value is performed, the LOGLEVEL is set to LEVEL.

The value of LOGLEVEL is then returned to the caller, whether or not LEVEL is present.

warn @message

This method is a replacement for Perl's builtin warn(). The message is sent to the STDERR, STDLOG, and STDBUG streams.

die @message

This method is a replacement for Perl's builtin die(). The message is sent to the STDERR, STDLOG, and STDBUG streams.

carp @message

This method is a replacement for Carp::carp(). The message is sent to the STDERR, STDLOG, and STDBUG streams.

croak @message

This method is a replacement for Carp::croak(). The message is sent to the STDERR, STDLOG, and STDBUG streams.

confess @message

This method is a replacement for Carp::confess(). The message is sent to the STDERR, STDLOG, and STDBUG streams.

logmsg @message

This method operates similarly to the warn() method. The message is sent to the STDLOG and STDBUG streams.

debug @message

This method operates similarly to the warn() method. The message is sent to the STDBUG stream when DEBUGLEVEL > 0.

trace @message

This method operates similarly to the warn() method. The message is sent to the STDBUG stream when DEBUGLEVEL is greater than one.

carpout FILEHANDLE

A method to redirect the STDERR stream to the given FILEHANDLE. It accepts FILEHANDLE as a reference or a string.

See the section on REDIRECTING ERROR MESSAGES and the section on REDIRECTING MESSAGES IN GENERAL.

logmsgout FILEHANDLE

A method to redirect the STDLOG stream to the given FILEHANDLE. It accepts FILEHANDLE as a reference or a string.

See the section on REDIRECTING ERROR MESSAGES and the section on REDIRECTING MESSAGES IN GENERAL.

debugout FILEHANDLE

A method to redirect the STDBUG stream to the given FILEHANDLE. It accepts FILEHANDLE as a reference or a string.

See the section on REDIRECTING ERROR MESSAGES and the section on REDIRECTING MESSAGES IN GENERAL.

is_STDOUT FILEHANDLE

This method compares FILEHANDLE with the STDOUT stream and returns the boolean result.

This method is not exported by default.

is_STDERR FILEHANDLE

This method compares FILEHANDLE with the STDERR stream and returns the boolean result.

This method is not exported by default.

is_STDBUG FILEHANDLE

This method compares FILEHANDLE with the STDBUG stream and returns the boolean result.

This method is not exported by default.

is_STDLOG FILEHANDLE

This method compares FILEHANDLE with the STDLOG stream and returns the boolean result.

This method is not exported by default.

PRIVATE METHODS

realwarn @MESSAGE

This private method encapsulates Perl's underlying warn() method, actually producing the message on the STDERR stream. Locking is performed to ensure exclusive access while appending.

This method is not exportable.

realdie @MESSAGE

This private method encapsulates Perl's underlying die() method, actually producing the message on the STDERR stream and then terminating execution. Locking is performed to ensure exclusive access while appending.

This method is not exportable.

reallog @MESSAGE

This private method synthesizes an underlying logmsg() method, actually producing the message on the STDLOG stream. Locking is performed to ensure exclusive access while appending. The message will only be sent when LOGLEVEL is greater than zero.

This method is not exportable.

realbug @message

This private method synthesizes an underlying debug() method, actually producing the message on the STDBUG stream. Locking is performed to ensure exclusive access while appending. The message will only be sent when DEBUGLEVEL is greater than zero.

This method is not exportable.

id $level

This private method returns the file, line, and basename of the currently executing function.

This method is not exportable.

stamp $stream_id

A private method to construct a normalized timestamp prefix for a message.

This method is not exportable.

streams_are_equal FILEHANDLE, FILEHANDLE

This private method compares two FILEHANDLE streams to each other and returns the boolean result.

This method is not exportable.

Note: This function is probably not portable to non-Unix-based operating systems (i.e. NT, VMS, etc.).

LOCK_SH, LOCK_EX, LOCK_NB, LOCK_UN

Some private methods encapsulating the implementation-defined values for the OPERATION parameter of the Perl builtin flock(), based upon the operating system flock(2) function. See the manual page for flock(2) for your system-specific values.

The as-defined-here values for the flock() OPERATION parameter are:

LOCK_SH = 1 - Shared lock
LOCK_EX = 2 - Exclusive lock
LOCK_NB = 4 - Non-blocking lock
LOCK_UN = 8 - Unlock

NOTE: YMMV.

SEEK_BOF, SEEK_CUR, SEEK_EOF

Some private methods encapsulating the implementation-defined values for the WHENCE parameter of the Perl builtin seek(), based upon the operating system flock(2) function. See the manual page for flock(2) for your system-specific values.

The as-defined-here values for the seek() WHENCE parameter are:

SEEK_BOF = 0 - Beginning of the file
SEEK_CUR = 1 - Current location in the file
SEEK_BOF = 2 - End of the file

NOTE: YMMV.

lock FILEHANDLE

A private method that uses Perl's builtin flock() and seek() to obtain an exclusive lock on the stream specified by FILEHANDLE. A lock is only attempted on actual files that are writeable.

This method is not exportable.

unlock FILEHANDLE

A private method that uses Perl's builtin flock() to release any exclusive lock on the stream specified by FILEHANDLE. An unlock is only attempted on actual files that are writeable.

This method is not exportable.