perldieoverridingcarp

Overriding croak cluck confess carp from carp module in Perl


I know how to override in built functions in perl and I have overridden die warn say and since print and printf can't be overridden I have tied it to a handle for my logging framework.

Example of overriding warn:

BEGIN{ *CORE::GLOBAL::warn = sub {
                my ($package, $filename, $line, $subroutine) = caller;
                untie *STDERR;
                my $message;
                foreach my $arg (@_) {
                        $message = $message.$arg;
                }
                print STDERR $message;
                tie *STDERR, __PACKAGE__, (*STDERR);
                logmessage("warn",$message,$filename, $line);
                return;
        }
}

Now is there way I can override croak cluck confess carp from carp module in Perl?


Solution

  • The functions provided by Carp are just regular functions that get imported into your packages via Exporter when the module is used. The trick is to overwrite them as early as possible inside of the Carp namespace, before anyone can import them. Then when they do, they'll get the overwritten ones.

    In your script, or at the very top of your own logging module:

    BEGIN {
        require Carp;
    
        # save original croak (will create closure ...)
        my $original_croak = \&Carp::croak;
    
        no warnings 'redefine';
        *Carp::croak = sub { 
            print "Croaking...\n"
              or $original_croak->("cannot fake croak"); # (... here)
        };
    }
    

    You need to load Carp once so Perl has the code parsed and the functions installed in the Carp namespace. Then you can overwrite them.

    Later, in some other module in your code:

    use Carp 'croak';
    
    croak 'foo';
    

    This will now produce the output we set above.

    If you want to call the original Carp::croak inside your new one, save it to a coderef and keep it around as shown in the above example.

    Note that this only works if the substitution happens really early. If you put this in your own logging module, and it gets loaded after Carp has been loaded, this will fail.

    package Foo;
    use Carp;
    use Your::Logging::Framework;
    
    croak 'foo';
    

    Will not work, because at the point where you overwrite Carp::croak, Foo::croak is already a copy of the original Carp::croak.

    If you wanted to make that work, you could always import your own carp, croak and so on to the caller explicitly as well. That will throw a bunch of warnings or complain under strict, but it should work.