#pragma once #ifndef _NB_LOGGER #define _NB_LOGGER #include #include #include #include #include #include "Processes.hpp" #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; const std::thread::id tid; const uint64_t pid; }; typedef std::string (*LogProcessFunction)(const LoggerTimePoint&, const std::string&); typedef std::unordered_map LogProcessFunctionMap; template class Logger { public: using Type = LoggerName; Logger(std::ostream& stream) : _ostream(&stream) {} bool isRunning() const { return _running && bool(_runningThread); } unsigned int count() const { return _queue.size(); } bool run() { auto this_type = static_cast(this); if (!isRunning()) { _runningThread = std::make_shared([&]{ while(this_type->isRunning()) { this_type->flush(); } }); } return isRunning(); } bool stop() { if (isRunning()) { _running = false; _runningThread->join(); _runningThread = nullptr; flush(); } return isRunning(); } LogEvent pop() { std::shared_ptr event; _queue.pop(event); static_cast(this)->process(*event); return *event; } void flush() { while(_queue.size()) { pop(); } } void deleteAll() { _queue.empty(); } template void log(const T&, const uint8_t); void log(const std::string& msg, const uint8_t& lvl) { _queue.push(LogEvent{ std::chrono::system_clock::now(), lvl, msg, std::this_thread::get_id(), get_pid(), }); } void log(const std::exception& err, const uint8_t& lvl) { _queue.push(LogEvent{ std::chrono::system_clock::now(), lvl, err.what(), std::this_thread::get_id(), get_pid(), }); } void msg(const std::string& msg, const uint8_t& lvl=0x00) { static_cast(this)->log(msg, lvl); } void warn(const std::string& msg, const uint8_t& lvl=0x01) { static_cast(this)->log(msg, lvl); } void warn(const std::exception& err, const uint8_t lvl=0x01) { static_cast(this)->log(err, lvl); } void error(const std::string& msg, const uint8_t lvl=0xFF) { static_cast(this)->log(msg, lvl); } void error(const std::exception& err, const uint8_t lvl=0xFF) { static_cast(this)->log(err, lvl); } protected: void process(const LogEvent&); ThreadsafeQueue _queue; std::ostream* const _ostream; std::atomic _running; std::shared_ptr _runningThread = nullptr; }; class BasicLogger : public Logger { public: using Base = Logger; BasicLogger(std::ostream& stream) : Base(stream) {} virtual void process(const LogEvent& event) { *_ostream << event.msg << "\n"; } }; } // namespace nb #endif // _NB_LOGGER