create_custom_level()在哪里需要声明(log4perl)?

时间:2014-02-28 00:21:24

标签: perl logging

我正在尝试在Perl中创建自定义消息级别“警告”(警告和错误之间),但始终收到错误消息:

create_custom_level must be called before init or first get_logger() call at /usr/share/perl5/Log/Log4perl/Logger.pm line 705.

我的自定义级别声明如下:

use Log::Log4perl qw(get_logger); 
use Log::Log4perl::Level; 
Log::Log4perl::Logger::create_custom_level("ALERT", "ERROR");

据我所知,documentation将这个放在任何打算使用自定义级别的文件的顶部就足够了。所以我不知道我做错了什么。查看抛出错误的文件Logger.pm显示在声明自定义级别之前正在初始化logger。有谁知道这可能会发生什么?

P.S。我保证在这里创建一个自定义级别是正确的选择,即使它不受欢迎。

编辑:问题已回答!最重要的答案是更多的调试指南,所以我想从评论部分复制我的解决方案,以便未来的读者更有可能看到它。

我发现修复问题有两个步骤:

  1. 我需要将create_custom_level放在BEGIN {...}语句中,以便它在编译时运行,因为它显然被编译时调用的记录器初始化打败了。

  2. 我意识到在主脚本(.pl)和它的模块(.pm)中放置相同的create_custom_level行是多余的,并且导致我的部分问题。根据您在语句编译时执行语句的顺序(如'use'和'BEGIN'),在多个文件中调用create_custom_level可能会导致序列:'create custom level','initialize logger',跨多个文件'创建自定义级别'。我没有弄清楚早期初始化记录器的位置,但我能够通过尽早创建我的自定义级别来避免这种情况(对于其他没有经验的编码器,使用perl调试器可能是了解其中的顺序的关键)行和文件被执行)。最好将create_custom_level放在原始脚本或它使用的第一个模块中。

  3. 希望这有助于其他人!

1 个答案:

答案 0 :(得分:3)

您提供的代码不会产生错误。

您的脚本稍后可能会在编译时评估其他代码 - 在use语句中加载的模块或BEGIN { ... }块中的某些代码 - 初始化Logger。

如果可能发生这种情况并不明显,您可以使用Perl调试器找出Logger调用的来源。首先,在use Log::Log4perl;use Log::Log4perl::Level;语句之后立即将此行放在您的文件中:

BEGIN { $DB::single=1 }

此语句将使调试器在编译时阶段停止在此行,并允许您在编译阶段的其余部分停止在断点处。然后启动调试器

$ perl -d the_script.pl

在关键Log::Log4perl函数

上设置断点
DB<1> b Log::Log4perl::init
DB<2> b Log::Log4perl::get_logger

开始执行代码

DB<3> c

当代码停止时,获得堆栈跟踪

Log::Log4perl::get_logger(/usr/local/lib/perl5/site_perl/5.18.1/Log/Log4perl.pm:371):
371:        my $category;

DB<4> T