Logger ideas

Started by
8 comments, last by Replicon 16 years, 10 months ago
So I'm thinking about rewriting my cheap little logger class into a newer, stream-based logger. I know std::clog is all I need, but I want it to support multiple streams at a time, so, for example, I can be generating a log file, but at the same time, I may turn on logging in the in-game console, which would require the log entries being pumped into two streams. I was wondering if you guys could share some more ideas for really useful (but relatively lightweight) features on a logger geared towards gaming. I think something like what I describe should be sufficient though... Also, what's a good way to entirely compile out that stuff? Like suppose I have this in an inner loop:

someDebugLog << "Values are " << slightPerformanceHit(x) << " and "
             << otherSlightPerformanceHit(y) << endl;
Just turning off debug logging won't do me any good, because of the order of execution of the chained operator<<'s. I don't want to do some tacky macro that puts a comment there or something (plus that would be hard due to the multiline nature of it all anyway). I guess I could do something that would make my code look like:

logDebug(someDebugLog << .....);
But that's also kind of ugly-looking..... Ideas?
Advertisement
How about log levels? The idea is to allow the creation of certain log
destinations to only listen to certain log levels.

For example:
LogLocation* pFile = new LogLocHTML ("MyLog.html");pFile.SetThreshold (LOG_WARNING);  // only output warnings/errorsLogSource lout;lout << LogLevel (DEBUG) << "Hi" << std::endl;  // will only output to DEBUG streamslout << LogLevel (WARNING) << " *** Some error" << std::endl; //outputs to file

My log manager uses this approch[smile]


For compiling out, you can try using the preprocessor:
#ifdef DEBUGlout << LogLevel (DEBUG) << "Hi" << std::endl;  // will only output to DEBUG streams#endif

#define DEBUG for debuig builds, #undef for release. In release builds, the
compilier will not see the above code. It will only compile if DEBUG is
defined.

Alot of compilier IDEs predefine NDEBUG for debug builds. You can use
this method instead, if you like.
Oh yeah don't worry loglevels are kind of assumed to be in there, sorry, should have mentioned that (already had them in the old logger). That's kind of a given :D.

As for compiling out, having to put #ifdefs all over the code is precisely what I wanted to avoid. Though I guess if I rely on the loglevels, then I only really have to ifdef out the parts that really are in an inner loop... but that could be lots of them.
Some time ago, I asked a very simular question (Looking for a way around
#ifdef/#endif everywhere)

Unfortanatly, its the only (Clean!) solution I could find right now.

Unless, anyone has suggestions?
I'm not a big fan of log levels myself, but certain languages allow for cleaner conditional compilation sans ifdefs (C# for example).

I do like the idea of log decoration though. Quite useful.
Quote:Original post by Telastyn
I do like the idea of log decoration though. Quite useful.


Hmm, can you elaborate on this? Are you talking about implementing such things as log levels and timestamps in the form of decorators around a very simple basic log system?
#if !defined(NDEBUG)  #define someDebugLog MyActualLoggingClassInstance#else  #define someDebugLog MyNullLoggingClassInstance#endifclass MyNullLoggingClassInstance : public std::ostream{public:    template <typename T>    MyNullLoggingClassInstance& operator << (T&)    {        // Do nothing, compiler will hopefully optimise it all away        return *this;    }};


Treat this as untested pseudo-code...
Unfortunately that probably won't do what the OP wants. It will suppress output but slightPerformanceHit and otherSlightPerformanceHit would still have to be called unless the compiler can prove to itself that those functions have no side effects.
-Mike
Quote:Original post by Replicon
Quote:Original post by Telastyn
I do like the idea of log decoration though. Quite useful.


Hmm, can you elaborate on this? Are you talking about implementing such things as log levels and timestamps in the form of decorators around a very simple basic log system?


Timestamps, linenumbers, current memory usage, synchronization primitives, stuff like your log 'fork'... all of which work off a common interface and end with non-decorators like 'dump to file $x', 'dump to console', 'dump to /dev/null', etc.
Quote:Original post by Anon Mike
Unfortunately that probably won't do what the OP wants. It will suppress output but slightPerformanceHit and otherSlightPerformanceHit would still have to be called unless the compiler can prove to itself that those functions have no side effects.


Yeah, that's kind of what I was getting at. Maybe there's a way to cause short-circuiting behaviour with operator<<? But I think the order of evaluation of a '<<' chain (extractor chain?) is either undefined, or highly dependant on what goes into it.

This topic is closed to new replies.

Advertisement