Изменить уровень логгера Log4perl в модуле из вызывающего скрипта

Итак, у меня есть модуль и вызывающий его скрипт, оба из которых реализуют Log4perl. Вот МВЕ:

test.plx:

#!/usr/bin/perl -w 
use strict;

my $logger;

BEGIN {
  eval { require Log::Log4perl; };

  if($@) {
    print "Log::Log4perl not installed - stubbing.\n";
    no strict qw(refs);
    *{__PACKAGE__."::$_"} = sub { } for qw(TRACE DEBUG INFO WARN ERROR FATAL);
  } else {
    no warnings;
    print "Log::Log4perl installed - life is good.\n";
    require Log::Log4perl::Level;
    Log::Log4perl::Level->import(__PACKAGE__);
    Log::Log4perl->import(qw(:easy));
    Log::Log4perl->easy_init({
      level => $main::INFO,
      layout => "[%r] %p %M %F line: %L> %m%n"});
    $logger = Log::Log4perl->get_logger();
  }
}

require "test.pm";

DEBUG "This is the test.plx DEBUG line";
INFO  "This is the test.plx INFO  line";
WARN  "This is the test.plx WARN  line";
ERROR "This is the test.plx ERROR line";

test::warning();

print "\nsetting logger level to ERROR\n\n";
$logger->level($ERROR);

DEBUG "This is the test.plx DEBUG line";
INFO  "This is the test.plx INFO  line";
WARN  "This is the test.plx WARN  line";
ERROR "This is the test.plx ERROR line";

test::warning();

exit;

тест.pm

package test;
use strict;

my $logger;

BEGIN {  
  eval { require Log::Log4perl; };

  if($@) {
      #print "Log::Log4perl not installed - stubbing.\n";
      no strict qw(refs);
      *{__PACKAGE__."::$_"} = sub { } for qw(TRACE DEBUG INFO WARN ERROR FATAL);
  } else {
      no warnings;
      #print "Log::Log4perl installed - life is good.\n";
      require Log::Log4perl::Level;
      Log::Log4perl::Level->import(__PACKAGE__);
      Log::Log4perl->import(qw(:easy get_logger :nowarn));
  }
}

INFO "This is the test.pm loading info";

sub warning {
  WARN "Danger!! Danger, Will Robinson!!"
}

return 1;

Что генерирует вывод:

Log::Log4perl installed - life is good.
[1] INFO main:: test.pm line: 22> This is the test.pm loading info
[1] INFO main:: test.plx line: 29> This is the test.plx INFO  line
[1] WARN main:: test.plx line: 30> This is the test.plx WARN  line
[1] ERROR main:: test.plx line: 31> This is the test.plx ERROR line
[1] WARN test::warning test.pm line: 25> Danger!! Danger, Will Robinson!!

setting logger level to ERROR

[2] ERROR main:: test.plx line: 40> This is the test.plx ERROR line
[2] WARN test::warning test.pm line: 25> Danger!! Danger, Will Robinson!!

Если я изменю строку

      level => $main::INFO,

to

      level => $main::ERROR,

Я получил:

Log::Log4perl installed - life is good.
[1] ERROR main:: test.plx line: 31> This is the test.plx ERROR line

setting logger level to ERROR

[2] ERROR main:: test.plx line: 40> This is the test.plx ERROR line

Как видите, вызов $logger-level($ERROR) в основном скрипте изменяет там уровень логирования (вызовы main INFO и WARN больше не выводятся), но уровень логера модуля не меняется при вызове.

Ясно, что модуль получает свой уровень регистратора из основного скрипта при загрузке, потому что вызов модуля WARN больше не печатается, если я изменю уровень на ERROR в блоке BEGIN. Но похоже, что он не поддерживает ссылку на один и тот же объект регистратора, поскольку изменения во время выполнения не распространяются.

(как) Могу ли я заставить изменение уровня регистратора динамически распространяться на модуль?

Спасибо.

P.S. Я бы предпочел использовать форму DEBUG ..., а не $logger->debug(...), просто для согласованности с другим кодом, который у нас есть, хотя я переключусь, если это единственный способ.

(Отредактировано, чтобы попытаться быть более ясным.)


person ipetrik    schedule 25.05.2017    source источник
comment
Я не совсем понимаю этот момент. но этот уровень не обновляется из основного скрипта Что вы имеете в виду, говоря, что не обновляется?   -  person Gerhard    schedule 25.05.2017
comment
Я попытался отредактировать свой вопрос, чтобы уточнить.   -  person ipetrik    schedule 25.05.2017
comment
Итак, модуль будет использовать STDERR, а не log4perl. Вам нужно привязать STDOUT к Log4perl. Опубликует ответ на метод.   -  person Gerhard    schedule 25.05.2017
comment
Мне также интересно, поможет ли объявление $logger с our вместо my. Возможно, кто-то сможет ответить на этот вопрос.   -  person Gerhard    schedule 25.05.2017


Ответы (1)


Так что вам нужно tie STDOUT для log4perl.

подробнее здесь

use Log::Log4perl qw(:easy);

sub TIEHANDLE {
    my $class = shift;
    bless [], $class;
}

sub PRINT {
    my $self = shift;
    $Log::Log4perl::caller_depth++;
    DEBUG @_;
    $Log::Log4perl::caller_depth--;
}
1;

и команда tie в основной программе для привязки STDERR к модулю trapper вместе с обычной инициализацией Log::Log4perl:

########################################
package main;
########################################
use Log::Log4perl qw(:easy);
Log::Log4perl->easy_init(
    {level  => $DEBUG, 
     file   => 'stdout',   # make sure not to use stderr here!
     layout => "%d %M: %m%n",
    });
tie *STDERR, "Trapper";
person Gerhard    schedule 25.05.2017
comment
Это не решает проблему. Это для случая, когда модуль выводит на STDOUT или STDERR, тогда как мой модуль генерирует вывод с WARN, а не print STDERR. - person ipetrik; 25.05.2017
comment
вы уже пробовали our $logger вместо my $logger в основном скрипте? - person Gerhard; 26.05.2017