#ifndef BELL_LOGGER_H #define BELL_LOGGER_H #include // for va_end, va_list, va_start #include // for printf, vprintf #include #include #include #include // for string, basic_string namespace bell { class AbstractLogger { public: bool enableSubmodule = false; bool enableTimestamp = false; virtual void debug(std::string filename, int line, std::string submodule, const char* format, ...) = 0; virtual void error(std::string filename, int line, std::string submodule, const char* format, ...) = 0; virtual void info(std::string filename, int line, std::string submodule, const char* format, ...) = 0; }; extern bell::AbstractLogger* bellGlobalLogger; class BellLogger : public bell::AbstractLogger { public: // static bool enableColors = true; void debug(std::string filename, int line, std::string submodule, const char* format, ...) { printTimestamp(); printf(colorRed); printf("D "); if (enableSubmodule) { printf(colorReset); printf("[%s] ", submodule.c_str()); } printFilename(filename); printf(":%d: ", line); va_list args; va_start(args, format); vprintf(format, args); va_end(args); printf("\n"); }; void error(std::string filename, int line, std::string submodule, const char* format, ...) { printTimestamp(); printf(colorRed); printf("E "); if (enableSubmodule) { printf(colorReset); printf("[%s] ", submodule.c_str()); } printFilename(filename); printf(":%d: ", line); printf(colorRed); va_list args; va_start(args, format); vprintf(format, args); va_end(args); printf("\n"); }; void info(std::string filename, int line, std::string submodule, const char* format, ...) { printTimestamp(); printf(colorBlue); printf("I "); if (enableSubmodule) { printf(colorReset); printf("[%s] ", submodule.c_str()); } printFilename(filename); printf(":%d: ", line); printf(colorReset); va_list args; va_start(args, format); vprintf(format, args); va_end(args); printf("\n"); }; void printTimestamp() { if (enableTimestamp) { auto now = std::chrono::system_clock::now(); time_t now_time = std::chrono::system_clock::to_time_t(now); const auto nowMs = std::chrono::duration_cast( now.time_since_epoch()) % 1000; auto gmt_time = gmtime(&now_time); printf(colorReset); std::cout << std::put_time(gmt_time, "[%Y-%m-%d %H:%M:%S") << '.' << std::setfill('0') << std::setw(3) << nowMs.count() << "] "; } } void printFilename(std::string filename) { #ifdef _WIN32 std::string basenameStr(filename.substr(filename.rfind("\\") + 1)); #else std::string basenameStr(filename.substr(filename.rfind("/") + 1)); #endif unsigned long hash = 5381; for (char const& c : basenameStr) { hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ } printf("\033[0;%dm", allColors[hash % NColors]); printf("%s", basenameStr.c_str()); printf(colorReset); } private: static constexpr const char* colorReset = "\033[0m"; static constexpr const char* colorRed = "\033[0;31m"; static constexpr const char* colorBlue = "\033[0;34m"; static constexpr const int NColors = 15; static constexpr int allColors[NColors] = {31, 32, 33, 34, 35, 36, 37, 90, 91, 92, 93, 94, 95, 96, 97}; }; void setDefaultLogger(); void enableSubmoduleLogging(); void enableTimestampLogging(); } // namespace bell #define BELL_LOG(type, ...) \ do { \ bell::bellGlobalLogger->type(__FILE__, __LINE__, __VA_ARGS__); \ } while (0) #endif