1

I'm trying to find a decent way to do logging from C++. My current solution is this:

ostream & GetLog() { if( output == NULL ) throw error; return *output; }

Where output is defined somewhere and can be a file or whatever. This is fine, but it doesn't let me do anything other than throw an error if output is not allocated. Also, my program is multithreaded, and I need to obtain a lock in order to correctly check if output is not NULL and then write to it if it is not. Ideally, any code that uses GetLog() should obtain that lock:

{
    LockLog lock;
    if( HasLog() )
        GetLog() << "My dog ate " << n << " cookies!" << endl;
}

This seems like too much verbiage to me. I'd like to do something like just

GetLog() << "My dog ate " << n << " cookies!" << endl;

and have it work without an error when the log's not allocated (and with lock), or a function like

WriteLog( "My dog ate " << n << " cookies!" << endl );

I know with C printf syntax this can be done with variable argument function. Is there a way to do this with C++ syntax and without a macro that would force me to expose the GetLog, HasLog, and LockLog functions anyway?

Scott
  • 1,176
  • 2
  • 13
  • 19
  • If you like `printf`, what keeps you from using it? It's inside ``. – zneak Sep 11 '10 at 05:02
  • @zneak, obviously my problem is not where to find printf. I'm just used to the iostream syntax, and all my code is written using it, but thanks anyway. – Scott Sep 11 '10 at 22:51

4 Answers4

2

like this?

class Log {
    class buffer {
        buffer(...);
        ~buffer() {
            Lock lock(mutex);
            // write in destrcutor
        }
        string data;
        Mutex &mutex;
    };
    Mutex mutex;
...
};

template<class T>
Log::buffer operator<<(Log& l, T t) {
    return t;
}

template<class T>
Log::buffer& operator<<(Log::buffer& b, T t) {
    return b += t;
}

Log log;

log << "blah" << 6;
Anycorn
  • 50,217
  • 42
  • 167
  • 261
1

For the formatting you might try boost::format

http://beta.boost.org/doc/libs/1_44_0/libs/format/index.html

Mark
  • 1,124
  • 1
  • 14
  • 21
0

From experience, I would write a function which takes a string (or list of strings), and locks/logs inside the function. Leave the formatting outside the actual logging function, so you ensure that everything gets logged in the same block for a single logical log message.

You could do something like I did to handle the formatting, which is: create a string-derived class with a printf-style constructor, and use it inline.

So, for example:

class PFString : public string
{
public:
    PFString( const char* pcszFormat, ... )
    { ... }
};

Log( PFString( "something with number %d", 42 ) );

Of course, you're free to format the string other ways too (eg: C++ operator style syntax, resource string formatting, etc.).

Nick
  • 6,808
  • 1
  • 22
  • 34
0

Use log4cxx, which is a

decent way to do logging from C++

that you are unlikely to be able to match in a timely way. Even if this seems like overkill now you may find that your diagnostic needs grow as your system does, making the logging component a time sink that was not envisaged at the start.

I find I both save time, and learn good design from better developers, when I use well-designed, robust frameworks like this (cf. Boost, STL).

Steve Townsend
  • 53,498
  • 9
  • 91
  • 140