[LC++]Producing a log of routine entry and exit

Dr Mark H Phillips mark at austrics.com.au
Mon Sep 2 15:51:18 UTC 2002


At the start of this thread I wrote:

On Thu, 2002-08-29 at 17:02, Dr Mark H Phillips wrote:
> Hi,
> 
> For debugging purposes, I wished to provide a standard means of
> logging the entry into, and exit from, each of my routines.  This
> log should give the name of the routine, and calling signature.
> On entry it should print the input parameters, and on exit, the
> output parameters.

I have now found a way of doing this which may be a
good solution.  I am interested to hear people's opinions
on it.  Are there potential problems with it?

int myRoutine(string& retString, int a, char b) {
  cout<<"entering myRoutine(string&, int, char)\n"
      <<"  second param: "<<a<<'\n'
      <<"  third  param: "<<b<<endl;
  int ret;

  struct ScopeExit {
    int const& ret; string const& retString; 
    ScopeExit(int const& r, string const& s): ret(r), retString(s) {}
    ~ScopeExit() {
      cout<<"exiting myRoutine(string&, int, char)\n"
          <<"  first param: "<<retString<<'\n'
          <<"       return: "<<ret<<endl;
    }
  } scopeExit(ret, retString);

  // do stuff here
  // including "return ret;" at various locations

  return ret;
}

The key advantages with this approach are:

1. No "goto preExit;" is required!

2. The "exit reporting" code is written in a single place.

3. The exit code may be tailored to the specific routine
whose exit is being logged.  Ie, in this example we know
that the first parameter and the return value should be
logged on exit; for another routine, different parameters
might need to be logged.

The potential downsides I can see are:

1. What if scopeExit tries to log a variable whose scope is
the same as scopeExit's, but this variable is destroyed before
scopeExit is destroyed?  Is there a way of avoiding this 
problem?  Is there a specified "order of destruction" in C++?

2. This code has to be written many times; ie for every routine
we wish to log in this way.  It would be nice to be able to
automate this somehow, yet still allowing some degree of
tailoring to specific routines.  Perhaps macros are the way
to go???

Cheers,

Mark.

P.S. Thanks for all the other helpful suggestions!  I'm going
to investigate some of these debugging code ideas, though I
still have a need for doing the above.  In any case, I imagine
there may be a range of circumstances where being able to
specify in one place some "code to be executed before leaving 
the function (or scope)" would be useful.

P.P.S. libcwd looks interesting.  I also read about Nana, 
the gnu assertions and logging library, which seems to also 
provide partial "Design by Contract" support.  Anyone have an 
opinion on this library?


> 
> My current way of doing this is like this:
> 
> int myRoutine(string& retString, int a, char b) {
>   cout<<"entering myRoutine(string&, int, char)\n"
>       <<"  second param: "<<a<<'\n'
>       <<"  third  param: "<<b<<endl;
>   int ret;
> 
>   // do stuff here
>   // including some things like "goto preExit;"
> 
> preExit:
>   cout<<"exiting myRoutine(string&, int, char)\n"
>       <<"  first param: "<<retString<<'\n'
>       <<"       return: "<<ret<<endl;
>   return ret;
> }
> 
> The problem with this is that it requires the use of gotos
> which generally should be avoided.  It also means I can't
> create any objects "on the fly" before preExit, or I get
> an error like:
> 
> parsing.h: In function `bool moat::getToken(int &, string &)':
> parsing.h:277: jump to label `preExit'
> parsing.h:248:   from here
> parsing.h:274:   crosses initialization of `class string myString'
> 
> Now I can think of a range of alternative solutions to this
> kind of logging, but they each have their drawbacks:
> 
> 1. Same as above, but replace every instance of "goto preExit;"
> with a local copy of the code that currently follows preExit.  This
> would eliminate gotos, but would make routines very verbose, and
> would be wasteful, both in terms of program size, and in terms of
> program writing and maintenance.
> 
> 2. Create general routines "entryLog(...)" and "exitLog(...)".  Call
> entryLog(...) at the start.  Then do as in 1, except that "goto preExit"
> is replaced by a call to exitLog(...).  This is less wasteful than 1,
> but still somewhat so.  And the parameters of these calls need to be
> very general to cater for all kinds of uses - very tricky to get right,
> and involving lots of template variables and function overloading.
> 
> 3. Create a "RoutineLogger" object, instanciated at the beginning of
> its routine, and told information about the routine it is responsible
> for logging.  It has the same scope as the routine it is representing,
> so it will be destructed just before the routine exits.  In this way
> it will automatically be called at the right time without the need for
> gotos.  This solution sounds really good, except it's very hard to
> properly pass it the information needed so it can log properly.
> 
> 
> Any thoughts?
> 
> Cheers,
> 
> Mark.
> 
> 
> -- 
> Dr Mark H Phillips
> Research Analyst (Mathematician)
> 
> AUSTRICS - smarter scheduling solutions - www.austrics.com
> 
> Level 2, 50 Pirie Street, Adelaide SA 5000, Australia
> Phone +61 8 8226 9850
> Fax   +61 8 8231 4821
> Email mark at austrics.com.au
> 
> 
> _______________________________________________
> This is the Linux C++ Programming List
> : http://lists.linux.org.au/listinfo/tuxcpprogramming List
-- 
Dr Mark H Phillips
Research Analyst (Mathematician)

AUSTRICS - smarter scheduling solutions - www.austrics.com

Level 2, 50 Pirie Street, Adelaide SA 5000, Australia
Phone +61 8 8226 9850
Fax   +61 8 8231 4821
Email mark at austrics.com.au





More information about the tuxCPProgramming mailing list