Re: Module Proposal: Log::Any

2007-09-08 Thread Jonathan Swartz
Ok, noted. The ::Abstract suffix does have some precedence in other  
CPAN modules, which was what ultimately convinced me. Log::Any seems  
to have turned a number of people off. I'm still open to other names.


On Sep 7, 2007, at 12:30 PM, Bill Ward wrote:


Abstract has two meanings, so I think that could be confusing.  I
think Log::Any is better.

On 9/7/07, Jonathan Swartz [EMAIL PROTECTED] wrote:

That is very true. That is why I'd volunteer to patch the major
modules in a backwards-compatible way.

Incidentally, this is also being commented on here:

 http://use.perl.org/~jonswar/journal/34366

and the name Log::Abstract was suggested, which I like a lot more, so
I'm leaning towards that now.

Thanks for your feedback,
Jon

On Sep 7, 2007, at 10:27 AM, Bill Ward wrote:


I like the concept of this, but I think to be successfull you need
buy-in from the various log package authors as well as more than  
a few

core module authors.  The name Log::Any sounds as good as any (har
har) but in this case, I think naming is the least of your worries.

On 9/6/07, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote:

This is a proposal for a minimal log-facilitation package that
provides modules with a standard log API while leaving the  
choice of

log framework and configuration to the application.

TOO MANY WAYS TO LOG

It seems as if every CPAN module has its own way of logging debug
information and error conditions. For example:

   * LWP - activate by use'ing LWP::Debug; outputs to STDERR
   * DBI - activate by calling DBI-trace(); outputs to STDERR or a
file
   * Rose::DB - activate by setting various $Debug package  
variables;

outputs to STDERR
   * Encode::* - activate by modifying various DEBUG subroutines to
return 1; outputs using warn()
   * Apache::* - activate by setting the Apache log level and
restarting; outputs to the Apache logs

In addition, many CPAN modules do not log anything at all, possibly
because they don't want to invent another logging mechanism or  
become

dependent on an existing one.

This situation is pretty much the opposite of what I want when
developing a large application. I want a single way to turn
logging on
and off, and to control where logs get sent, for all of the modules
I'm using.

This being Perl, there are many fine logging frameworks available:
Log::Log4perl, Log::Dispatch, Log::Handler, Log::Agent,  
Log::Trivial,
etc. So why do CPAN modules eschew the use of these and invent  
their

own mechanisms that are almost guaranteed to be less powerful?

   * The very existence of so many logging modules means that
there is
no one standard that a CPAN author would feel comfortable binding
their users to. As usual, TMTOWTDI is a double-edged sword.

   * A logging framework can be a significant dependency for a  
module

to have, easily dwarfing the size of the module itself. For small
modules that want to minimize dependencies, depending on Log4perl
(for
example) is a non-starter.

A COMMON LOG API

One thing to notice is that while the logging frameworks all
differ in
their configuration and activation API, and the set of features  
they

support, the API to log messages is generally quite simple. At its
core it consists of

   * A set of valid log levels, e.g. debug, info, warn, error,  
fatal


   * Methods to log a message at a particular level, e.g. $log-

debug()


   * Methods to determine if a particular level is activated, e.g.
$log-is_debug()

I expect most CPAN modules would happily stick to this API, and let
the application worry about configuring what's getting logged and
where it's going. Therefore...

PROPOSED MODULE: LOG::ANY

I propose a small module called Log::Any that provides this API,  
with

no dependencies and no logging implementation of its own. Log::Any
would be designed to be linked by the main application to an  
existing

logging framework.

A CPAN module would use it like this:

package Foo;
use Log::Any;
my $log = Log::Any-get_logger(category = __PACKAGE__);

$log-debug(a debug message)
if $log-is_debug();

$log-error(yikes!);

By default, methods like $log-debug would be no-ops, and methods
like
$log-is_debug() would return false.

As a convenient shorthand, you can use

package Foo;
use Log::Any qw($log);

$log-debug(a debug message)
if $log-is_debug();

where $log is a newly created logger object, initialized with the
package name of the caller and imported as a package-scoped  
variable.


An application that wished to activate logging would call Log::Any-

set_logger with a single argument: a subroutine that takes a log

category and returns a logger object implementing the standard
logging
API above. The log category is typically the class doing the  
logging,

and it may be ignored.

For example, to link with Log::Log4perl:

use Log::Any;
use Log::Log4perl;

Log::Log4perl-init(log.conf);
Log::Any-set_logger(sub { Log::Log4perl-get_logger(@_) });

To link with 

Re: Module Proposal: Log::Any

2007-09-08 Thread Bill Ward
On 9/8/07, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote:
  So I guess what I'm saying is that the final thing that would stop me from
  using Log::Any everywhere (meaning also in performance-critical code) is
  the overhead for the common (production) case of logging being entirely
  disabled.  How about providing all three methods of checking as part of the
  API?
 
  $log-debug(...)  if $log-is_debug();  # method
  $log-debug(...)  if Log::Any::is_debug();  # sub
  $log-debug(...)  if $Log::Any::Is_Debug;   # var

 Good point. The last two need to be tweaked so that we can assign
 different logging levels and/or destinations to different loggers -
 e.g. to turn on just Rose::DB debug logging without a flood from other
 modules. (See log4perl).

 How about this:

 use Log::Abstract qw($log $log_is_debug);

 $log-debug(...) if $log_is_debug;

 which translates to something like

 use Log::Abstract;
 my $log = Log::Abstract-get_logger
 (category = __PACKAGE__, is_debug_flag = \my $log_is_debug);

 $log-debug(...) if $log_is_debug;

 Now $log_is_debug, like $log, is class/category specific. Note that
 with either syntax, Log::Abstract is able to keep track of all the
 $log_is_debug variables and update them at runtime when something
 happens in the log framework to change log levels (e.g. log4perl
 reloading configuration). Assuming log level changes happen
 infrequently, this should yield good performance even when logging is
 turned on.

So you're saying if export() finds '$log' in its arg list, it will
create a $log variable in the calling package and initialize it to an
object?  I don't think I've ever seen that done, but I think I like
that idea...  though I'm inclined to think that passing \$LOG would be
a bit more perlish.