preaction / Log-Any

Simple, fast Perl logging API compatible with any logging system
Other
13 stars 19 forks source link

Can't locate object method "more_logging" via package "Log::Any::Proxy" #81

Open XSven opened 3 years ago

XSven commented 3 years ago

I have an application

...
use Log::Any qw($logger);
use Log::Any::Adapter;
use Log::Log4perl;
...
Log::Log4perl->init_once(first { -f } map { File::Spec->catfile($_, 'log4perl.properties') } @INC);
Log::Any::Adapter->set('Log::Log4perl');
...
$logger->more_logging(1);

I known that Log::Anys standard log production API doesn't know anything about the Log::Log4perl specific method more_logging(), but I thought that unknown method calls are delegated to the chosen adapter that is Log::Log4perl in my case?!

preaction commented 3 years ago

There's no AUTOLOAD in Log::Any::Proxy, so no, it won't delegate unknown methods to the adapter inside. The proxy object itself shouldn't have (or appear to have) methods that don't exist on all adapters. We could implement something like it, perhaps. What are you trying to do with that method? Temporarily increase logging for a scope?

XSven commented 3 years ago

My application has a Getopt::Long based command line interface with a "v"erbosity option that should increase the log level from INFO to DEBUG (-v) to TRACE (-v -v). Apart from this specific use case my question is a general one because we have used Log::Log4perl directly before and we are no going to switch over to Log::Any. Some of the methods like $logger->logdie(...) we could simply avoid using die($logger->fatal(...)) but others like more_logging() cannot be bypassed, right?!

preaction commented 3 years ago

Not at the moment. I could add support for that to the Adaptor (Log::Any::Adaptor::Log4perl), but it wouldn't make much sense on the Proxy. I think, though, what you want might be more like:

GetOptions( \my %opt, 'verbose+' );
Log::Log4perl::init('/etc/log4perl.conf');
Log::Log4perl->get_logger("")->more_logging( $opt{verbose} ); # https://metacpan.org/pod/Log::Log4perl#Shortcuts says `->get_logger("")` gets the root logger
Log::Any::Adaptor->set_adaptor( 'Log::Log4perl' ); # XXX is this right? Should it be 'Log4perl' instead? If so, the docs for the adaptor are wrong :(

Log::Any can't prevent all interfacing with the adaptor class. It tries to make library code not have to worry about which adaptor the consuming system is using. Your main script that initializes everything may still need to call Log::Log4perl methods (like init(...)) to get things started.

Adding more_logging support to the adaptor could look like:

Log::Any::Adaptor->set_adaptor( 'Log::Log4perl' => { more_logging => $opt{verbose} } );

But, there might be some other better way of adding that support... Let me know what you'd like to try!

XSven commented 3 years ago
XSven commented 3 years ago

I have thought about this challenge again. For me Log::Any in perl is similar to slf4j in Java. After reading this

https://prateep.info/2015/12/12/dynamically-change-log-level-in-slf4j-log4j-with-standalone-java-class/

I am convinced that this issue can be closed!

XSven commented 3 years ago

I am reopening this issue because I have understood it better and got a new perspective on it:

package Foo;

use Log::Any::Adapter  ();
use Log::Log4perl      qw(:easy);
Log::Log4perl->easy_init(
  {
    category => __PACKAGE__,
    level    => $DEBUG,
    file     => 'STDERR',
    layout   => '%d{HH:mm:ss} %-5p [%M{3}, %L] - %m%n'
  }
);
Log::Any::Adapter->set('Log::Log4perl');

my $logger = Log::Any->get_logger(category => __PACKAGE__);

$logger->trace('not logged');
$logger->adapter->{logger}->more_logging(1);
$logger->trace('logged');

Why is the real logger not a public attribute of either Log::Any::Proxy ($logger->get_real_logger) or Log::Any::Adapter::Base ($logger->adapter->get_real_logger)?

P.S. Maybe the method get_real_logger should be named get_log_consumer to indicate a certain flexibility.