#ifndef _LOGGER_H_ #define _LOGGER_H_ #include "log_queue.h" #include #include #include #include #include #include #include enum class log_type { std_output, file }; class logger { private: std::atomic _enabled; std::stringstream _logLine; std::ofstream _outFile; log_queue _queue; log_type _type; public: logger(); logger(std::string path); void set_enabled(bool enabled); template void log_info(const char* s, const Args&... args) { log("info", s, args...); } template void log_warning(const char* s, const Args&... args) { log("warning", s, args...); } template void log_error(const char* s, const Args&... args) { log("error", s, args...); } private: template void log(const char* log_level, const char* s, const Args&... args) { if (_enabled) { auto hrc = std::chrono::high_resolution_clock::now(); auto sc = std::chrono::system_clock::now(); _queue.add_log([this, s, args..., sc, hrc, log_level]{ _logLine.str(""); //_logLine << "[" << hrc.time_since_epoch().count() << "] "; char tm_buffer[50]; std::time_t tm = std::chrono::system_clock::to_time_t(sc); std::strftime(tm_buffer, 50, "%F %T", std::localtime(&tm)); _logLine << "[" << tm_buffer << "] "; _logLine << "[" << log_level << "] "; form_log_line(s, args...); switch(_type) { case log_type::std_output: std::cout << _logLine.str() << std::endl; break; case log_type::file: _outFile << _logLine.str() << std::endl; break; } }); } } void form_log_line(const char* s); template void form_log_line(const char* s, const T& value, const Args&... args) { while (*s) { if (*s == '%' && *++s != '%') { _logLine << value; return form_log_line(s, args...); } _logLine << *s++; } throw std::runtime_error("extra arguments provided"); } }; extern logger ulog; #endif // _LOGGER_H_