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

I would like my script to tell me every subroutine it calls in debug mode without having to call something like print join(",",caller(1)); inside every method of the module. In other words, I would like to see log output something like:
Entered sub ABC Entered sub DEF ..etc...
without putting code in ABC, DEF, etc. I thought about tie-ing %ModuleName:: to a routine that would do the logging, but I can't quite figure how to detect when the sub is called and this seems inefficient anyways. Any thoughts?

Replies are listed 'Best First'.
(tye)Re: Automatic Debugging
by tye (Sage) on May 30, 2001 at 03:27 UTC

    See Devel::TraceFuncs for one way to do this.

    It wouldn't be too hard to write a module, say Devel::TraceMethods that would be used like:

    use Module::Name; use Devel::TraceMethods qw( Module::Name );
    And would import all function from Module::Name into Devel::TraceMethods::Module::Name and then undef them from Module::Name. Then it would define Module::Name::AUTOLOAD that logged the call and then called the real function Devel::TraceMethods::Module::Name.

    You could even make this work in the face of a module that used AUTOLOAD (by having your AUTOLOAD log and then, if needed, call their AUTOLOAD, but then shuffle the new routine into the other namespace when that returns).

    Unfortunately, I'm not free to write one at the moment.

    Update: The above would break can for this module, so the start-up and AUTOLOAD should build shim routines that log and then call the real routine.

            - tye (but my friends call me "Tye")
      That's clever. I suppose a quick and dirty way would be to define ChildModule of Module and only define an ChildModule::Autoload. ChildModule::Autoload would log the function call, then call SUPER::ModuleSub

        Sorry, no. SUPER:: requires @ChildModule::ISA contain your Module, which also means that AUTOLOAD won't be called for methods that are defined in your Module.

        But you can do something like:

        package AutoTrace; my %pkgMap; sub AUTOLOAD { logCall( $AUTOLOAD, @_ ); my $wantPkg= $AUTOLOAD =~ s/(.*):://; $AUTOLOAD= $pkgMap{$wantPkg}."::".$AUTOLOAD; goto &$AUTOLOAD; } $pkgMap{ChildModule}= "Module"; *ChildModule::AUTOLOAD= \&AUTOLOAD;
        instead of the SUPER:: trick (again, can won't work, which often won't be a problem).

                - tye (but my friends call me "Tye")
Re: Automatic Debugging
by bikeNomad (Priest) on May 30, 2001 at 18:10 UTC
    I'm not sure what you gain by including code when the debugger already does this...

    If you set the frame option in the debugger, it'll tell you when you enter a subroutine:
    PERLDB_OPTS="frame=1" perl -d myprogram.pl
    If you just want a trace (and don't need to debug interactively), you can use the NonStop option:
     PERLDB_OPTS="NonStop frame=1" perl -d myprogram

    The output with NonStop on (with interspersed program output) looks like this:

    Package pathdiff.pl. entering Algorithm::Diff::traverse_sequences entering Algorithm::Diff::_longestCommonSubsequence entering CODE(0x80fdd48) entering CODE(0x80fdd48) entering CODE(0x80fdd48) entering Algorithm::Diff::_withPositionsOfInInterval entering CODE(0x80fdcb8) entering CODE(0x80fdcb8) entering main::match same: a a entering main::discA omitA: b entering main::discB omitB: c

    Updated: added output sample

Re: Automatic Debugging
by princepawn (Parson) on May 30, 2001 at 08:14 UTC
    Carp::Datum - debugging and tracing ultimate module allows for programming by contract but as a side effect, throug Log::Agent offers very verbose and easy-to-follow debugging info.
      Forgive my ignorance, but wouldn't using this module require me to change the code in ALL my subroutines? This is what I was trying to avoid. I could be misunderstanding the documentation, however.