Log4perl:如何在运行时动态加载附加程序?

发布于 2024-10-12 07:24:46 字数 1230 浏览 4 评论 0 原文

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

但是,我在 Log4perl 手册中没有找到太多关于如何在运行时从配置文件初始化附加附加程序的文档。 http://metacpan.org/pod/Log::Log4perl::Appender 引用了 add_appender 方法,但该方法适用于实例化的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 角色块之外声明一个全局变量,那么使用该角色的每个类是否都会使用相同的 conf 变量?

I'd like to have modules managing their logging at runtime, but without having everything referring to a single monolithic config file. When dealing with processes running under different permissions, I really don't want to deal with each process needing to be able to access every log on the system when they're only writing to a subset of them.

However, I'm not finding much documentation in the Log4perl manual on how to initialize additional appenders from a configuration file at runtime. http://metacpan.org/pod/Log::Log4perl::Appender references an add_appender method, but that works on instantiated appender objects instead of conf files. It also doesn't define the logger objects and the logger->appender relations.

I tried having each package init from its own conf, but that simply clobbers the existing config each time it's initalized. What I'd like to do is something along the lines of:

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

How can I parse and add the configuration into the current config?

Edit: Probalem with using a package variable is that this is just a Moose role being consumed by various classes, pretty much just a MooseX::Role::Parameterized version of Ether's answer in Making self-logging modules with Log::Log4perl. Thus, my logger is getting composed into the library consuming it, and I don't have a global variable I can work on each time I use it.

Though..

If I declare a global variable outside of the MooseX::Role::Parameterized role block, would each and every class that consumes the role be using that same conf variable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无人接听 2024-10-19 07:24:46

虽然我希望避免它,但如果我自己解析配置文件,我可以通过 http://search.cpan.org/perldoc?Log::Log4perl。也就是说,

  ########################
  # 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);

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

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

While I was hoping to avoid it, if I parse the config files myself I can then access the configuration in perl via the API documented in http://search.cpan.org/perldoc?Log::Log4perl. Namely,

  ########################
  # 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);

While the other method works, there's too many caveats for me to be comfortable using it (Gee I used this library, why'd my logging stop?) -- it's just too surprising for my tastes.

Instead, I think I'm going to see if I can't get from config file to Log::Log4perl state by looking through how to use Log::Log4perl::Config::PropertyConfigurator, which is delegated to by ->init when parsing a config file is needed. If I go over the data structure that returns, i can compare changes to the initialization on a logger-by-logger and appender-by-appender basis and modify the initialized state appropriately, handle namespace collisions properly, etc.

红颜悴 2024-10-19 07:24:46

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

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

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;

You can remember what config files was already loaded (%log_configs hash in code below). When new class arrives, you can reread all configs, merge it together and init Log::Log4perl again using string reference parameter to init.

I generally prefer having a single log configuration per application, because of easier maintenance and reload capability.

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文