Logging class (without singleton?)

Started by
16 comments, last by Trienco 14 years, 8 months ago
Hello, Im writing a little engine which will have this structure: I have a Root object, which acts kinda as a factory. Here is an (pseudo code) example:
Root r = createRoot();
SceneManager sc = r->createSceneManager();
Entity e = sc->createEntity("robot.mesh");
Now I need to log at various parts in my engine (in Root methods, SceneManager methods, Entity Methods) and so on. I wonder how I could implement this logging. Currently I only see 2 possibilites: The Root object stores a pointer to a Logger and passes the Logger to all created objects. Thus EVERY class whose methods ever need to log something needs a pointer to the logger. Another problem is that all created objects wouldnt recognice is if I did change the logger. The other possibility is to make the logger a singleton. Then every class could just log with Logger::getInstance().Log(...). The problem with this approach is: Well, I just dont like singletons and try to avoid them whenever I can. Any suggestions how I could provide a logging feature for all my classes are highly appreciated!
Advertisement
A global? Less work than either of your alternatives. Yup, same old approach the Standard C++ Library uses for std::cout, std::cerr and std::clog.
Just create some log object at the appropriate scope and use it. This is all I do, on those rare cases where I need logging.
#include "Log.h"void SomeFunction() {  Log log("somefile");   log << "Hello there."}

(Yes, the obvious implementation involves opening and closing the backing file often. You can work around this, or just eat the cost since logging is 'slow' anyway, and you probably want to flush the stream constantly regardless to ensure that you always get the most updated file contents, especially if you're logging around a crash).
I also thought about a global variable. But... aren't global variables even more evil than singletons?
Quote:
I also thought about a global variable. But... aren't global variables even more evil than singletons?

No, they're less evil.

Logging is a mostly-trivial problem. Do the simplest thing that works for you. Don't over-engineer the thing.
I've written a handful of loggers. They end up a single, globally defined object, every time.

This is because, in my cases at least, logging has always been a debugging aid, not an integrated part of the functionality. I might decide that any part of the code, at any level, has a sudden need to log. The next day it will be different. As a result, adding logging code doesn't fit neatly into a design process. It's not compartmentalized. And that's a situation that often drives the creation of singletons.

If what you're calling logging is really an audit trail, something that's a critical part of the application and not something you'll ultimately turn off, then it deserves a more formal place in the design.
Hehe, yes thats true.

I can't use your approach jpetrie, because my logger is a little bit more compley. For example I can add various Appenders to my logger and thus creating a logger everytime I need to log is no option.

So I guess I just go for the global variable approach.
When people say that "globals are evil", they really mean shared mutable state. Read only constants aren't evil. The logger, which really has a "write only" interface, is tolerable as a global IMO.
Quote:Original post by ScottMayo
If what you're calling logging is really an audit trail, something that's a critical part of the application and not something you'll ultimately turn off, then it deserves a more formal place in the design.


Well, I think it just a nice feature to get some consistent feedback from the engine. I will definitely use logging in debug mode AND release mode, though my logging in debug mode will be more verbose (in debug mode I also log the function, source file etc).
Nonetheless I still tend to use a global variable (because passing logger pointers to billions of objects isnt elegant either and I just hate singletons;)
Hm, one more question that is related to my problem:
Sooner or later I will need some additional classes which are heavily access from various places. For example a class "TextureManager" which loads and pools textures.
Would you make such "complex" classes like TextureManager also accessible through a global variable, or would you make it a singleton or ...?

This topic is closed to new replies.

Advertisement