#pragma once #ifndef _NB_LOGGER #define _NB_LOGGER #include #include #include #include #include #ifndef THROW_WITH_INFO #ifdef CODE_ERROR_LOCATIONS #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) #else #define THROW_WITH_INFO(type, ...) throw type(__VA_ARGS__) #endif // CODE_ERROR_LOCATIONS #endif // THROW_WITH_INFO #ifndef THROW #ifdef LOGGING #define THROW_WTIH_INFO(type, ...) throw type(__VA_ARGS__, __LINE__, __FILE__) #else #define THROW(...) THROW_WITH_INFO(__VA_ARGS__) #endif // LOGGING #endif // THROW #include "DataSink.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" #include "TypeTraits.hpp" namespace nb { 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 (!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); }; struct LogEvent{ const LoggerTimePoint time; const unsigned char lvl; const std::string msg; const std::thread::id tid; const uint64_t pid; }; 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() { 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(prepend_strblock(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; 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) { for (const auto os : this->_ostream) { *os << msg.lvl << "\t|\t" << msg.msg << "\n"; } return true; } }; extern DefaultDebugLogger logger; // Taking Charge of Adult ADHD by Russell Barkley } // namespace nb #endif // _NB_LOGGER