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");
|
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);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user