Max
Max

Reputation: 835

Where Does create_custom_level() Need to Be Declared (log4perl)?

I'm trying to create a custom message level 'alert' (between warn and error) in Perl, but consistently get the error message:

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

My declaration of the custom level looks like this:

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

As far as I can tell from the documentation putting this at the top of any file which intends to use the custom level should be enough. So I can't tell what I'm doing wrong. Looking in the file Logger.pm where the error is thrown from shows that logger is being initialized before the custom level is being declared. Does anyone know how this could be happening?

P.S. I assure you creating a custom level is the right choice here, even if it's frowned upon.

EDIT: Question Answered! The top answer was more a guide to debugging, so I wanted to copy my solution from the comment section so that future readers would be more likely to see it.

I found that there were two steps to fixing my problem:

  1. I needed to put create_custom_level in a BEGIN { ... } statement so that it would run at compile time, since it was apparently being beaten by a logger initialization that was being called at compile time.

  2. I realized that putting the same create_custom_level line in both the main script (.pl) and its modules (.pm) is redundant and caused part of my problems. Depending on the order in which you've put your statements that execute at compile time (like 'use' and 'BEGIN'), calling create_custom_level in multiple files could lead to the sequence: 'create custom level', 'initialize logger', 'create custom level', across multiple files. I didn't figure out where the logger was being initialized early, but I was able to circumvent that by just creating my custom level as early as possible (for other inexperienced coders, using the perl debugger can be key in understanding the order in which lines and files are executed). Best to put create_custom_level in the original script or the first module it uses.

Hope this helps someone else!

Upvotes: 1

Views: 275

Answers (1)

mob
mob

Reputation: 118605

The code you provided doesn't produce an error.

Perhaps you have some other code later in your script that is evaluated at compile time -- a module loaded in a use statement or some code in a BEGIN { ... } block -- that initializes a Logger.

If it's not obvious where this might be happening, you can use the Perl debugger to find out where the Logger call could be coming from. First, put this line in your file right after the use Log::Log4perl; and use Log::Log4perl::Level; statements:

BEGIN { $DB::single=1 }

This statement will get the debugger to stop at this line during the compile time phase, and allow you to stop at breakpoints during the rest of the compile phase. Then fire up a debugger

$ perl -d the_script.pl

set breakpoints on the critical Log::Log4perl functions

DB<1> b Log::Log4perl::init
DB<2> b Log::Log4perl::get_logger

begin executing the code

DB<3> c

and when the code stops, get a stack trace

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

DB<4> T

Upvotes: 3

Related Questions