8

我想让模块在运行时管理它们的日志记录,但不要让所有东西都引用一个单一的整体配置文件。当处理在不同权限下运行的进程时,我真的不想处理需要能够访问系统上每个日志的每个进程,而它们只写入其中的一个子集。

但是,我在 Log4perl 手册中没有找到太多关于如何在运行时从配置文件初始化附加附加程序的文档。http://metacpan.org/pod/Log::Log4perl::Appender引用了一个 add_appender 方法,但它适用于实例化的 appender 对象而不是 conf 文件。它也没有定义 logger 对象和 logger->appender 关系。

我尝试让每个包从它自己的 conf 中初始化,但这只会在每次初始化时破坏现有配置。我想做的是类似的事情:

my $foo = Foo->new() ## Checks Log::Log4perl::initialized(), sees that it
                     ## hasn't been initalized yet, inits Log4perl from foo.conf
my $bar = Bar->new() ## Checks Log::Log4perl::initialized(), sees that it
                     ## has been initalized. Adds appenders and loggers defined
                     ## in bar.conf into the initialized configuration

如何解析配置并将其添加到当前配置中?

编辑:使用包变量的问题在于,这只是各种类使用的 Moose 角色,几乎只是 Ether 在使用 Log::Log4perl 制作自记录模块中的答案的 MooseX::Role::Parameterized 版本。因此,我的记录器正在组合到使用它的库中,并且我没有每次使用它时都可以处理的全局变量。

尽管..

如果我在 MooseX::Role::Parameterized 角色块之外声明一个全局变量,是否每个使用该角色的类都使用相同的 conf 变量?

4

2 回答 2

5

虽然我希望避免这种情况,但如果我自己解析配置文件,我可以通过http://search.cpan.org/perldoc?Log::Log4perl中记录的 API 访问 perl 中的配置。即,

  ########################
  # Initialization section
  ########################
  use Log::Log4perl;
  use Log::Log4perl::Layout;
  use Log::Log4perl::Level;

     # Define a category logger
  my $log = Log::Log4perl->get_logger("Foo::Bar");

     # Define a layout
  my $layout = Log::Log4perl::Layout::PatternLayout->new("[%r] %F %L %m%n");

     # Define a file appender
  my $file_appender = Log::Log4perl::Appender->new(
                          "Log::Log4perl::Appender::File",
                          name      => "filelog",
                          filename  => "/tmp/my.log");

     # Define a stdout appender
  my $stdout_appender =  Log::Log4perl::Appender->new(
                          "Log::Log4perl::Appender::Screen",
                          name      => "screenlog",
                          stderr    => 0);

     # Have both appenders use the same layout (could be different)
  $stdout_appender->layout($layout);
  $file_appender->layout($layout);

  $log->add_appender($stdout_appender);
  $log->add_appender($file_appender);
  $log->level($INFO);

虽然另一种方法有效,但有太多警告让我无法舒适地使用它(天啊,我使用了这个库,为什么我的日志记录停止了?)——这对我的口味来说太令人惊讶了。

相反,我想通过查看如何使用由 ->init 委托的Log::Log4perl::Config::PropertyConfigurator来查看是否无法从配置文件进入 Log::Log4perl 状态需要解析配置文件时。如果我检查返回的数据结构,我可以逐个记录器和逐个附加程序比较初始化的更改,并适当地修改初始化状态,正确处理命名空间冲突等。

于 2011-01-25T15:09:59.813 回答
5

您可以记住已经加载了哪些配置文件(%log_configs下面代码中的哈希)。当新类到达时,您可以重新读取所有配置,将它们合并在一起并Log::Log4perl使用字符串引用参数再次初始化init

我通常更喜欢每个应用程序有一个日志配置,因为更容易维护和重新加载功能。

package Logger;
use Moose::Role;
use Log::Log4perl;

our %log_configs = ();

around BUILDARGS => sub {
    my $orig  = shift;
    my $class = shift;

    my $config_name = lc($class) . '.conf';

    # if the config is not integrated yet
    if(! defined $log_configs{$config_name}) {
        $log_configs{$config_name} = 1;

        # reload all configs including new one
        my $config_text = '';
        for my $file (sort keys %log_configs) {
            $config_text .= "\n" . do {
                local $/;   # slurp
                unless(open my $fh, "<", $file) {
                    warn "$file could not be open\n";
                    '';
                }
                else {
                    <$fh>
                }
            };
        }

        # refresh config
        Log::Log4perl::init(\$config_text);
    }

    return $class->$orig(@_);
};


package Foo;
use Moose;
with 'Logger';
use Log::Log4perl ':easy';

sub BUILD {
    ERROR 'Foo reporting';
}


package Bar;
use Moose;
with 'Logger';
use Log::Log4perl ':easy';

sub BUILD {
    INFO 'Bar reporting';
}


package main;

my $foo = Foo->new;
my $bar = Bar->new;
于 2011-01-21T09:57:51.070 回答