211 lines
6.1 KiB
C++
211 lines
6.1 KiB
C++
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
|
|
|
#include "DebugLog.h"
|
|
#include "Engine/Core/Log.h"
|
|
#include "Engine/Scripting/InternalCalls.h"
|
|
#include "Engine/Scripting/ScriptingObject.h"
|
|
#include "Engine/Scripting/MException.h"
|
|
#include "Engine/Scripting/Scripting.h"
|
|
#include "Engine/Scripting/ScriptingType.h"
|
|
#include "Engine/Scripting/BinaryModule.h"
|
|
#include "Engine/Scripting/MainThreadManagedInvokeAction.h"
|
|
#include "Engine/Scripting/ManagedCLR/MDomain.h"
|
|
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
|
|
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
|
#include "FlaxEngine.Gen.h"
|
|
#include <ThirdParty/mono-2.0/mono/metadata/exception.h>
|
|
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
|
|
|
namespace DebugLogHandlerInternal
|
|
{
|
|
void LogWrite(LogType level, MonoString* msgObj)
|
|
{
|
|
StringView msg;
|
|
MUtils::ToString(msgObj, msg);
|
|
Log::Logger::Write(level, msg);
|
|
}
|
|
|
|
void Log(LogType level, MonoString* msgObj, ScriptingObject* obj, MonoString* stackTrace)
|
|
{
|
|
if (msgObj == nullptr)
|
|
return;
|
|
|
|
// Get info
|
|
StringView msg;
|
|
MUtils::ToString(msgObj, msg);
|
|
//const String objName = obj ? obj->ToString() : String::Empty;
|
|
|
|
// Send event
|
|
// TODO: maybe option for build to threat warnings and errors as fatal errors?
|
|
//const String logMessage = String::Format(TEXT("Debug:{1} {2}"), objName, *msg);
|
|
Log::Logger::Write(level, msg);
|
|
}
|
|
|
|
void LogException(MonoException* exception, ScriptingObject* obj)
|
|
{
|
|
if (exception == nullptr)
|
|
return;
|
|
|
|
// Get info
|
|
MException ex(exception);
|
|
String objName = obj ? obj->ToString() : String::Empty;
|
|
|
|
// Print exception including inner exceptions
|
|
// TODO: maybe option for build to threat warnings and errors as fatal errors?
|
|
ex.Log(LogType::Warning, objName.GetText());
|
|
}
|
|
}
|
|
|
|
namespace FlaxLogWriterInternal
|
|
{
|
|
void WriteStringToLog(MonoString* msg)
|
|
{
|
|
if (msg == nullptr)
|
|
return;
|
|
|
|
auto msgStr = (Char*)mono_string_to_utf16(msg);
|
|
LOG_STR(Info, msgStr);
|
|
}
|
|
}
|
|
|
|
void DebugLog::RegisterInternalCalls()
|
|
{
|
|
// DebugLogHandler
|
|
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogWrite", &DebugLogHandlerInternal::LogWrite);
|
|
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_Log", &DebugLogHandlerInternal::Log);
|
|
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogException", &DebugLogHandlerInternal::LogException);
|
|
|
|
// FlaxLogWriter
|
|
ADD_INTERNAL_CALL("FlaxEngine.FlaxLogWriter::Internal_WriteStringToLog", &FlaxLogWriterInternal::WriteStringToLog);
|
|
}
|
|
|
|
namespace DebugLogImpl
|
|
{
|
|
MMethod* Internal_SendLog = nullptr;
|
|
MMethod* Internal_SendLogException = nullptr;
|
|
MMethod* Internal_GetStackTrace = nullptr;
|
|
CriticalSection Locker;
|
|
}
|
|
|
|
using namespace DebugLogImpl;
|
|
|
|
void ClearMethods(MAssembly*)
|
|
{
|
|
Internal_SendLog = nullptr;
|
|
Internal_SendLogException = nullptr;
|
|
Internal_GetStackTrace = nullptr;
|
|
}
|
|
|
|
bool CacheMethods()
|
|
{
|
|
if (Internal_SendLog && Internal_SendLogException && Internal_GetStackTrace)
|
|
return false;
|
|
ScopeLock lock(Locker);
|
|
if (Internal_SendLog && Internal_SendLogException && Internal_GetStackTrace)
|
|
return false;
|
|
|
|
auto engine = GetBinaryModuleFlaxEngine()->Assembly;
|
|
if (engine == nullptr || !engine->IsLoaded())
|
|
return true;
|
|
auto debugLogHandlerClass = engine->GetClass("FlaxEngine.DebugLogHandler");
|
|
if (!debugLogHandlerClass)
|
|
return false;
|
|
|
|
Internal_SendLog = debugLogHandlerClass->GetMethod("Internal_SendLog", 2);
|
|
if (!Internal_SendLog)
|
|
return false;
|
|
|
|
Internal_SendLogException = debugLogHandlerClass->GetMethod("Internal_SendLogException", 1);
|
|
if (!Internal_SendLogException)
|
|
return false;
|
|
|
|
Internal_GetStackTrace = debugLogHandlerClass->GetMethod("Internal_GetStackTrace");
|
|
if (!Internal_GetStackTrace)
|
|
return false;
|
|
|
|
engine->Unloading.Bind<ClearMethods>();
|
|
|
|
return false;
|
|
}
|
|
|
|
void DebugLog::Log(LogType type, const String& message)
|
|
{
|
|
if (CacheMethods())
|
|
return;
|
|
|
|
auto scriptsDomain = Scripting::GetScriptsDomain();
|
|
MainThreadManagedInvokeAction::ParamsBuilder params;
|
|
params.AddParam(type);
|
|
params.AddParam(message, scriptsDomain->GetNative());
|
|
MainThreadManagedInvokeAction::Invoke(Internal_SendLog, params);
|
|
}
|
|
|
|
void DebugLog::LogException(MonoObject* exceptionObject)
|
|
{
|
|
if (exceptionObject == nullptr)
|
|
return;
|
|
|
|
if (CacheMethods())
|
|
return;
|
|
|
|
MainThreadManagedInvokeAction::ParamsBuilder params;
|
|
params.AddParam(exceptionObject);
|
|
MainThreadManagedInvokeAction::Invoke(Internal_SendLogException, params);
|
|
}
|
|
|
|
String DebugLog::GetStackTrace()
|
|
{
|
|
String result;
|
|
if (!CacheMethods())
|
|
{
|
|
auto stackTraceObj = Internal_GetStackTrace->Invoke(nullptr, nullptr, nullptr);
|
|
MUtils::ToString((MonoString*)stackTraceObj, result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void DebugLog::ThrowException(const char* msg)
|
|
{
|
|
// Throw exception to the C# world
|
|
auto ex = mono_exception_from_name_msg(mono_get_corlib(), "System", "Exception", msg);
|
|
mono_raise_exception(ex);
|
|
}
|
|
|
|
void DebugLog::ThrowNullReference()
|
|
{
|
|
//LOG(Warning, "Invalid null reference.");
|
|
//LOG_STR(Warning, DebugLog::GetStackTrace());
|
|
|
|
// Throw exception to the C# world
|
|
auto ex = mono_get_exception_null_reference();
|
|
mono_raise_exception(ex);
|
|
}
|
|
|
|
void DebugLog::ThrowArgument(const char* arg, const char* msg)
|
|
{
|
|
// Throw exception to the C# world
|
|
auto ex = mono_get_exception_argument(arg, msg);
|
|
mono_raise_exception(ex);
|
|
}
|
|
|
|
void DebugLog::ThrowArgumentNull(const char* arg)
|
|
{
|
|
// Throw exception to the C# world
|
|
auto ex = mono_get_exception_argument_null(arg);
|
|
mono_raise_exception(ex);
|
|
}
|
|
|
|
void DebugLog::ThrowArgumentOutOfRange(const char* arg)
|
|
{
|
|
// Throw exception to the C# world
|
|
auto ex = mono_get_exception_argument_out_of_range(arg);
|
|
mono_raise_exception(ex);
|
|
}
|
|
|
|
void DebugLog::ThrowNotSupported(const char* msg)
|
|
{
|
|
// Throw exception to the C# world
|
|
auto ex = mono_get_exception_not_supported(msg);
|
|
mono_raise_exception(ex);
|
|
}
|