8

有没有办法使用Log::Log4perl制作一个智能的自记录模块,即使在没有调用脚本未初始化 Log4perl 的情况下也可以将其操作记录到文件中?据我从文档中可以看出,使用 Log4perl 的唯一方法是在运行脚本中从配置中对其进行初始化,然后实现 Log4perl 的模块根据调用者的 Log4perl 配置调用自己的日志。

相反,我希望模块为 Log4perl 提供默认的初始化配置。这将为模块的类别提供默认的文件附加程序。然后,如果需要,我可以通过在调用者中使用不同的配置初始化 Log4perl 来覆盖此行为,并且希望一切都能正常工作。

这种防御性日志记录行为是否可能,或者我是否需要在每个调用我想要记录的模块的 .pl 脚本中依赖初始化 Log4perl?

4

2 回答 2

7

我在Moose中以自定义 Log 角色执行此操作(删除了不相关的复杂代码):

package MyApp::Role::Log;

use Moose::Role;
use Log::Log4perl;

my @methods = qw(
    log trace debug info warn error fatal
    is_trace is_debug is_info is_warn is_error is_fatal
    logexit logwarn error_warn logdie error_die
    logcarp logcluck logcroak logconfess
);

has _logger => (
    is => 'ro',
    isa => 'Log::Log4perl::Logger',
    lazy_build => 1,
    handles => \@methods,
);

around $_ => sub {
    my $orig = shift;
    my $this = shift;

    # one level for this method itself
    # two levels for Class:;MOP::Method::Wrapped (the "around" wrapper)
    # one level for Moose::Meta::Method::Delegation (the "handles" wrapper)
    local $Log::Log4perl::caller_depth;
    $Log::Log4perl::caller_depth += 4;

    my $return = $this->$orig(@_);

    $Log::Log4perl::caller_depth -= 4;
    return $return;

} foreach @methods;

method _build__logger => sub {
    my $this = shift;

    my $loggerName = ref($this);
    Log::Log4perl->easy_init() if not Log::Log4perl::initialized();
    return Log::Log4perl->get_logger($loggerName)
};

如您所见,日志对象是自初始化的——如果Log::Log4perl->init没有被调用,easy_init则被调用。您可以轻松地修改它以允许每个模块自定义其记录器——我使用可选角色参数这样做,并ref($this)作为默认后备。

PS。您可能还想查看MooseX::Log::Log4perl,这是我在使用上述记录器角色之前开始的地方。有一天,当我解决这个问题时,我会向那个 MX 模块提交一些急需的补丁,以整合我添加的一些功能。

于 2010-06-10T21:45:49.120 回答
1

简短的回答是调用 Log::Log4perl::initialized(); 在某些时候,如果它是错误的,请设置一些默认日志记录。

棘手的部分是“某个点”。

您不能在 BEGIN {} 中执行此操作,因为即使您创建了不必要的文件,主脚本也会阻碍您的初始化。您不想在每次调用 get_logger() 之前执行此操作,因为这很浪费。所以你应该在模块的初始化过程中这样做,比如 sub new 或 sub init。

于 2010-11-05T18:08:30.727 回答