I went back and had a look at the reporting implementation I wrote - I think the main difference is that I put my logger in a DLL, not the EXE. That way it's a lot easier for everything to link against it and be able to call it at run-time. However, the implementation boiled down to what I described - there's a class with a single static function allowing reporting, and purely static (i.e. single instance for the whole class) data members: Header file:
class Reporter
{
public:
Reporter();
/// Output a message at a specified level.
static void Report(TMessageLevel level, const std::string& message);
/// Determine if a message level is enabled and has attached output sink(s).
static bool Reporting(TMessageLevel level);
private:
static TMessageLevel level_; // Store message levels to be output - a bitmask
static implementation-defined message_; // Output sink mechanism
enum { ReportLevelCount = sizeof(Reporter::level_) * 8 };
};
C++ file:
Reporter::Reporter()
{
}
void Reporter::Report(TMessageLevel level, const std::string& message)
{
if (Reporting(level)) {
message_(message);
}
}
// Reporter::Reporting
//
// Is the specified reporting level active? OnError is treated separately to other
// levels, as there's a separate reporting channel for errors
bool Reporter::Reporting(TMessageLevel level)
{
int levelMask = (level < ReportLevelCount)?(1<
message_ is effectively a function object that allows me to hook up the output mechanism at runtime.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p