#include "Logger.hpp" #include "Register.hpp" #include "Core.hpp" // ------------------------------------------------------------------------------------------------ #include #include #include // ------------------------------------------------------------------------------------------------ #include // ------------------------------------------------------------------------------------------------ namespace { #ifdef SQMOD_OS_WINDOWS #include enum { LOG_COLOR_NORMAL = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, LOG_COLOR_WHITE = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, LOG_COLOR_GRAY = FOREGROUND_INTENSITY, LOG_COLOR_LIGHT_BLUE = FOREGROUND_INTENSITY | FOREGROUND_BLUE, LOG_COLOR_DARK_BLUE = FOREGROUND_BLUE, LOG_COLOR_LIGHT_GREEN = FOREGROUND_INTENSITY | FOREGROUND_GREEN, LOG_COLOR_DARK_GREEN = FOREGROUND_GREEN, LOG_COLOR_LIGHT_CYAN = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE, LOG_COLOR_DARK_CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE, LOG_COLOR_LIGHT_YELLOW = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN, LOG_COLOR_DARK_YELLOW = FOREGROUND_RED | FOREGROUND_GREEN, LOG_COLOR_LIGHT_RED = FOREGROUND_INTENSITY | FOREGROUND_RED, LOG_COLOR_DARK_RED = FOREGROUND_RED, LOG_COLOR_LIGHT_MAGENTA = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE, LOG_COLOR_DARK_MAGENTA = FOREGROUND_RED | FOREGROUND_BLUE }; enum { LOG_COLOR_DBG = LOG_COLOR_LIGHT_BLUE, LOG_COLOR_MSG = LOG_COLOR_GRAY, LOG_COLOR_SCS = LOG_COLOR_LIGHT_GREEN, LOG_COLOR_INF = LOG_COLOR_LIGHT_CYAN, LOG_COLOR_WRN = LOG_COLOR_LIGHT_YELLOW, LOG_COLOR_ERR = LOG_COLOR_LIGHT_MAGENTA, LOG_COLOR_FTL = LOG_COLOR_LIGHT_RED }; #endif // SQMOD_OS_WINDOWS } // Namespace:: // ------------------------------------------------------------------------------------------------ namespace SqMod { // ------------------------------------------------------------------------------------------------ const Logger::Pointer _Log = Logger::Inst(); // ------------------------------------------------------------------------------------------------ inline const char * GetLevelTag(Uint8 type) { switch (type) { case Logger::LEVEL_DBG: return "[DBG]"; case Logger::LEVEL_MSG: return "[MSG]"; case Logger::LEVEL_SCS: return "[SCS]"; case Logger::LEVEL_INF: return "[INF]"; case Logger::LEVEL_WRN: return "[WRN]"; case Logger::LEVEL_ERR: return "[ERR]"; case Logger::LEVEL_FTL: return "[FTL]"; default: return "[UNK]"; } } #ifdef SQMOD_OS_WINDOWS // ------------------------------------------------------------------------------------------------ inline Uint16 GetLevelColor(Uint8 type) { switch (type) { case Logger::LEVEL_DBG: return LOG_COLOR_DBG; case Logger::LEVEL_MSG: return LOG_COLOR_MSG; case Logger::LEVEL_SCS: return LOG_COLOR_SCS; case Logger::LEVEL_INF: return LOG_COLOR_INF; case Logger::LEVEL_WRN: return LOG_COLOR_WRN; case Logger::LEVEL_ERR: return LOG_COLOR_ERR; case Logger::LEVEL_FTL: return LOG_COLOR_FTL; default: return LOG_COLOR_NORMAL; } } #else // ------------------------------------------------------------------------------------------------ inline const char * GetLevelColor(Uint8 type) { return ""; } #endif // SQMOD_OS_WINDOWS // ------------------------------------------------------------------------------------------------ Logger::Logger() : m_ConsoleTime(false), m_FileTime(true) , m_ConsoleLevels(Logger::LEVEL_ANY), m_FileLevels(Logger::LEVEL_ANY) , m_LogPath("./logs/"), m_DebugLevel(SQMOD_DEBUG_LEVEL), m_Verbosity(0) { } // ------------------------------------------------------------------------------------------------ Logger::~Logger() { } // ------------------------------------------------------------------------------------------------ void Logger::_Finalizer(Logger * ptr) { if (ptr) delete ptr; } // ------------------------------------------------------------------------------------------------ Logger::Pointer Logger::Inst() { if (!_Log) return Pointer(new Logger(), &Logger::_Finalizer); return Pointer(nullptr, &Logger::_Finalizer); } // ------------------------------------------------------------------------------------------------ bool Logger::Init() { return true; } bool Logger::Load() { return true; } // ------------------------------------------------------------------------------------------------ void Logger::Deinit() { } void Logger::Unload() { } // ------------------------------------------------------------------------------------------------ void Logger::Terminate() { } // ------------------------------------------------------------------------------------------------ void Logger::ToggleConsoleTime(bool enabled) { m_ConsoleTime = enabled; } void Logger::ToggleFileTime(bool enabled) { m_FileTime = enabled; } // ------------------------------------------------------------------------------------------------ bool Logger::HasConsoleTime() const { return m_ConsoleTime; } bool Logger::HasFileTime()const { return m_FileTime; } // ------------------------------------------------------------------------------------------------ void Logger::SetConsoleLevels(Uint8 levels) { m_ConsoleLevels = levels; } void Logger::SetFileLevels(Uint8 levels) { m_FileLevels = levels; } // ------------------------------------------------------------------------------------------------ Uint8 Logger::GetConsoleLevels() const { return m_ConsoleLevels; } Uint8 Logger::GetFileLevels() const { return m_FileLevels; } // ------------------------------------------------------------------------------------------------ void Logger::EnableConsoleLevel(Uint8 level) { m_ConsoleLevels |= level; } void Logger::EnableFileLevel(Uint8 level) { m_FileLevels |= level; } // ------------------------------------------------------------------------------------------------ void Logger::DisableConsoleLevel(Uint8 level) { if (m_ConsoleLevels & level) m_ConsoleLevels ^= level; } void Logger::DisableFileLevel(Uint8 level) { if (m_FileLevels & level) m_FileLevels ^= level; } // ------------------------------------------------------------------------------------------------ Uint8 Logger::GetDebugLevel() const { return m_DebugLevel; } void Logger::SetDebugLevel(Uint8 level) { m_DebugLevel = level; } // ------------------------------------------------------------------------------------------------ SQInt32 Logger::GetVerbosity() const { return m_Verbosity; } void Logger::SetVerbosity(SQInt32 level) { m_Verbosity = level; } // ------------------------------------------------------------------------------------------------ void Logger::Send(Uint8 type, bool sub, const char * fmt, va_list args) { // Verify that this level is allowed to be streamed if (!(m_ConsoleLevels & type) && !(m_FileLevels & type)) return; // Allocate space for the time stamp string char timebuff[80]; // Grab the local time into a string if required if (m_ConsoleTime || m_FileTime) { // Create the variables required to retrieve the time. time_t rawtime; struct tm * timeinfo; // Retrieve the local time. time(&rawtime); timeinfo = localtime(&rawtime); // Format the retrieved time. strftime(timebuff, 80, "%Y-%m-%d %H:%M:%S", timeinfo); } // Output to console if streaming to console is enabled if (m_ConsoleLevels & type) { #ifdef SQMOD_OS_WINDOWS // Get the handle to the output stream HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE); // Save the current state of the console screen buffer CONSOLE_SCREEN_BUFFER_INFO csb_state; GetConsoleScreenBufferInfo(hstdout, &csb_state); // Set the attributes for the message information SetConsoleTextAttribute(hstdout, GetLevelColor(type)); // Output the message information if (m_ConsoleTime) { printf("%s %s ", GetLevelTag(type), timebuff); } else { printf("%s ", GetLevelTag(type)); } // Set the attributes for the message content SetConsoleTextAttribute(hstdout, sub ? LOG_COLOR_NORMAL : LOG_COLOR_WHITE); // Print the specified message vprintf(fmt, args); // Restore the state of the console screen buffer SetConsoleTextAttribute(hstdout, csb_state.wAttributes); #else // Output the message information if (m_ConsoleTime) { printf("%s %s ", GetLevelTag(type), timebuff); } else { printf("%s ", GetLevelTag(type)); } // Print the specified message vprintf(fmt, args); #endif // SQMOD_OS_WINDOWS // Terminate the line puts(""); } } // ------------------------------------------------------------------------------------------------ void Logger::Message(Uint8 type, bool sub, const char * fmt, ...) { va_list args; va_start(args, fmt); Send(type, sub, fmt, args); va_end(args); } // ------------------------------------------------------------------------------------------------ #define SQMOD_LOG(N_, L_, S_) /* */ void Logger::N_(const char * fmt, ...) /* */ { /* */ va_list args; /* */ va_start(args, fmt); /* */ Send(L_, S_, fmt, args); /* */ va_end(args); /* */ } /* */ // ------------------------------------------------------------------------------------------------ SQMOD_LOG(Dbg, LEVEL_DBG, false) SQMOD_LOG(Msg, LEVEL_MSG, false) SQMOD_LOG(Scs, LEVEL_SCS, false) SQMOD_LOG(Inf, LEVEL_INF, false) SQMOD_LOG(Wrn, LEVEL_WRN, false) SQMOD_LOG(Err, LEVEL_ERR, false) SQMOD_LOG(Ftl, LEVEL_FTL, false) // ------------------------------------------------------------------------------------------------ SQMOD_LOG(SDbg, LEVEL_DBG, true) SQMOD_LOG(SMsg, LEVEL_MSG, true) SQMOD_LOG(SScs, LEVEL_SCS, true) SQMOD_LOG(SInf, LEVEL_INF, true) SQMOD_LOG(SWrn, LEVEL_WRN, true) SQMOD_LOG(SErr, LEVEL_ERR, true) SQMOD_LOG(SFtl, LEVEL_FTL, true) // ------------------------------------------------------------------------------------------------ #define SQMOD_CLOG(N_, L_, S_) /* */bool Logger::N_(bool c, const char * fmt, ...) /* */ { /* */ if (c) /* */ { /* */ va_list args; /* */ va_start(args, fmt); /* */ Send(L_, S_, fmt, args); /* */ va_end(args); /* */ } /* */ return c; /* */ } /* */ // ------------------------------------------------------------------------------------------------ SQMOD_CLOG(cDbg, LEVEL_DBG, false) SQMOD_CLOG(cMsg, LEVEL_MSG, false) SQMOD_CLOG(cScs, LEVEL_SCS, false) SQMOD_CLOG(cInf, LEVEL_INF, false) SQMOD_CLOG(cWrn, LEVEL_WRN, false) SQMOD_CLOG(cErr, LEVEL_ERR, false) SQMOD_CLOG(cFtl, LEVEL_FTL, false) // ------------------------------------------------------------------------------------------------ SQMOD_CLOG(cSDbg, LEVEL_DBG, true) SQMOD_CLOG(cSMsg, LEVEL_MSG, true) SQMOD_CLOG(cSScs, LEVEL_SCS, true) SQMOD_CLOG(cSInf, LEVEL_INF, true) SQMOD_CLOG(cSWrn, LEVEL_WRN, true) SQMOD_CLOG(cSErr, LEVEL_ERR, true) SQMOD_CLOG(cSFtl, LEVEL_FTL, true) // ------------------------------------------------------------------------------------------------ template < Uint8 L, bool S > static SQInteger LogBasicMessage(HSQUIRRELVM vm) { const SQInteger top = sq_gettop(vm); // Are there any arguments on the stack? if (top <= 1) { _Log->Err("Attempting to without specifying a value"); } // Is there a single string or at least something that can convert to a string on the stack? else if (top == 2 && ((sq_gettype(vm, -1) == OT_STRING) || !SQ_FAILED(sq_tostring(vm, -1)))) { // Variable where the resulted string will be retrieved const SQChar * msg = 0; // Attempt to retrieve the specified message from the stack if (SQ_FAILED(sq_getstring(vm, -1, &msg))) { _Log->Err("Unable to from the stack"); // Pop any pushed values pushed to the stack sq_settop(vm, top); // Failed to log the value return 0; } // Pop any pushed values pushed to the stack sq_settop(vm, top); // Log the specified string _Log->Message(L, S, "%s", msg); } else if (top > 2) { // Variables containing the resulted string SQChar * msg = NULL; SQInteger len = 0; // Attempt to call the format function with the passed arguments if (SQ_FAILED(sqstd_format(vm, 2, &len, &msg))) { _Log->Err("Unable to because : %s", Error::Message(vm).c_str()); // Failed to log the value return 0; } // Log the resulted string _Log->Message(L, S, "%s", msg); } else { _Log->Err("Unable to from the specified value"); } // At this point everything went correctly return 0; } // ================================================================================================ bool Register_Log(HSQUIRRELVM vm) { // // Attempt to create the Log namespace Sqrat::Table logns(vm); // Output debugging information LogDbg("Beginning registration of type"); // Attempt to register the free functions logns.SquirrelFunc(_SC("Dbg"), &LogBasicMessage< Logger::LEVEL_DBG, false >); logns.SquirrelFunc(_SC("Msg"), &LogBasicMessage< Logger::LEVEL_MSG, false >); logns.SquirrelFunc(_SC("Scs"), &LogBasicMessage< Logger::LEVEL_SCS, false >); logns.SquirrelFunc(_SC("Inf"), &LogBasicMessage< Logger::LEVEL_INF, false >); logns.SquirrelFunc(_SC("Wrn"), &LogBasicMessage< Logger::LEVEL_WRN, false >); logns.SquirrelFunc(_SC("Err"), &LogBasicMessage< Logger::LEVEL_ERR, false >); logns.SquirrelFunc(_SC("Ftl"), &LogBasicMessage< Logger::LEVEL_FTL, false >); logns.SquirrelFunc(_SC("SDbg"), &LogBasicMessage< Logger::LEVEL_DBG, true >); logns.SquirrelFunc(_SC("SMsg"), &LogBasicMessage< Logger::LEVEL_MSG, true >); logns.SquirrelFunc(_SC("SScs"), &LogBasicMessage< Logger::LEVEL_SCS, true >); logns.SquirrelFunc(_SC("SInf"), &LogBasicMessage< Logger::LEVEL_INF, true >); logns.SquirrelFunc(_SC("SWrn"), &LogBasicMessage< Logger::LEVEL_WRN, true >); logns.SquirrelFunc(_SC("SErr"), &LogBasicMessage< Logger::LEVEL_ERR, true >); logns.SquirrelFunc(_SC("SFtl"), &LogBasicMessage< Logger::LEVEL_FTL, true >); // Output debugging information LogDbg("Registration of type was successful"); // Attempt to bind the namespace to the root table Sqrat::RootTable(vm).Bind(_SC("Log"), logns); // Registration succeeded return true; } } // Namespace:: SqMod