#pragma once #ifndef _NB_LOGGER #define _NB_LOGGER #include #include #include #include #include #include "DataSink.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" #include "TypeTraits.hpp" namespace nb { template class ErrorBase; typedef std::chrono::time_point< std::chrono::system_clock, std::chrono::nanoseconds > LoggerTimePoint; 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() override { if (!static_cast(this)->isRunning()) { this->_running = true; this->_runningThread = std::make_shared([&]{ while(static_cast(this)->isRunning()) { static_cast(this)->flush(); } static_cast(this)->flush(); }); } return static_cast(this)->isRunning(); } protected: LoggerBase() = default; StreamType _ostream; }; struct LogEvent{ const LoggerTimePoint time; const unsigned char lvl; const std::string msg; const std::thread::id tid; const uint64_t pid; const std::string file=""; const unsigned int line=0; }; template class DebugLogger : public LoggerBase>{ using StreamType = std::vector; using LoggerType = LT; using Base = LoggerBase; public: template DebugLogger(ST&... streams) : _ostream(nb::RefPackToPtrVec(streams...).vec) {} ~DebugLogger() { static_cast(this)->stop(); } void log( std::string msg, uint8_t lvl=0x00, std::string file="", unsigned int line=0 ) { static_cast(this)->push(LogEvent{ std::chrono::system_clock::now(), lvl, msg, std::this_thread::get_id(), GetPID(), file, line }); } template void log( char const(&msg) [N], uint8_t lvl=0x00, std::string file="", unsigned int line=0 ) { static_cast(this)->log(std::string(msg), lvl, file, line); } template void log( const ErrorBase& err, uint8_t lvl=0xFF, std::string file="", unsigned int line=0 ) { static_cast(this)->log(err.what(), lvl, file, line); } template std::enable_if_t, void> log( const T& err, uint8_t lvl=0xFF, std::string file="", unsigned int line=0 ) { static_cast(this)->log(std::string(err.what()), lvl, file, line); } template void warn( U val, uint8_t lvl=0x01, std::string file="", unsigned int line=0 ) { static_cast(this)->log(val, lvl, file, line); } template void error( U val, std::string file="", unsigned int line=0 ) { static_cast(this)->log(val, 0xFF, file, line); static_cast(this)->flush(); } protected: std::vector _ostream; }; class DefaultDebugLogger : public DebugLogger { using LoggerType = DefaultDebugLogger; using Base = DebugLogger; template struct LogRow; public: using Base::Base; ~DefaultDebugLogger() { stop(); } friend class BufferedDataProcessor, DefaultDebugLogger>; template friend STR& operator<<(STR&, const DefaultDebugLogger::LogRow&); protected: using Base::_ostream; bool process(const LogEvent& msg); }; #ifndef _NB_NO_LOGGER extern DefaultDebugLogger logger; #endif // _NB_NO_LOGGER // Taking Charge of Adult ADHD by Russell Barkley } // namespace nb #endif // _NB_LOGGER