1

I have a logger class. Call it MyLogger. I may use it in a function like this:

void MyFunc(MyLogger& oLogger)
{
   //Do stuff
   oLogger.Log("In MyFunc : Some Error");
   //Do something else
   oLogger.Log("In MyFunc : Some other error");
}

Now, I want to prepend "In MyFunc" to the logs if the log comes from inside MyFunc. Similarly for other functions...

Because this is tiresome, I tried something like this:

void MyLogger::PushPrependString(const char*)
{
   //Store prepend string in stack and set it as current prepend string.
}

void MyLogger::PopPrependString()
{
   //Pop the most recent prepend string.
}

Now, I can use these two functions like this:

void MyFunc(MyLogger& oLogger)
{
   oLogger.PushPrependString("In MyFunc : ");
   //Do stuff
   oLogger.Log("Some Error");
   //Do something else
   oLogger.Log("Some other error");
   oLogger.PopPrependString();
}

The trouble is, if there are multiple returns in a function, this becomes ugly. Is there any way around this? Is this a common problem? Is there any preprocessor macro like __FILE__ or __LINE__ for getting the name of the function a line appears in? Any comments would be appreciated. Thanks.

nakiya
  • 14,063
  • 21
  • 79
  • 118

2 Answers2

3

"The trouble is, if there are multiple returns in a function, this becomes ugly. Is there any way around this?"

Yes, just use an object with constructor (calls PushPrependString) and destructor (calls PopPrependString).

class LogPrefix
{
private:
    MyLogger* logger_;

    LogPrefix( LogPrefix const& );              // No such.
    LogPrefix& operator=( LogPrefix const& );   // No such.
public:
    LogPrefix( MyLogger& logger, char const s[] )
        : logger_( &logger )
    {
        logger_->PushPrependString( s );
    }
    ~LogPrefix()
    {
        logger_->PopPrependString();
    }
};

Disclaimer: off the cuff code, not touched by compiler's hands...

"Is this a common problem?"

Yes.

"Is there any preprocessor macro like FILE or LINE for getting the name of the function a line appears in?"

Not in C++98. Various compilers offer various extensions that do that. IIRC C++0x adopts the C99 scheme, which unfortunately just provides static strings.

Cheers & hth.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • +1... I'm flagging Jonathan Leffler's answer as the solution just because he answered first. – nakiya Oct 28 '10 at 05:54
2

RAII - Resource Acquisition Is Initialization.

In this case, you create an object on entry to the function that identifies the current function to the logging system; when the function exits (by any return or by exception thrown or by exception not caught), the object will be destroyed, and the destructor changes what is printed in future by the logging system.

In C99, and maybe in some C++ compilers such as G++, there is a predefined variable, __func__ containing the function name. The C++ equivalent is more complex, I believe.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Nice... Never occurred to me that the lifetime of the function is lifetime of its locals :(. – nakiya Oct 28 '10 at 05:01