1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 08:47:17 +01:00

Implement logging callbacks to allow sharing of output with other mediums.

This commit is contained in:
Sandu Liviu Catalin 2019-05-01 18:00:24 +03:00
parent 05159b5558
commit b54dd0a0b9
3 changed files with 152 additions and 0 deletions

View File

@ -532,6 +532,8 @@ void Core::Terminate(bool shutdown)
cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins the virtual machine is closing"); cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins the virtual machine is closing");
// Tell modules to do their monkey business // Tell modules to do their monkey business
_Func->SendPluginCommand(SQMOD_CLOSING_CMD, ""); _Func->SendPluginCommand(SQMOD_CLOSING_CMD, "");
// Release any callbacks from the logger
Logger::Get().Release();
// Attempt to close the VM // Attempt to close the VM
sq_close(sq_vm); sq_close(sq_vm);

View File

@ -99,6 +99,24 @@ static inline CCStr GetLevelTag(Uint8 level)
} }
} }
/* ------------------------------------------------------------------------------------------------
* Identify the message prefix.
*/
static inline Uint8 GetLevelIdx(Uint8 level)
{
switch (level)
{
case LOGL_DBG: return 0;
case LOGL_USR: return 1;
case LOGL_SCS: return 2;
case LOGL_INF: return 3;
case LOGL_WRN: return 4;
case LOGL_ERR: return 5;
case LOGL_FTL: return 6;
default: return 0xFF;
}
}
#ifndef SQMOD_OS_WINDOWS #ifndef SQMOD_OS_WINDOWS
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
@ -196,8 +214,10 @@ Logger::Logger()
, m_LogFileLevels(~LOGL_DBG) , m_LogFileLevels(~LOGL_DBG)
, m_ConsoleTime(false) , m_ConsoleTime(false)
, m_LogFileTime(true) , m_LogFileTime(true)
, m_CyclicLock(false)
, m_File(nullptr) , m_File(nullptr)
, m_Filename() , m_Filename()
, m_LogCb{}
{ {
/* ... */ /* ... */
} }
@ -257,6 +277,38 @@ void Logger::SetLogFilename(CCStr filename)
} }
} }
// ------------------------------------------------------------------------------------------------
void Logger::BindCb(Uint8 level, Object & env, Function & func)
{
// Get the index of this log level
const Uint8 idx = GetLevelIdx(level);
// Is the log level valid?
if (idx > 6)
{
STHROWF("Out of range log level index: %d > 4", int(idx));
}
// Obtain the function instance called for this log level
Function & cb = m_LogCb[idx];
// Is the specified callback function null?
if (func.IsNull())
{
cb.ReleaseGently(); // Then release the current callback
}
// Does this function need a custom environment?
else if (env.IsNull())
{
// Use the root table instead
RootTable root(DefaultVM::Get_());
// Bind the root table with the function
cb = Function(env.GetVM(), root, func.GetFunc());
}
// Assign the specified environment and function
else
{
cb = Function(env.GetVM(), env, func.GetFunc());
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Logger::Initialize(CCStr filename) void Logger::Initialize(CCStr filename)
{ {
@ -275,9 +327,71 @@ void Logger::Terminate()
m_Buffer.ResetAll(); m_Buffer.ResetAll();
} }
// ------------------------------------------------------------------------------------------------
void Logger::Release()
{
for (Uint8 i = 0; i < 7; ++i)
{
m_LogCb[i].ReleaseGently();
}
}
// ------------------------------------------------------------------------------------------------
SQBool Logger::ProcessCb(Uint8 level, bool sub)
{
// Get the index of this log level
const Uint8 idx = GetLevelIdx(level);
// Is the log level valid and is there a callback associated?
if (idx > 6 || m_LogCb[idx].IsNull())
{
return SQFalse;
}
// Grab the associated function
Function & fn = m_LogCb[idx];
// Grab the default VM
HSQUIRRELVM vm = DefaultVM::Get_();
// Gram the top of the stack
SQInteger top = sq_gettop(vm);
// Push the function followed by the environment
sq_pushobject(vm, fn.GetFunc());
sq_pushobject(vm, fn.GetEnv());
// Push the log message
sq_pushstring(vm, m_Buffer.Get< SQChar >(), -1);
// Specify whether this is a sub message
sq_pushbool(vm, static_cast< SQBool >(sub));
// Make the function call and store the result
SQRESULT res = sq_call(vm, 3, true, ErrorHandling::IsEnabled());
// Default to non greedy callback
SQBool ret = SQFalse;
// Did the function succeeded and is the returned value not null?
if (SQ_SUCCEEDED(res) && sq_gettype(vm, -1) != OT_NULL) {
// Obtain the returned value
sq_tobool(vm, -1, &ret);
}
// Pop the callback object and return value from the stack
sq_settop(vm, top);
// Return the outcome of this callback
return ret;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Logger::Proccess(Uint8 level, bool sub) void Logger::Proccess(Uint8 level, bool sub)
{ {
// Is there a cyclic lock on the logger?
if (!m_CyclicLock)
{
// Lock the logger to prevent a cyclic dependency
m_CyclicLock = true;
// Attempt to process the script callback first
const bool greedy = ProcessCb(level, sub);
// Unlock the logger after the callback was invoked
m_CyclicLock = false;
// Is the callback for this level greedy?
if (greedy)
{
return;
}
}
// Obtain the time-stamp if necessary // Obtain the time-stamp if necessary
CCStr tms = (m_ConsoleTime || m_LogFileTime) ? GetTimeStampStr() : nullptr; CCStr tms = (m_ConsoleTime || m_LogFileTime) ? GetTimeStampStr() : nullptr;
// Are we allowed to send this message level to console? // Are we allowed to send this message level to console?
@ -551,6 +665,12 @@ template < Uint8 L, bool S > static SQInteger LogBasicMessage(HSQUIRRELVM vm)
return 0; return 0;
} }
// ------------------------------------------------------------------------------------------------
template < Uint8 L > static void BindLogCallback(Object & env, Function & func)
{
Logger::Get().BindCb(L, env, func);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
static void SqLogClose() static void SqLogClose()
{ {
@ -678,6 +798,13 @@ void Register_Log(HSQUIRRELVM vm)
.SquirrelFunc(_SC("SWrn"), &LogBasicMessage< LOGL_WRN, true >) .SquirrelFunc(_SC("SWrn"), &LogBasicMessage< LOGL_WRN, true >)
.SquirrelFunc(_SC("SErr"), &LogBasicMessage< LOGL_ERR, true >) .SquirrelFunc(_SC("SErr"), &LogBasicMessage< LOGL_ERR, true >)
.SquirrelFunc(_SC("SFtl"), &LogBasicMessage< LOGL_FTL, true >) .SquirrelFunc(_SC("SFtl"), &LogBasicMessage< LOGL_FTL, true >)
.Func(_SC("BindDbg"), &BindLogCallback< LOGL_DBG >)
.Func(_SC("BindUsr"), &BindLogCallback< LOGL_USR >)
.Func(_SC("BindScs"), &BindLogCallback< LOGL_SCS >)
.Func(_SC("BindInf"), &BindLogCallback< LOGL_INF >)
.Func(_SC("BindWrn"), &BindLogCallback< LOGL_WRN >)
.Func(_SC("BindErr"), &BindLogCallback< LOGL_ERR >)
.Func(_SC("BindFtl"), &BindLogCallback< LOGL_FTL >)
.Func(_SC("Close"), &SqLogClose) .Func(_SC("Close"), &SqLogClose)
.Func(_SC("Initialize"), &SqLogInitialize) .Func(_SC("Initialize"), &SqLogInitialize)
.Func(_SC("ToggleConsoleTime"), &SqLogToggleConsoleTime) .Func(_SC("ToggleConsoleTime"), &SqLogToggleConsoleTime)

View File

@ -9,6 +9,9 @@
#include <cstdio> #include <cstdio>
#include <string> #include <string>
// ------------------------------------------------------------------------------------------------
#include <sqrat/sqratFunction.h>
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
@ -80,11 +83,15 @@ private:
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
bool m_ConsoleTime; // Whether console messages should be timestamped. bool m_ConsoleTime; // Whether console messages should be timestamped.
bool m_LogFileTime; // Whether log file messages should be timestamped. bool m_LogFileTime; // Whether log file messages should be timestamped.
bool m_CyclicLock; // Prevent the script callback from entering a loop.
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
std::FILE* m_File; // Handle to the file where the logs should be saved. std::FILE* m_File; // Handle to the file where the logs should be saved.
std::string m_Filename; // The name of the file where the logs are saved. std::string m_Filename; // The name of the file where the logs are saved.
// --------------------------------------------------------------------------------------------
Function m_LogCb[7]; //Callback to receive debug information instead of console.
protected: protected:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -117,6 +124,11 @@ public:
*/ */
void Terminate(); void Terminate();
/* --------------------------------------------------------------------------------------------
* Release the script associated resources.
*/
void Release();
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Enable or disable console message time stamping. * Enable or disable console message time stamping.
*/ */
@ -260,6 +272,11 @@ public:
*/ */
void SetLogFilename(CCStr filename); void SetLogFilename(CCStr filename);
/* --------------------------------------------------------------------------------------------
* Bind a script callback to a log level.
*/
void BindCb(Uint8 level, Object & env, Function & func);
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Send a log message. * Send a log message.
*/ */
@ -280,6 +297,12 @@ public:
*/ */
void Debug(CCStr fmt, va_list args); void Debug(CCStr fmt, va_list args);
private:
/* --------------------------------------------------------------------------------------------
* Forward the log message to a callback.
*/
SQBool ProcessCb(Uint8 level, bool sub);
}; };
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------