talexb has asked for the wisdom of the Perl Monks concerning the following question:

I am in the process of cleaning up a module I've written called JobQueue for submission to CPAN. The module is an API that allows job submission to either a Sun Grid Engine installation, or a local fork/wait bundle of processes, in case that's useful to anyone.

Anyway, tt's all very exciting. However, since it's my first submission, I have some stylistic questions. I use Log::Log4perl as a development tool, and as a consequence have a variety of debug, info and a few logdie statements in the JobQueue code. These are very useful to have in the event that something goes horribly wrong, but the bad news is that Log::Log4perl is not a core module (in fact, installing it can be a bit of a pain), and I don't want to force users of my module to install it.

But that leaves me in a difficult place -- if they don't have the logging module installed, and the module misbehaves, they don't have any log file to look at to assist them (and me) in understanding what went wrong.

So, force them into installing the logger, or do without, and have no diagnostic tools?

Alex / talexb / Toronto

"Groklaw is the open-source mentality applied to legal research" ~ Linus Torvalds

Replies are listed 'Best First'.
Re: Any suggestions on cleaning up a module for submission to CPAN?
by imp (Priest) on Aug 31, 2006 at 17:42 UTC
    I prefer pluggable logging objects personally.

    Here's an untested example of what I mean:

    package Foo; use strict; use warnings; sub new { my $class = shift; $self = bless {@_}, $class; $self->init_logging(); } sub init_logging { my $self = shift; return if exists $self->{LOGGER}; eval { require SomeLogger; $self->{LOGGER} = SomeLogger->new(); }; } sub debug { my $self = shift; return unless exists $self->{LOGGER}; $self->{LOGGER}->debug(@_); }
    With this type of setup the user can run the code without any problems if the logging class is not available, and if they wish to use a different type of logger they can do something like this:
    my $logger = SomeOtherLogger->new(log_level => 'debug'); my $foo = Foo->new(LOGGER => $logger);
    As long as SomeOtherLogger uses the same interface you're ok. To make it more robust you can do something like this:
    use Scalar::Util qw( blessed ); sub debug { my $self = shift; return unless exists $self->{LOGGER}; return unless blessed $self->{LOGGER}; return unless $self->{LOGGER}->can('debug'); $self->{LOGGER}->debug(@_); }

    Update - switched to require within the eval, per chromatic's suggestion

      Do you mean instead:

      require SomeLogger;

      ... in the eval block? I'm not sure whether you intended a conditional load.

        Aye, that was my intent.
        eval { require SomeLogger; $self->{LOGGER} = SomeLogger->new(); };
Re: Any suggestions on cleaning up a module for submission to CPAN?
by jdporter (Paladin) on Aug 31, 2006 at 17:42 UTC

    You shouldn't force them one way or the other. Make the dependency optional; detect the presence of Log4perl at run time; use if present.

    Personally, I'd isolate the logging bits behind a generic interface, that is, a wrapper; then I'd make another wrapper for a different logging module. If it turns out to be easy, you could do several. Detect the presence of any of them at run time (in some kind of priority order), and use one if found. I've done something like this for XML parsing modules.

    We're building the house of the future together.
Re: Any suggestions on cleaning up a module for submission to CPAN?
by Solo (Deacon) on Sep 15, 2006 at 01:16 UTC
    In case you haven't seen it, the Log::Log4perl FAQ offers a recommended method to 'gracefully' degrade.

    --Solo

    --
    You said you wanted to be around when I made a mistake; well, this could be it, sweetheart.