views:

183

answers:

1

I want to adopt logging within several utility classes, e. g. DBI. What is the best practice to do it with Log::Log4perl?

I think it is OK to subclass DBI (say, MyDBI) and override some methods there to make them do the logging. But there's a problem with categories. If you create a logger with

Log::Log4perl->get_logger(ref $self || $self)

then all log entries belong to MyDBI and it would be hard to filter them. So it seems better to me to pass a logger to MyDBI from the calling module (say, MyModule), so that category would be semantically right. The first question, is it OK in general? I mean, are there any hidden reefs regarding such approach?

The second question, how to pass the logger to MyDBI? I have an idea to declare a global variable, e. g. $MyDBI::logger and set in the calling method:

local $MyDBI::logger = Log::Log4perl->get_logger(ref $self || $self);

There's a traditional dislike for global variables. Can you think of a better way?

EDIT: Of course, the best code is no code. caller would suffice, if it took inheritance into account.

The third question, is it possible to log into both categories, MyDBI and MyModule, with Log::Log4perl, if they are hierarchically unrelated?

+1  A: 

I would strongly encourage you to to log independently on the caller in a separate logger either per function or per module, so that you can run your module independently of log4perl used in your caller. Each module will create its own logger with Log::Log4perl->get_logger("module name").
If the caller does not create any appender, the program will simply not log anything and the log4perl in the modules will be ignored from a functional stand point.
Log4Perl implements a singleton pattern for creating a logger, which is similar to a global variable.
Your Logging should be fine-grained as possible and as a rule of thumb I log in debug any input parameter and any result of a function/method. If really necessary, you can also use the stack trace to find out the caller which has lead to the error condition. Adding it into the parameters does just add additional complexity.

The following recipes might give you some more ideas about the flexibility on the configuration side of log4perl.Log4Perl Recipes The whole idea for me is to keep the code unchanged and change the logging configuration depending on my actual logging/bug tracing requirements (which might change in the future). To keep the code unchanged if possible is even more important with modules as you want to avoid testing all calling programs.

To answer your questions in brief. 1.) Each module should have its own logger 2.) Thus do not add the loggers into the interface 3.) Log4Perl will log on all levels depending on your appender configuration. This way you control what you will see not see - normal level will usually be INFO and specific modules might be in debug. In bad cases the Pattern layout will allow you to add the stack trace into the logging purely with configuration.

weismat
Excuse me, I haven't understood the first sentence. What do you mean by "caller", "run your module independently of log4perl"? Could you please make it more explicit?
codeholic
E.g. when writing test classes you might create some modules which will not necessarily implement log4perl - you can simply skip it whereas you need to add plenty of logic if it part of your interface.
weismat