mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
Implement logging callbacks to allow sharing of output with other mediums.
This commit is contained in:
parent
05159b5558
commit
b54dd0a0b9
@ -532,6 +532,8 @@ void Core::Terminate(bool shutdown)
|
||||
cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins the virtual machine is closing");
|
||||
// Tell modules to do their monkey business
|
||||
_Func->SendPluginCommand(SQMOD_CLOSING_CMD, "");
|
||||
// Release any callbacks from the logger
|
||||
Logger::Get().Release();
|
||||
// Attempt to close the VM
|
||||
sq_close(sq_vm);
|
||||
|
||||
|
@ -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
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
@ -196,8 +214,10 @@ Logger::Logger()
|
||||
, m_LogFileLevels(~LOGL_DBG)
|
||||
, m_ConsoleTime(false)
|
||||
, m_LogFileTime(true)
|
||||
, m_CyclicLock(false)
|
||||
, m_File(nullptr)
|
||||
, 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)
|
||||
{
|
||||
@ -275,9 +327,71 @@ void Logger::Terminate()
|
||||
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)
|
||||
{
|
||||
// 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
|
||||
CCStr tms = (m_ConsoleTime || m_LogFileTime) ? GetTimeStampStr() : nullptr;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template < Uint8 L > static void BindLogCallback(Object & env, Function & func)
|
||||
{
|
||||
Logger::Get().BindCb(L, env, func);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void SqLogClose()
|
||||
{
|
||||
@ -678,6 +798,13 @@ void Register_Log(HSQUIRRELVM vm)
|
||||
.SquirrelFunc(_SC("SWrn"), &LogBasicMessage< LOGL_WRN, true >)
|
||||
.SquirrelFunc(_SC("SErr"), &LogBasicMessage< LOGL_ERR, 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("Initialize"), &SqLogInitialize)
|
||||
.Func(_SC("ToggleConsoleTime"), &SqLogToggleConsoleTime)
|
||||
|
@ -9,6 +9,9 @@
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <sqrat/sqratFunction.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
@ -80,11 +83,15 @@ private:
|
||||
// --------------------------------------------------------------------------------------------
|
||||
bool m_ConsoleTime; // Whether console 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::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:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@ -117,6 +124,11 @@ public:
|
||||
*/
|
||||
void Terminate();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release the script associated resources.
|
||||
*/
|
||||
void Release();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Enable or disable console message time stamping.
|
||||
*/
|
||||
@ -260,6 +272,11 @@ public:
|
||||
*/
|
||||
void SetLogFilename(CCStr filename);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Bind a script callback to a log level.
|
||||
*/
|
||||
void BindCb(Uint8 level, Object & env, Function & func);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Send a log message.
|
||||
*/
|
||||
@ -280,6 +297,12 @@ public:
|
||||
*/
|
||||
void Debug(CCStr fmt, va_list args);
|
||||
|
||||
private:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Forward the log message to a callback.
|
||||
*/
|
||||
SQBool ProcessCb(Uint8 level, bool sub);
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user