#pragma once #ifndef _NB_LOGGER #define _NB_LOGGER #include #include #include #include #include #include #include #include "DataSink.hpp" #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 LoggerBase : public MultithreadedDataProcessor{ using StreamType = ST; using LoggerType = Logger; using Base = MultithreadedDataProcessor; public: bool run() { if (!type_ptr->isRunning()) { this->_running = true; this->_runningThread = std::make_shared([&]{ while(type_ptr->isRunning()) { type_ptr->flush(); } type_ptr->flush(); }); } return type_ptr->isRunning(); } protected: LoggerBase() = default; StreamType _ostream; private: LoggerType* type_ptr = static_cast(this); }; template struct PackIsType; template struct PackIsType { const bool value = std::is_base_of::value; }; template struct PackIsType { const bool value = std::is_base_of::value && PackIsType::value; }; template struct StreamRefToPtrVec { StreamRefToPtrVec(std::vector _vec, Pack1& p1, Pack&... packs) : vec(_vec) { static_assert(std::is_base_of::value); vec.push_back(&p1); vec = StreamRefToPtrVec(vec, packs...).vec; } StreamRefToPtrVec(Pack1& p1, Pack&... packs) : StreamRefToPtrVec({}, p1, packs...) {} std::vector vec; }; template struct StreamRefToPtrVec { StreamRefToPtrVec(std::vector _vec, Pack& p1) : vec(_vec) { static_assert(std::is_base_of::value); vec.push_back(&p1); } StreamRefToPtrVec(Pack& p1) : StreamRefToPtrVec({}, p1) {} std::vector vec; }; template class DebugLogger : public LoggerBase>{ using StreamType = std::vector; using LoggerType = LT; using Base = LoggerBase; public: template DebugLogger(ST&... streams) : _ostream(StreamRefToPtrVec(streams...).vec) {} ~DebugLogger() { type_ptr->stop(); } void log(const std::string& msg, const uint8_t& lvl=0xFF) { type_ptr->push(LogEvent{ std::chrono::system_clock::now(), lvl, msg, std::this_thread::get_id(), GetPID(), }); } template void log(char const(&msg) [N], const uint8_t& lvl=0xFF) { type_ptr->log(std::string(msg), lvl); } void log(const std::exception& err, const uint8_t& lvl=0xFF) { type_ptr->log(err.what(), lvl); } template void warn(const U& val, const uint8_t& lvl=0x01) { type_ptr->log(val, lvl); } template void error(const U& val) { type_ptr->log(val, 0xFF); } protected: std::vector _ostream; private: LoggerType* type_ptr = static_cast(this); }; class DefaultDebugLogger : public DebugLogger { using LoggerType = DefaultDebugLogger; using Base = DebugLogger; public: using Base::Base; ~DefaultDebugLogger() { stop(); } friend class BufferedDataProcessor, DefaultDebugLogger>; protected: using Base::_ostream; bool process(const LogEvent& msg) { for (const auto os : this->_ostream) { (*os) << msg.pid << " - " << msg.tid << " : " << msg.msg << "\n"; } return true; } }; /* class BasicLogger : public LoggerBase { public: using Base = LoggerBase; BasicLogger(std::ostream& stream) : Base(stream) {} virtual void process(const LogEvent& event) { *_ostreams[0] << event.msg << "\n"; } }; */ } // namespace nb #endif // _NB_LOGGER