Sign in to follow this  
ConorH

Best way to implement a logging feature

Recommended Posts

I currently have 5 subsytems like input.cpp, system.cpp, sound.cpp etc Id like to implement a logging feature for all of them, but all of the subsytems need to use it. Iv tried to make a class with ofstream, but found it hard to let all the other instances use the same stream sigh this is annoying me now, please help me!

Share this post


Link to post
Share on other sites
You might want to look into the "singleton pattern". I use it for the log manager in my game. Basically, it restricts a certain class to having at most one instantiation. Sometimes people overuse singletons, but for a LogManager, one instance is all you would ever want. So when I need to log a message, I just call LogManager::instance().log("blah") and it deals with the stream internally, and I can log messages from any part of my game that I need to without passing around a stream object.

Share this post


Link to post
Share on other sites
Please do not use a singleton (google will provide many reasons).

Personally, I tend to use the strategy pattern (akin to Crazyfool's suggestion) if doing anything moderately complex. Otherwise std::cerr is sufficient.

Share this post


Link to post
Share on other sites
<IMHO>

While I'm not big on singletons generally, passing around a pointer to all classes that may possibly need to log something (ie. everything) is probably a bit overkill/fugly/annoying. :)

However, doing the whole Logger::instance().log("blah") is also pretty fugly, so what I'm doing for my logger is have a global instance (*gasp*), rather than using a singleton (which is just a global in fancy dress anyway). In fact, I have several instances, one for each level of "severity".

</IMHO>

Here's an example of what I do:


in Log.h:

namespace Log {
class Logger { }

extern Logger Normal;
extern Logger Warning;
extern Logger Error;
extern Logger Debug;

}

in Log.cpp
Logger Normal(kSeverity_Normal);
Logger Warning(kSeverity_Warning);
etc...



My Logger class overloads << (using ostringstream internally) so i can just do:

Log::Normal << "Level of pie: " << pieLevel << Log::End;


It's probably worth pointing out that the Logger class is pretty much a stub class that's pretty empty of functionality besides the stream operator. Once Log::End is streamed in, the Logger class calls a callback that was setup by the application on startup. It's up to the application to log to file, print to game console, etc.

Okay, I better stop rambling and get back to work. Hope this helps :)

Share this post


Link to post
Share on other sites
Personally I use a singleton for my logger (it's one of the few places where I feel the singleton pattern actually has a use), along with a helper macro for working with it:


extern Singleton<Logger> g_logger;

#define LOG(level) g_logger::get().startEntry(level, __FILE__, __LINE__)

void func()
{
LOG(WARNING) << "This is warning number " << 5;
}

int main()
{
g_logger::get().open("app.log");
g_logger::get().set_formatter(new LogFormatterXML);
func();
}



The Logger::startEntry() function returns a helper object that acts as a std::stringstream, and on destruction of the helper outputs the complete log entry (the format of which is determined by a LogFormatter object) to the log file.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this