APPLICATION API (WITH ADAPTERS)

# Log::Log4perl
Log::Log4perl::init('/etc/log4perl.conf');
Log::Any->set_adapter('Log::Log4perl');

# Log::Dispatch
my $dispatcher = Log::Dispatch->new();
$dispatcher->add(Log::Dispatch::File->new(name => 'foo', min_level => 'info', filename => 'foo.log', mode => 'append', callbacks => sub { $_[0] . "\n" }));
Log::Any->set_adapter('Log::Dispatch', dispatcher => $dispatcher);

# Log::Dispatch::Config
Log::Dispatch::Config->configure('/path/to/log.conf');
my $dispatcher = Log::Dispatch::Config->instance;
Log::Any->set_adapter('Log::Dispatch', dispatcher => $dispatcher);

# Log::Tiny
my $log = Log::Tiny->new('myapp.log');
Log::Any->set_adapter('Log::Tiny', log => $log);

# My class
Log::Any->set_adapter('+My::Log::Any::Adapter', foo => 17);

ADAPTERS

Each log class should have an adapter.
* Constructor creates a blessed hash from the parameters, then calls init() which may optionally be overriden in adapter. Constructor should not be overriden - in particular it is important that it returns a hash, not some other fancy representation of an object.
* Adapter must implement the standard logging and detection methods (based on Log::Dispatch).
* Adapter may implement init().

STANDARD LOGGER API?

The logger API that I imagined being so standard is perhaps not that standard.

Log::Log4perl:
  Levels: debug, info, warn, error, fatal
  Log method: $log->debug("msg");
  Detect method: $log->is_debug

Log::Dispatch:
  Levels: debug, info, notice, warning, error, critical, alert, emergency (like syslog but expanded to full words)
  Log method: $log->debug("msg");
  Detect method: $log->is_debug

Log::Dispatch::Config:
  Same as Log::Dispatch, just a different configuration

Log::Fine:
  Levels: EMER, ALRT, CRIT, ERR, WARN, NOTI, INFO, DEBG (like syslog but shortened to four letters)
  Log method: $log->log(DEBUG, "msg");
  Detect method: $handle->isLoggable(DEBUG);

Log::Tiny:
  Levels: Whatever you want them to be - any unreserved method
  Log method: $log->whatever("msg");
  Detect method: none

Log::Agent:
  Levels: EMERG, ALERT, CRIT, ERROR, WARN, NOTICE, INFO (like syslog)
  Log method: logerr(msg), logwarn(msg), logsay(msg), logtrc(level, msg), logdbg(level, msg) - holy crap this is complex
  Detect method: none

Ignore these, they are too far off the mark and/or unused
Log::Simple
Log::Simplest

TRACKING OBJECTS

The plan to track each imported object, and update it whenever the underlying logger changes, is clever but may be flawed in practice. Most notably, the user cannot copy the logger, place it into another object, etc., without losing the update property. It seems preferable to have each logger be a proxy object that forwards all methods to the real object (which may then change at will).

That would have to hold true for $log_is_debug and family as well. Is there any point to these, given that at the very least, they'd have to be tied scalars?

Maybe we should start it out as a tied scalar, and if we can improve it later, so be it.

MODULE API

use Log::Any qw($log);

my $log = Log::Any->get_logger();   # auto computes category from class
my $log = Log::Any->get_logger(category => 'Foo');
$log->debug('...') if ($log->is_debug);

(later)
use Log::Any qw($log $log_is_debug);
$log->debug('...') if ($$log_is_debug);  # $log_is_debug updates dynamically

APPLICATION API

# If we want to be clever
Log::Any->set_logger('log4perl');
Log::Any->set_logger(['DispatchClass', 'Level', DispatchArgs...]);
Log::Any->set_logger($blessed_logger_object);
Log::Any->set_logger(sub { my $category = shift; ...; return $logger });  # good for smart matching

# If we want to be safe
Log::Any->set_logger(log4perl => 1);
Log::Any->set_logger(dispatch => ['DispatchClass', 'Level', DispatchArgs...]);
Log::Any->set_logger(object => $blessed_logger_object);
Log::Any->set_logger(factory => sub { my $category = shift; ...; return $logger });

# Special case for log4perl - shorthand for
#   Log::Any->set_logger(sub { Log::Log4perl->get_logger(shift) });

# Example using Log::Dispatch - ugh
# Maybe we can at least convince Rolsky to
# * add the std logging api on Log::Dispatch::Output base class, so we can ditch the first line
# * eliminate the name as a requirement
my $logger = Log::Dispatch->new();
$logger->add(Log::Dispatch::File->new(name => 'foo', min_level => 'info', filename => 'foo.log', mode => 'append'));
Log::Any->set_logger($logger);

# So then some better examples:
Log::Any->set_logger(Log::Dispatch::File->new(min_level => 'info', filename => 'foo.log', mode => 'append'));
Log::Any->set_logger(Log::Dispatch::Scalar->new(min_level => 'info', scalar => \$foo));
Log::Any->set_logger(Log::Dispatch::Screen->new(min_level => 'info');

# And if we implement a shortcut for dispatch...
Log::Any->set_logger(['info', 'File', filename => 'foo.log', mode => 'append']);
Log::Any->set_logger(['info', 'Scalar', scalar => \$foo]);
Log::Any->set_logger(['info', 'Screen']);

# Send Server::Control* logs to screen
Log::Any->set_logger({ qr/^Server::Control/ => ['Screen'] });

LEVELS



QUESTIONS FOR ROLSKY

* Can we add the std logging api on Log::Dispatch::Output base class, so we can ditch the first line?
* Why are so many things documented repeatedly throughout the Log::Dispatch classes, e.g. min_level?
* Can we make the name optional?
