.. _program_listing_file_Utilities_Logger.h: Program Listing for File Logger.h ================================= |exhale_lsh| :ref:`Return to documentation for file ` (``Utilities/Logger.h``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef __Logger_h__ #define __Logger_h__ #include #include #include #include #include #include #include namespace Utilities { enum LogLevel { DEBUG=0, INFO, WARN, ERR }; class LogSink { protected: LogLevel m_minLevel; public: LogSink(const LogLevel minLevel) : m_minLevel(minLevel) {} virtual ~LogSink() {} virtual void write(const LogLevel level, const std::string &str) = 0; void setMinLevel(LogLevel level) { m_minLevel = level; } }; class ConsoleSink : public LogSink { public: ConsoleSink(const LogLevel minLevel) : LogSink(minLevel) {} virtual void write(const LogLevel level, const std::string &str) { if (level < m_minLevel) return; // if (level == LogLevel::INFO) // std::cout << "Info: "; // else if (level == LogLevel::WARN) std::cout << "Warning: "; else if (level == LogLevel::ERR) std::cerr << "Error: "; std::cout << str << std::endl; } }; class FileSink : public LogSink { protected: std::ofstream m_file; public: FileSink(const LogLevel minLevel, const std::string &fileName) : LogSink(minLevel) { m_file.open(fileName.c_str(), std::ios::out); if (m_file.fail()) std::cerr << "Failed to open file: " << fileName << "\n"; } virtual ~FileSink() { m_file.close(); } virtual void write(const LogLevel level, const std::string &str) { if (level < m_minLevel) return; // print time time_t t = time(0); // get time now struct tm * now = localtime(&t); m_file << "[" << (now->tm_year + 1900) << '-' << std::setfill('0') << std::setw(2) << (now->tm_mon + 1) << '-' << std::setfill('0') << std::setw(2) << now->tm_mday << " " << std::setfill('0') << std::setw(2) << now->tm_hour << ":" << std::setfill('0') << std::setw(2) << now->tm_min << ":" << std::setfill('0') << std::setw(2) << now->tm_sec << "] "; // print level if (level == LogLevel::DEBUG) m_file << "Debug: "; else if (level == LogLevel::INFO) m_file << "Info: "; else if (level == LogLevel::WARN) m_file << "Warning: "; else if (level == LogLevel::ERR) m_file << "Error: "; m_file << str << std::endl; m_file.flush(); } }; class BufferSink : public Utilities::LogSink { protected: std::vector> m_buffer; public: BufferSink(const LogLevel minLevel) : LogSink(minLevel) { m_buffer.reserve(10000); } virtual void write(const Utilities::LogLevel level, const std::string& str) { if (level < m_minLevel) return; m_buffer.push_back({ level, str }); } std::vector>& getBuffer() { return m_buffer; } void clearBuffer() { m_buffer.clear(); } }; class Logger { public: Logger() { m_active = true; } ~Logger() { m_sinks.clear(); } protected: std::vector> m_sinks; bool m_active; public: // Todo: format void addSink(std::shared_ptr sink) { m_sinks.push_back(sink); } void removeSink(std::shared_ptr sink) { for (auto it = m_sinks.begin(); it != m_sinks.end(); it++) { if (*it == sink) { m_sinks.erase(it); break; } } } std::vector>& getSinks() { return m_sinks; } void write(const LogLevel level, const std::string &str) { if (!m_active) return; for (unsigned int i = 0; i < m_sinks.size(); i++) m_sinks[i]->write(level, str); } void activate(const bool b) { m_active = b; } }; class LogStream { public: LogStream(Logger *logger, const LogLevel level) : m_logger(logger), m_level(level) {} template LogStream& operator<<(T const & value) { m_buffer << value; return *this; } ~LogStream() { m_logger->write(m_level, m_buffer.str()); } protected: LogLevel m_level; Logger *m_logger; std::ostringstream m_buffer; }; extern Utilities::Logger logger; #define LOG_DEBUG Utilities::LogStream(&Utilities::logger, Utilities::LogLevel::DEBUG) #define LOG_INFO Utilities::LogStream(&Utilities::logger, Utilities::LogLevel::INFO) #define LOG_WARN Utilities::LogStream(&Utilities::logger, Utilities::LogLevel::WARN) #define LOG_ERR Utilities::LogStream(&Utilities::logger, Utilities::LogLevel::ERR) #define INIT_LOGGING Utilities::Logger Utilities::logger; } #endif