#pragma once #include #include #include #include #include #include "common.hpp" #include "settings.hpp" #ifndef STDOUT_FILENO #define STDOUT_FILENO 1 #endif #ifndef STDERR_FILENO #define STDERR_FILENO 2 #endif POLYBAR_NS enum class loglevel { NONE = 0, ERROR, WARNING, NOTICE, INFO, TRACE, }; class logger { public: using make_type = const logger&; static make_type make(loglevel level = loglevel::NONE); explicit logger(loglevel level); static loglevel parse_verbosity(const string& name, loglevel fallback = loglevel::NONE); void verbosity(loglevel level); #ifdef DEBUG_LOGGER // {{{ template void trace(const string& message, Args&&... args) const { output(loglevel::TRACE, message, std::forward(args)...); } #ifdef DEBUG_LOGGER_VERBOSE template void trace_x(const string& message, Args&&... args) const { output(loglevel::TRACE, message, std::forward(args)...); } #else template void trace_x(Args&&...) const {} #endif #else template void trace(Args&&...) const {} template void trace_x(Args&&...) const {} #endif // }}} /** * Output an info message */ template void info(const string& message, Args&&... args) const { output(loglevel::INFO, message, std::forward(args)...); } /** * Output a notice */ template void notice(const string& message, Args&&... args) const { output(loglevel::NOTICE, message, std::forward(args)...); } /** * Output a warning message */ template void warn(const string& message, Args&&... args) const { output(loglevel::WARNING, message, std::forward(args)...); } /** * Output an error message */ template void err(const string& message, Args&&... args) const { output(loglevel::ERROR, message, std::forward(args)...); } protected: template decltype(auto) convert(T&& arg) const { return forward(arg); } /** * Convert string */ const char* convert(string& arg) const; const char* convert(const string& arg) const; /** * Convert thread id */ size_t convert(std::thread::id arg) const; /** * Write the log message to the output channel * if the defined verbosity level allows it */ template void output(loglevel level, const string& format, Args&&... values) const { if (level > m_level) { return; } #if defined(__clang__) // {{{ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wformat-security" #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-security" #endif // }}} dprintf(m_fd, (m_prefixes.at(level) + format + m_suffixes.at(level) + "\n").c_str(), convert(values)...); #if defined(__clang__) // {{{ #pragma clang diagnostic pop #elif defined(__GNUC__) #pragma GCC diagnostic pop #endif // }}} } private: /** * Logger verbosity level */ loglevel m_level{loglevel::TRACE}; /** * File descriptor used when writing the log messages */ int m_fd{STDERR_FILENO}; /** * Loglevel specific prefixes */ std::map m_prefixes; /** * Loglevel specific suffixes */ std::map m_suffixes; }; POLYBAR_NS_END