#ifndef NEWSBOAT_LOGGER_H_ #define NEWSBOAT_LOGGER_H_ #include #include #include #include namespace newsboat { /* Be sure to update loglevel_str array in src/logger.cpp if you change this * enum. */ enum class level { NONE = 0, USERERROR, CRITICAL, ERROR, WARN, INFO, DEBUG }; class logger { public: static logger &getInstance(); void set_logfile(const std::string& logfile); void set_errorlogfile(const std::string& logfile); void set_loglevel(level l); template void log(level l, const std::string& format, Args... args) { const char * loglevel_str[] = { "NONE", "USERERROR", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG" }; /* * This function checks the loglevel, creates the error message, and then * writes it to the debug logfile and to the error logfile (if applicable). */ std::lock_guard lock(logMutex); if (l <= curlevel && curlevel > level::NONE && (f.is_open() || ef.is_open())) { if (curlevel > level::DEBUG) curlevel = level::DEBUG; char date[128]; time_t t = time(nullptr); struct tm * stm = localtime(&t); strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", stm); auto logmsgbuf = strprintf::fmt(format, args...); auto buf = strprintf::fmt("[%s] %s: %s", date, loglevel_str[static_cast(l)], logmsgbuf); if (f.is_open()) { f << buf << std::endl; } if (level::USERERROR == l && ef.is_open()) { buf = strprintf::fmt("[%s] %s", date, logmsgbuf); ef << buf << std::endl; ef.flush(); } } } private: logger(); logger(const logger &) {} logger& operator=(const logger &) { return *this; } ~logger() { } level curlevel; std::mutex logMutex; static std::mutex instanceMutex; std::fstream f; std::fstream ef; }; } // see http://kernelnewbies.org/FAQ/DoWhile0 #ifdef NDEBUG #define LOG(x, ...) do { } while(0) #else #define LOG(x, ...) do { logger::getInstance().log(x, __VA_ARGS__); } while(0) #endif #endif /* NEWSBOAT_LOGGER_H_ */