views:

2646

answers:

4

I trying to incorporate a simple error logging into my existing app, at the moment it reports errors just using cout so i was hoping to keep a similar interface using the << operator. However i want it to log the line & function the error occurred. But i don't want to have to type __LINE__, __FUNCTION__ every time i need to log. Does anyone know a trick i can use to allow the __LINE__ macro to be used inside another function, reporting the calling line instead. Hope that makes sense

class myLogClass {
    uint8_t level;            
public:           
    bool operator<<( const char * input );       
};

bool myLogClass::operator<<( const char * input ) {
    logItInSQL( input );
    return true;
}

Instead of this every time

myLogClass << "Line No: " << __LINE__
    << " Function: " << __FUNCTION__
    << " Error: " << "This is my error to be logged";

I would like to just be able to do:

myLogClass << "This is my error to be logged";

bool myLogClass::operator<<( const char * input ) {
    logItInSQL( " Line No: __LINE__" );
    logItInSQL( " Function: __FUNCTION__" );
    logItInSQL( " Error: " + input );
    return true;
}
+1  A: 

No, this is why logging is done with macros. __LINE__ needs to be expanded by the preprocessor on the line in question, not in a common logging function.

Adam Mitz
A: 

As Adam Mitz mentioned you need to use __LINE__ in the place of call.
I recommend to you to add an extra parameter like "additionalInfo" and create a macro that will generate this "additionalInfo" using __LINE__ and __FUNCTION__.

Mykola Golubyev
+7  A: 
myLogClass << "Line No: " << __LINE__ ...

With your operator << chaining will not work since it returns a bool.

bool myLogClass::operator << (const char * input)

It is customary to define stream insertion as follows:

std::ostream& myLogClass::operator << (std::ostream& o, const char * input) {
    // do something
    return o;
}

Do this:

#define log(o, s) o << "Line No: " << __LINE__ << \
                   " Function: " << __FUNCTION__ << \
                   " Error: " << s // note I leave ; out

Additionally, you can wrap the macro in a do-while loop:

#define log(o, s) do { o << "Line No: " << __LINE__ << \
                   " Function: " << __FUNCTION__ << \
                   " Error: " << s; \ 
                  } while(0) // here, I leave ; out

Then you can happily write:

 myLogClass myLogger; // do this

 // use it
log(myLogger, "This is my error to be logged"); // note the ;
dirkgently
Good answer, except that myLogClass is a class, not an instance, so he actually needs to instantiate it and pass an instance to log(instance,"message)
Carlos A. Ibarra
@thinkcube: Thanks! Note to self: never copy-paste from questions. Always compile.
dirkgently
A: 

I could not get the code in the first answer to compile. I use this simple macro which accomplishes the task well:

#define qlog(s) std::cerr << __FUNCTION__ << "::" << __LINE__ << "\t" << s << endl

applecommander