#pragma once #ifndef _NB_LOGGER #define _NB_LOGGER #include #include #include #include #include #include "ThreadSafeQueue.hpp" namespace nb { typedef std::chrono::time_point< std::chrono::system_clock, std::chrono::nanoseconds > LoggerTimePoint; struct LogEvent{ const LoggerTimePoint time; const unsigned char lvl; const std::string msg; }; typedef std::string (*LogProcessFunction)(const LoggerTimePoint&, const std::string&); typedef std::unordered_map LogProcessFunctionMap; template class Logger { public: Logger(StreamType& stream) : _ostream(&stream) {} bool isRunning() const; unsigned int count() const; bool run(); bool stop(); LogEvent pop(); void flush() { while(_queue.size()) { pop(); } } void deleteAll() { _queue.empty(); } void msg(const std::string& _msg, uint8_t lvl=0) { _queue.push(LogEvent{std::chrono::system_clock::now(), lvl, _msg}); } void warn(const std::string& _msg, uint8_t lvl=1) { msg(_msg, lvl); } void warn(const std::exception& _err, uint8_t lvl=1) { msg(_err.what(), lvl); } void error(const std::string& _msg, uint8_t lvl=0xFF) { msg(_msg, lvl); } void error(const std::exception& _err, uint8_t lvl=0xFF) { msg(_err.what(), lvl); } protected: virtual void process(const LogEvent& event) { uint8_t lvl = event.lvl; try { *_ostream << _function_map.at(lvl)(event.time, event.msg).c_str(); } catch (std::out_of_range e) { *_ostream << _function_map.at(0)(event.time, event.msg).c_str(); //*_ostream << event.msg; } *_ostream << "\n"; } static const LogProcessFunctionMap _function_map; ThreadsafeQueue _queue; StreamType* const _ostream; std::atomic _running; std::shared_ptr _runningThread = nullptr; }; template const LogProcessFunctionMap Logger::_function_map = { {0, [](const LoggerTimePoint& tp, const std::string& msg){ return msg; }} }; template bool Logger::isRunning() const { return _running && bool(_runningThread); } template unsigned int Logger::count() const { return _queue.size(); } template bool Logger::run() { if (!isRunning()) { _runningThread = std::make_shared([&]{ while(this->isRunning()) { this->flush(); } }); } return isRunning(); } template bool Logger::stop() { if (isRunning()) { _running = false; _runningThread->join(); _runningThread = nullptr; flush(); } return isRunning(); } template LogEvent Logger::pop() { std::shared_ptr event; _queue.pop(event); process(*event); return *event; } } // namespace nb #endif // _NB_LOGGER