#ifndef LOGGING_H #define LOGGING_H #include #include #include #include namespace gpu { enum LogLevel { kNone = 0, kError = 1, kWarn = 2, kInfo = 3, kTrace = 4 }; static const char *kLevelStr[] = {"none", "error", "warn", "info", "trace"}; /** * @brief Logger struct for logging messages. * stream: The stream to log to. * level: The log level to log messages at. */ struct Logger { std::ostream &stream; int level; }; template inline std::string toString(const T &value) { std::ostringstream oss; oss << value; return oss.str(); } /** * @brief Log a message to the logger. If NO_LOG is defined in a source or as a * compiler flag, this is a no-op. * * @param logger The logger to log to. * @param level The log level of the message. * @param message The message to log. */ #ifndef NO_LOG template inline void LOG(Logger &logger, int level, const char *message, ...) { static const char *orange = "\033[0;33m"; static const char *red = "\033[0;31m"; static const char *white = "\033[0;37m"; static const char *gray = "\033[0;90m"; static const char *reset = "\033[0m"; static const char *logColors[] = {red, red, orange, gray}; if (level <= logger.level) { va_list args; va_list args2; va_start(args, message); va_copy(args2, args); int size = vsnprintf(nullptr, 0, message, args) + 1; std::unique_ptr buffer(new char[size]); #ifdef _WIN32 _vsnprintf_s(buffer.get(), size, _TRUNCATE, message, args2); #else vsnprintf(buffer.get(), size, message, args2); #endif // Brackets and messages are white. // Log levels are red for error and warning, orange for info, and grey for trace. // Then the color is reset. logger.stream << white << "[" << logColors[level] << kLevelStr[level] << white << "] "; logger.stream << buffer.get(); logger.stream << reset << std::endl; va_end(args); va_end(args2); } } #else template inline void LOG(Logger &logger, int level, const char *message, Args... args) { (void)logger; (void)level; (void)message; (void)(std::initializer_list{(static_cast(args), 0)...}); } #endif /** * @brief Default logger for logging messages to stdout at the info level. * Output stream and logging level for the default logger can be globally * changed on a per-program basis. */ static Logger kDefLog = {std::cout, kInfo}; /** * @brief Set the log level of the default logger. * @param level The log level to set. */ static inline void setLogLevel(int level) { kDefLog.level = level; } } // namespace gpu #endif