/* log.hh * vim: set tw=80: * Eryn Wells */ #ifndef __LOG_HH__ #define __LOG_HH__ #include #include #include #include #include #include #include namespace charles { namespace log { /** Useful predefined levels. */ namespace level { unsigned int Error = 10; unsigned int Warning = 20; unsigned int Info = 30; unsigned int Debug = 40; unsigned int Trace = 50; }; struct Log { static void Init(const std::string& filename, unsigned int level = level::Info); static void Close(); Log(const std::string& name = "root", unsigned int level = level::Info); ~Log(); template Log& operator<<(const T& item); private: struct Logger { Logger(unsigned int level = level::Info); unsigned int level; }; typedef std::map LoggerMap; static unsigned int sLevel; static std::ostream* sOutput; static LoggerMap sLoggers; static Logger& GetLogger(const std::string& name); const std::string& mName; unsigned int mLevel; Logger& mOutput; }; struct Tracer { Tracer(const std::string& name, const std::string& function); ~Tracer(); private: const std::string& mName; const std::string& mFunction; }; unsigned int Log::sLevel = 0; std::ostream* Log::sOutput = nullptr; Log::LoggerMap Log::sLoggers; /* static */ void Log::Init(const std::string& filename, unsigned int level) { assert(sOutput == nullptr); sOutput = new std::ofstream(filename); sLevel = level; Log("ROOT", 1) << "Opening log file: " << filename; Log("ROOT", 1) << "Level set to " << sLevel; } /* static */ void Log::Close() { assert(sOutput != nullptr); delete sOutput; sOutput = nullptr; } /** * Construct a Log object. * * @param [in] name The name of the log stream. If this name hasn't been * seen before, a new one will be created for you. * @param [in] level The level. If this is higher than the level of the log * stream, nothing will be output. */ Log::Log(const std::string& name, unsigned int level) : mName(name), mLevel(level), mOutput(Log::GetLogger(name)) { using namespace std::chrono; /* Write a log message leader: "