// (c) 2015 Ralf Ramsauer - Logger class from the sdfs project #include #include #include #include #include #include #include #ifdef _WIN32 #include #endif #include "config.h" #include "logger.h" using std::map; using std::string; using std::mutex; using std::lock_guard; using std::move; using std::cerr; using std::endl; #ifdef USE_COLORIZED_LOGS #ifdef _WIN32 // If Windows, Use Windows Terminal coloring const static map colorAttribute = { {LogLevel::error, FOREGROUND_RED }, {LogLevel::warning, FOREGROUND_RED | FOREGROUND_GREEN }, {LogLevel::notice, FOREGROUND_BLUE }, {LogLevel::info, FOREGROUND_GREEN }, {LogLevel::debug, FOREGROUND_BLUE | FOREGROUND_RED }, {LogLevel::debug2, FOREGROUND_BLUE | FOREGROUND_RED }, }; #else // Use ANSI Escape sequences const static map prefix_ansicolor = { {LogLevel::error, "\x1b[1m\x1b[31m" }, {LogLevel::warning, "\x1b[1m\x1b[33m" }, {LogLevel::notice, "\x1b[1m\x1b[34m" }, {LogLevel::info, "\x1b[1m\x1b[32m" }, {LogLevel::debug, "\x1b[1m\x1b[35m" }, {LogLevel::debug2, "\x1b[1m\x1b[36m" }, }; const static string suffix_ansireset = "\x1b[0m"; #endif #endif const static map logLevel = { {LogLevel::error, "ERROR " }, {LogLevel::warning, "WARNING" }, {LogLevel::notice, "NOTICE " }, {LogLevel::info, "INFO " }, {LogLevel::debug, "DEBUG " }, {LogLevel::debug2, "DEBUG2 " }, }; Logger::Logger(const LogLevel level) : _level(level), _ostreamMutex() { } Logger::~Logger() { } Logger &Logger::get() { static Logger l(DEFAULT_LOG_LEVEL); return l; } void Logger::operator ()(const std::string &message, const LogLevel level) const { if(level > _level) { return; } std::ostringstream prefix; auto t = std::time(nullptr); auto tm = *std::localtime(&t); #if defined(USE_COLORIZED_LOGS) && !defined(_WIN32) prefix << prefix_ansicolor.at(level); #endif // GCC does not support put_time :-( /*stringstream ss; ss << std::put_time(&tm, "%d-%m-%Y %H-%M-%S"); prefix = "[" + ss.str() + "] ";*/ const size_t BUFFER_SIZE = 80; char timeBuffer[BUFFER_SIZE]; std::strftime(timeBuffer, BUFFER_SIZE, "%Y-%m-%d %H:%M:%S", &tm); prefix << "[" << timeBuffer << "] -- " << logLevel.at(level) << " :: "; // Critical section { lock_guard lock(_ostreamMutex); #if defined(USE_COLORIZED_LOGS) && !defined(_WIN32) cerr << prefix.str() << message << suffix_ansireset << endl; cerr.flush(); #elif defined(USE_COLORIZED_LOGS) && defined(_WIN32) // taken from GTEST const HANDLE stdout_handle = GetStdHandle(STD_ERROR_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. cerr.flush(); SetConsoleTextAttribute(stdout_handle, colorAttribute.at(level) | FOREGROUND_INTENSITY); cerr << prefix.str() << message << endl; cerr.flush(); // Restores the text color. SetConsoleTextAttribute(stdout_handle, old_color_attrs); #else cerr << prefix.str() << message << endl; cerr.flush(); #endif } } void Logger::operator ()(const std::ostringstream &message, const LogLevel level) const { (*this)(message.str(), level); } void Logger::operator ()(const LogLevel level, const char* format, ...) const { if(level > _level) { return; } va_list argp; char* message = nullptr; // determine buffer length va_start(argp, format); int size = vsnprintf(nullptr, 0, format, argp) + 1; va_end(argp); if (size >= 0) { message = (char*)malloc(size); if (message == nullptr) { (*this)("[LOGGER] CRITICAL: MEMORY ALLOCATION ERROR", LogLevel::error); } va_start(argp,format); vsnprintf(message, size, format, argp); va_end(argp); (*this)(string(message), level); free(message); } else { (*this)("[LOGGER] CRITICAL: VSNPRINTF ERROR", LogLevel::error); } } void Logger::level(const LogLevel level) { _level = level; } LogLevel Logger::level() const { return _level; } void foo(void) { }