Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
XSven opened this issue Nov 6, 2020 · 6 comments
Open

Comments

@XSven
Copy link
Contributor

XSven commented Nov 6, 2020

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
Copy link
Owner

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
Copy link
Contributor Author

XSven commented Nov 6, 2020

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
Copy link
Owner

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
Copy link
Contributor Author

XSven commented Nov 9, 2020

  • Log::Any::Adapter->set('Log::Log4perl') is completely ok. No change of the documentation is needed. Please have a look at Log::Any::Manager::_get_adapter_class().

  • I want to use Log::Any to create my $logger. I see no need to call the adapters Log::Log4perl::get_logger() method.

  • I do not use the Getopt::Long incremental option approach. This is my option specification
    v => sub { $logger->more_logging(1); return; }.

  • If you can make Log::Any::Adapter::Log4perl to delegate the call $logger->more_logging() to the behaviour already defined by Log::Log4perl I am fine with that. I do not like any solution that reimplements methods again.

  • I do not understand your suggestion
    Log::Any::Adapter->set( 'Log::Log4perl' => { more_logging => $opt{verbose} } );
    It should be sufficient to name the adapter. Why should I specify the method that the adapter should already know about again?!

@XSven
Copy link
Contributor Author

XSven commented Nov 12, 2020

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 XSven closed this as completed Nov 12, 2020
@XSven
Copy link
Contributor Author

XSven commented Jul 28, 2021

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');
  • $logger is an instance of Log::Any::Proxy.
  • $logger->adapter is an instance of Log::Any::Adapter::Log4perl.
  • $logger->adapter->{logger} is an instance of Log::Log4perl::Logger. I will name this proxied instance the real logger.

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.

@XSven XSven reopened this Jul 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants