Added logging & exception handling tools into engine, modified premake5 on SHADE_Application to include spdlog

This commit is contained in:
Diren D Bharwani 2022-09-08 12:51:23 +08:00
parent ce37eb004c
commit 280ef33587
15 changed files with 969 additions and 18 deletions

View File

@ -60,7 +60,7 @@
<PrecompiledHeaderFile>SBpch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>SBpch.h</PrecompiledHeaderFile>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat> <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
@ -80,7 +80,7 @@
<PrecompiledHeaderFile>SBpch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>SBpch.h</PrecompiledHeaderFile>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<PreprocessorDefinitions>_RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization>Full</Optimization> <Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Application">
<UniqueIdentifier>{D9DE78AF-4594-F1A4-CE88-EB7B3A3DE8A8}</UniqueIdentifier>
</Filter>
<Filter Include="Scenes">
<UniqueIdentifier>{86EEB3D0-7290-DEA6-5B4B-F2FA478C65F7}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Application\SBApplication.h">
<Filter>Application</Filter>
</ClInclude>
<ClInclude Include="src\SBpch.h" />
<ClInclude Include="src\Scenes\SBTestScene.h">
<Filter>Scenes</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\Application\SBApplication.cpp">
<Filter>Application</Filter>
</ClCompile>
<ClCompile Include="src\SBpch.cpp" />
<ClCompile Include="src\Scenes\SBTestScene.cpp">
<Filter>Scenes</Filter>
</ClCompile>
<ClCompile Include="src\WinMain.cpp" />
</ItemGroup>
</Project>

View File

@ -21,8 +21,7 @@ project "SHADE_Application"
includedirs includedirs
{ {
"%{IncludeDir.GLFW}", "%{IncludeDir.spdlog}/include",
"%{IncludeDir.GLAD}",
"../SHADE_Engine/src", "../SHADE_Engine/src",
"src" "src"
} }

View File

@ -15,6 +15,8 @@ namespace Sandbox
bool paused = false; bool paused = false;
void SBApplication::Initialize(void) void SBApplication::Initialize(void)
{ {
#ifdef SHEDITOR #ifdef SHEDITOR
#else #else
#endif #endif

View File

@ -1,5 +1,7 @@
#include "SBpch.h" #include "SBpch.h"
#include <Engine/SHEngine.h> #include <Engine/SHEngine.h>
#include <Tools/SHLogger.h>
#include <Tools/SHExceptionHandler.h>
#include "Application/SBApplication.h" #include "Application/SBApplication.h"
@ -15,15 +17,35 @@
#define DBG_NEW new #define DBG_NEW new
#endif #endif
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, INT WINAPI WinMain
PSTR lpCmdLine, INT nCmdShow) (
_In_ HINSTANCE /*hInstance*/,
_In_opt_ HINSTANCE /*hPrevInstance*/,
_In_ PSTR /*lpCmdLine*/,
_In_ INT /*nCmdShow*/
)
{ {
#ifndef SHEDITOR const SHADE::SHLogger::Config LOGGER_CONFIG{ .directoryPath = "./logs/" };
ShowWindow(::GetConsoleWindow(), SW_HIDE); SHADE::SHLogger::Initialise(LOGGER_CONFIG);
#endif
SHADE::SHEngine::Run<Sandbox::SBApplication>(); try
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); {
#ifndef SHEDITOR
//ShowWindow(::GetConsoleWindow(), SW_HIDE);
#endif
SHLOG_INFO("sup")
SHADE::SHEngine::Run<Sandbox::SBApplication>();
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
}
catch(...)
{
SHADE::SHExceptionHandler::HandleException(std::current_exception());
SHADE::SHLogger::Shutdown();
}
SHADE::SHLogger::Shutdown();
return 0; return 0;
} }

View File

@ -117,9 +117,12 @@
<ClInclude Include="src\Engine\ECS_Base\System\SHSystemManager.h" /> <ClInclude Include="src\Engine\ECS_Base\System\SHSystemManager.h" />
<ClInclude Include="src\Engine\SHEngine.h" /> <ClInclude Include="src\Engine\SHEngine.h" />
<ClInclude Include="src\Meta\SHIsDetected.h" /> <ClInclude Include="src\Meta\SHIsDetected.h" />
<ClInclude Include="src\SHpch.h" />
<ClInclude Include="src\Scene\SHScene.h" /> <ClInclude Include="src\Scene\SHScene.h" />
<ClInclude Include="src\Scene\SHSceneManager.h" /> <ClInclude Include="src\Scene\SHSceneManager.h" />
<ClInclude Include="src\SHpch.h" /> <ClInclude Include="src\Tools\SHException.h" />
<ClInclude Include="src\Tools\SHExceptionHandler.h" />
<ClInclude Include="src\Tools\SHLogger.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponent.cpp" /> <ClCompile Include="src\Engine\ECS_Base\Components\SHComponent.cpp" />
@ -129,10 +132,13 @@
<ClCompile Include="src\Engine\ECS_Base\System\SHEntityManager.cpp" /> <ClCompile Include="src\Engine\ECS_Base\System\SHEntityManager.cpp" />
<ClCompile Include="src\Engine\ECS_Base\System\SHSystemManager.cpp" /> <ClCompile Include="src\Engine\ECS_Base\System\SHSystemManager.cpp" />
<ClCompile Include="src\Engine\SHEngine.cpp" /> <ClCompile Include="src\Engine\SHEngine.cpp" />
<ClCompile Include="src\Scene\SHSceneManager.cpp" />
<ClCompile Include="src\SHpch.cpp"> <ClCompile Include="src\SHpch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader> <PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile> </ClCompile>
<ClCompile Include="src\Scene\SHSceneManager.cpp" />
<ClCompile Include="src\Tools\SHException.cpp" />
<ClCompile Include="src\Tools\SHExceptionHandler.cpp" />
<ClCompile Include="src\Tools\SHLogger.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Dependencies\yamlcpp\yaml-cpp.vcxproj"> <ProjectReference Include="..\Dependencies\yamlcpp\yaml-cpp.vcxproj">
@ -157,4 +163,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

View File

@ -19,6 +19,15 @@
<Filter Include="Engine\ECS_Base\System"> <Filter Include="Engine\ECS_Base\System">
<UniqueIdentifier>{B3E3FAFD-9FDD-2350-884A-BA6074E389BC}</UniqueIdentifier> <UniqueIdentifier>{B3E3FAFD-9FDD-2350-884A-BA6074E389BC}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Meta">
<UniqueIdentifier>{AC05897C-983C-8A0D-4129-70102D3F060F}</UniqueIdentifier>
</Filter>
<Filter Include="Scene">
<UniqueIdentifier>{B3F7140E-1F0C-3DBF-E88D-E01E546139F0}</UniqueIdentifier>
</Filter>
<Filter Include="Tools">
<UniqueIdentifier>{16CF2D0E-82E3-55BF-4B65-F91EB73852F0}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\Engine\ECS_Base\Components\SHComponent.h"> <ClInclude Include="src\Engine\ECS_Base\Components\SHComponent.h">
@ -63,10 +72,25 @@
<ClInclude Include="src\Engine\SHEngine.h"> <ClInclude Include="src\Engine\SHEngine.h">
<Filter>Engine</Filter> <Filter>Engine</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\Meta\SHIsDetected.h">
<Filter>Meta</Filter>
</ClInclude>
<ClInclude Include="src\SHpch.h" /> <ClInclude Include="src\SHpch.h" />
<ClInclude Include="src\Meta\SHIsDetected.h" /> <ClInclude Include="src\Scene\SHScene.h">
<ClInclude Include="src\Scene\SHScene.h" /> <Filter>Scene</Filter>
<ClInclude Include="src\Scene\SHSceneManager.h" /> </ClInclude>
<ClInclude Include="src\Scene\SHSceneManager.h">
<Filter>Scene</Filter>
</ClInclude>
<ClInclude Include="src\Tools\SHException.h">
<Filter>Tools</Filter>
</ClInclude>
<ClInclude Include="src\Tools\SHExceptionHandler.h">
<Filter>Tools</Filter>
</ClInclude>
<ClInclude Include="src\Tools\SHLogger.h">
<Filter>Tools</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponent.cpp"> <ClCompile Include="src\Engine\ECS_Base\Components\SHComponent.cpp">
@ -91,6 +115,17 @@
<Filter>Engine</Filter> <Filter>Engine</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\SHpch.cpp" /> <ClCompile Include="src\SHpch.cpp" />
<ClCompile Include="src\Scene\SHSceneManager.cpp" /> <ClCompile Include="src\Scene\SHSceneManager.cpp">
<Filter>Scene</Filter>
</ClCompile>
<ClCompile Include="src\Tools\SHException.cpp">
<Filter>Tools</Filter>
</ClCompile>
<ClCompile Include="src\Tools\SHExceptionHandler.cpp">
<Filter>Tools</Filter>
</ClCompile>
<ClCompile Include="src\Tools\SHLogger.cpp">
<Filter>Tools</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1 +1,10 @@
/****************************************************************************************
* \file SHpch.h
* \brief Empty source file for generating SHADE Engine's precompiled header.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#include "SHpch.h" #include "SHpch.h"

View File

@ -0,0 +1,12 @@
/****************************************************************************************
* \file SHpch.h
* \brief Precompiled header file for SHADE Engine.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#pragma once
#include <iostream>

View File

@ -0,0 +1,51 @@
/****************************************************************************************
* \file SHException.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for custom exception types of SHADE Engine.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHException.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHException::SHException(std::string msg, const std::source_location& src) noexcept
: message { std::move(msg) }
, origin { src }
{}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
const char* SHException::what() const noexcept
{
std::stringstream ss;
ss << "SHException " << GetOriginString();
message = ss.str();
return message.c_str();
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
std::string SHException::GetOriginString() const noexcept
{
std::stringstream ss;
ss << "[" << origin.file_name() << ", " << origin.line() << "]";
return ss.str();
}
} // namespace SHADE

View File

@ -0,0 +1,84 @@
/****************************************************************************************
* \file SHException.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for custom exception types of SHADE Engine.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#pragma once
#include <exception>
#include <string>
#include <source_location>
#include <string_view>
#include <cassert>
#include <cstdlib>
// Project Headers
#include "SHLogger.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Concepts */
/*-----------------------------------------------------------------------------------*/
template <typename ExceptionType>
concept IsException = std::is_base_of_v<std::exception, ExceptionType>;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/**
* @brief Base exception type thrown by SHADE Engine.
*/
class SHException : public std::exception
{
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHException
(
std::string msg = "",
const std::source_location& src = std::source_location::current()
) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
const char* what() const noexcept override;
protected:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
mutable std::string message;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
std::string GetOriginString() const noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
const std::source_location& origin;
};
}
#define SHASSERT(cond, msg) \
if (!(cond)) \
{ \
SHLOGV_CRITICAL(msg) \
std::abort(); \
}

View File

@ -0,0 +1,49 @@
/****************************************************************************************
* \file SHExceptionHandler.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for SHADE Engine's exception handler.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHExceptionHandler.h"
// Project Headers
#include "SHException.h"
#include "SHLogger.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHExceptionHandler::HandleException(const std::exception_ptr& exceptionPtr)
{
try
{
// Re-throw all valid exception types
if (exceptionPtr)
{
std::rethrow_exception(exceptionPtr);
}
}
catch (const std::exception& e)
{
SHLOG_CRITICAL(e.what())
}
catch (...)
{
// Catch any non-std::exception derived types and consider them as unknown.
SHLOG_CRITICAL("SHADE Engine has experienced an unknown fatal error!")
}
return false;
}
} // namespace SHADE

View File

@ -0,0 +1,37 @@
/****************************************************************************************
* \file SHExceptionHandler.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for SHADE Engine's exception handler.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#pragma once
#include <exception>
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SHExceptionHandler
{
public:
/*---------------------------------------------------------------------------------*/
/* Static Function Members */
/*---------------------------------------------------------------------------------*/
/**
* @brief Catches and logs any exceptions thrown. If the exception's type is
* SHAssertException, the application will not end unless crashOnAssert is set
* to true.
* @param exceptionPtr Pointer to the exception that was caught.
* @returns True if the application should continue running after an exception was caught.
*/
static bool HandleException(const std::exception_ptr& exceptionPtr);
};
} // namespace SHADE

View File

@ -0,0 +1,441 @@
/****************************************************************************************
* \file SHLogger.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for SHADE Engine's logger.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHLogger.h"
#include <fstream>
#include <chrono>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
/*-------------------------------------------------------------------------------------*/
/* Local Helper Function Declarations */
/*-------------------------------------------------------------------------------------*/
std::string GetDatePattern (SHADE::SHLogger::DateFormat fmt);
std::string GetClockPattern (bool is24HR);
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Data Member Definitions */
/*-----------------------------------------------------------------------------------*/
unsigned char SHLogger::configFlags = DEFAULT_CONFIG_FLAG;
SHLogger::DateFormat SHLogger::dateFormat = SHLogger::DateFormat::DD_MM_YY;
std::string SHLogger::trivialPattern;
std::string SHLogger::verbosePattern;
std::string SHLogger::fileName;
std::filesystem::path SHLogger::directoryPath;
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHLogger::SetConfig(const Config& config) noexcept
{
unsigned char flags = 0U;
if (config.showTime)
flags |= 1U << 0;
if (config.clockFormat == ClockFormat::_24HR)
flags |= 1U << 1;
if (config.showDate)
flags |= 1U << 2;
if (config.showFunctionFileName)
flags |= 1U << 3;
if (config.showFunctionLineNumber)
flags |= 1U << 4;
configFlags = flags;
dateFormat = config.dateFormat;
fileName = config.fileName;
directoryPath = config.directoryPath;
UpdatePatterns();
}
void SHLogger::SetShowTime(bool showTime) noexcept
{
constexpr char RAW = 1U << 0;
showTime ? configFlags |= RAW : configFlags &= ~(RAW);
UpdatePatterns();
}
void SHLogger::SetShowDate(bool showDate) noexcept
{
constexpr char RAW = 1U << 2;
showDate ? configFlags |= RAW : configFlags &= ~(RAW);
UpdatePatterns();
}
void SHLogger::SetShowFunctionFileName(bool showFunctionFileName) noexcept
{
constexpr char RAW = 1U << 3;
showFunctionFileName ? configFlags |= RAW : configFlags &= ~(RAW);
UpdatePatterns();
}
void SHLogger::SetShowFunctionLineNumber(bool showFunctionLineNumber) noexcept
{
constexpr char RAW = 1U << 4;
showFunctionLineNumber ? configFlags |= RAW : configFlags &= ~(RAW);
UpdatePatterns();
}
void SHLogger::SetClockFormat(ClockFormat newClockFormat) noexcept
{
constexpr char RAW = 1U << 1;
newClockFormat == ClockFormat::_24HR ? configFlags |= RAW : configFlags &= ~(RAW);
UpdatePatterns();
}
void SHLogger::SetDateFormat(DateFormat newDateFormat) noexcept
{
dateFormat = newDateFormat;
UpdatePatterns();
}
void SHLogger::SetFileName(const std::string& logFileName) noexcept
{
if (CheckInitialisation("Logger has already been initialised!"))
return;
fileName = logFileName;
}
void SHLogger::SetDirectoryPath(const std::filesystem::path& logDirectoryPath) noexcept
{
if (CheckInitialisation("Logger has already been initialised!"))
return;
if (!is_directory(logDirectoryPath))
{
spdlog::get(SHLOGGER_NAME)->info("Supplied path is not a directory!");
return;
}
directoryPath = logDirectoryPath;
}
void SHLogger::SetFlushTime(int seconds) noexcept
{
spdlog::flush_every(std::chrono::seconds(seconds));
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHLogger::Initialise(const Config& config)
{
SetConfig(config);
// Initialise default fileName if fileName was not set
if (fileName.empty())
{
// Get current date and time
const auto NOW = std::time(nullptr);
std::tm localTime;
localtime_s(&localTime, &NOW);
std::stringstream tmp;
tmp << "SHADE Log_" << std::put_time(&localTime, "%F %H.%M.%S") << ".txt";
fileName = tmp.str();
}
CreateConsole();
try
{
std::vector<spdlog::sink_ptr> sinks;
// Colour console
const auto& COLOUR_CONSOLE_SINK = sinks.emplace_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
COLOUR_CONSOLE_SINK->set_pattern("%^" + trivialPattern + "%v%$");
// File
const std::string FULL_FILE_PATH = directoryPath.string() + fileName;
const auto& FILE_SINK = sinks.emplace_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(FULL_FILE_PATH));
FILE_SINK->set_pattern(trivialPattern + "%v");
// Create and register logger with spdlog
const auto LOGGER = std::make_shared<spdlog::logger>(SHLOGGER_NAME, sinks.begin(), sinks.end());
LOGGER->set_level(spdlog::level::trace);
LOGGER->flush_on(spdlog::level::trace);
register_logger(LOGGER);
// Flush every 3 seconds
spdlog::flush_every(std::chrono::seconds(config.flushTime));
configFlags |= (1U << 7);
}
catch (const spdlog::spdlog_ex& e)
{
std::cout << "Log initialisation failed: " << e.what() << std::endl;
}
}
void SHLogger::Shutdown() noexcept
{
spdlog::shutdown();
}
void SHLogger::UseTrivialPattern() noexcept
{
auto& sinks = spdlog::get(SHLOGGER_NAME)->sinks();
sinks[0]->set_pattern("%^" + trivialPattern + "%v%$"); // Colour Console Sink
sinks[1]->set_pattern(trivialPattern + "%v"); // File Sink
}
void SHLogger::UseVerbosePattern() noexcept
{
auto& sinks = spdlog::get(SHLOGGER_NAME)->sinks();
sinks[0]->set_pattern("%^" + verbosePattern + "%v%$"); // Colour Console Sink
sinks[1]->set_pattern(verbosePattern + "%v"); // File Sink
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHLogger::CreateConsole()
{
bool result = false;
DestroyConsole();
if (AllocConsole())
{
const HANDLE CONSOLE = GetStdHandle(STD_OUTPUT_HANDLE);
// Set the screen buffer to be big enough to scroll some text
CONSOLE_SCREEN_BUFFER_INFO conInfo;
GetConsoleScreenBufferInfo(CONSOLE, &conInfo);
if (conInfo.dwSize.Y < DEFAULT_CONSOLE_LEN)
{
conInfo.dwSize.Y = DEFAULT_CONSOLE_LEN;
}
SetConsoleScreenBufferSize(CONSOLE, conInfo.dwSize);
result = RedirectConsoleIO();
}
return result;
}
bool SHLogger::RedirectConsoleIO()
{
bool result = true;
FILE* fp;
// Redirect STDIN if the console has an input handle
if (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)
{
if (freopen_s(&fp, "CONIN$", "r", stdin) != 0)
{
result = false;
}
else
{
setvbuf(stdin, nullptr, _IONBF, 0);
}
}
// Redirect STDOUT if the console has an output handle
if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE)
{
if (freopen_s(&fp, "CONOUT$", "w", stdout) != 0)
{
result = false;
}
else
{
setvbuf(stdout, nullptr, _IONBF, 0);
}
}
// Redirect STDERR if the console has an error handle
if (GetStdHandle(STD_ERROR_HANDLE) != INVALID_HANDLE_VALUE)
{
if (freopen_s(&fp, "CONOUT$", "w", stderr) != 0)
{
result = false;
}
else
{
setvbuf(stderr, nullptr, _IONBF, 0);
}
}
// Make C++ standard streams point to console as well.
std::ios::sync_with_stdio(true);
// Clear the error state for each of the C++ standard streams.
std::wcin.clear();
std::cin.clear();
std::wcout.clear();
std::cout.clear();
std::wcerr.clear();
std::cerr.clear();
return result;
}
bool SHLogger::DestroyConsole()
{
bool result = true;
FILE* fP;
// Just to be safe, redirect standard IO to NUL before releasing.
// Redirect STDIN to NUL
if (freopen_s(&fP, "NUL:", "r", stdin) != 0)
{
result = false;
}
else
{
setvbuf(stdin, nullptr, _IONBF, 0);
}
// Redirect STDOUT to NUL
if (freopen_s(&fP, "NUL:", "w", stdout) != 0)
{
result = false;
}
else
{
setvbuf(stdout, nullptr, _IONBF, 0);
}
// Redirect STDERR to NUL
if (freopen_s(&fP, "NUL:", "w", stderr) != 0)
{
result = false;
}
else
{
setvbuf(stderr, nullptr, _IONBF, 0);
}
// Detach console
if (result)
return FreeConsole();
return result;
}
bool SHLogger::CheckInitialisation(const std::string_view& msg)
{
const bool INITIALISED = configFlags & (1U << 7);
if (INITIALISED)
{
spdlog::get(SHLOGGER_NAME)->warn(msg);
return true;
}
return false;
}
void SHLogger::UpdatePatterns()
{
const std::string DATE_TIME_PATTERN = BuildDateTimePattern();
const std::string VERBOSE_PATTERN = BuildVerbosePattern();
trivialPattern = DATE_TIME_PATTERN;
verbosePattern = DATE_TIME_PATTERN + VERBOSE_PATTERN;
}
std::string SHLogger::BuildDateTimePattern()
{
const bool SHOW_TIME = configFlags & (1U << 0);
const bool SHOW_DATE = configFlags & (1U << 2);
std::string pattern;
if (SHOW_DATE || SHOW_TIME)
{
pattern.append("[");
{
if (SHOW_DATE)
{
pattern.append(GetDatePattern(dateFormat));
}
// Put a space in between date and time
if (SHOW_DATE && SHOW_TIME)
{
pattern.append(" ");
}
if (SHOW_TIME)
{
const bool IS_24HR = configFlags & (1U << 1);
pattern.append(GetClockPattern(IS_24HR));
}
}
pattern.append("] ");
}
return pattern;
}
std::string SHLogger::BuildVerbosePattern()
{
const bool SHOW_SRC_FILE = configFlags & (1U << 3);
const bool SHOW_SRC_LINE = configFlags & (1U << 4);
std::string pattern { "[" };
if (SHOW_SRC_FILE)
{
pattern.append("%s, ");
if (SHOW_SRC_LINE)
{
pattern.append("%#, ");
}
}
pattern.append("%!] ");
return pattern;
}
} // namespace SHADE
std::string GetDatePattern(SHADE::SHLogger::DateFormat fmt)
{
switch (fmt)
{
case SHADE::SHLogger::DateFormat::DD_MM_YY: return std::string { "%d-%m-%Y" };
case SHADE::SHLogger::DateFormat::MM_DD_YY: return std::string { "%m-%d-%Y" };
case SHADE::SHLogger::DateFormat::YY_MM_DD: return std::string { "%Y-%m-%d" };
case SHADE::SHLogger::DateFormat::DD_Mth_YY: return std::string { "%d %b, %Y" };
case SHADE::SHLogger::DateFormat::Mth_DD_YY: return std::string { "%b %d, %Y" };
default: return std::string { "%d-%m-%Y" };
}
}
std::string GetClockPattern(bool is24HR)
{
return is24HR ? "%H:%M:%S" : "%I:%M:%S %p";
}

View File

@ -0,0 +1,174 @@
/****************************************************************************************
* \file SHLogger.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for SHADE Engine's logger.
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#pragma once
#include <string_view>
#include <filesystem>
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
#include <spdlog/spdlog.h>
/*-------------------------------------------------------------------------------------*/
/* Macros */
/*-------------------------------------------------------------------------------------*/
#define SHLOGGER_NAME "SHLogger"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SHLogger
{
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class ClockFormat { _12HR, _24HR };
enum class DateFormat
{
DD_MM_YY // 25-12-2022
, MM_DD_YY // 12-25-2022
, YY_MM_DD // 2022-12-25
, DD_Mth_YY // 25 Dec, 2022
, Mth_DD_YY // Dec 25, 2022
};
/**
* @brief Defines configuration parameters for the logger.
*/
struct Config
{
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
bool showTime = true;
bool showDate = true;
bool showFunctionFileName = true;
bool showFunctionLineNumber = true;
ClockFormat clockFormat = ClockFormat::_12HR;
DateFormat dateFormat = DateFormat::DD_MM_YY;
std::string fileName;
std::filesystem::path directoryPath;
int flushTime = 1;
};
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] static const std::string& GetTrivialPattern () noexcept { return trivialPattern; }
[[nodiscard]] static const std::string& GetVerbosePattern () noexcept { return verbosePattern; }
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
static void SetTrivialPattern (const std::string& pattern) noexcept { trivialPattern = pattern; }
static void SetVerbosePattern (const std::string& pattern) noexcept { verbosePattern = pattern; }
static void SetConfig (const Config& config) noexcept;
static void SetShowTime (bool showTime) noexcept;
static void SetShowDate (bool showDate) noexcept;
static void SetShowFunctionFileName (bool showFunctionFileName) noexcept;
static void SetShowFunctionLineNumber (bool showFunctionLineNumber) noexcept;
static void SetClockFormat (ClockFormat newClockFormat) noexcept;
static void SetDateFormat (DateFormat newDateFormat) noexcept;
static void SetFileName (const std::string& logFileName) noexcept;
static void SetDirectoryPath (const std::filesystem::path& logDirectoryPath) noexcept;
static void SetFlushTime (int seconds) noexcept;
static void SetFlushTime (size_t seconds) noexcept { spdlog::flush_every(std::chrono::seconds(seconds)); }
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
/**
* @brief Creates a console and a file to log to.
* @param[in] config The configuration parameters for the logger.
*/
static void Initialise (const Config& config = Config{});
static void Shutdown () noexcept;
/**
* @brief The next message logged by the logger will be set to follow the trivial pattern.
*/
static void UseTrivialPattern () noexcept;
/**
* @brief The next message logged by the logger will be set to follow the verbose pattern.
*/
static void UseVerbosePattern () noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
static constexpr char DEFAULT_CONFIG_FLAG = 0b00011101; // 00011101
static constexpr short DEFAULT_CONSOLE_LEN = 1024;
static unsigned char configFlags; // Initialised 0 0 FuncLine# FuncFileName Date TimeFormat Time
static DateFormat dateFormat;
static std::string trivialPattern;
static std::string verbosePattern;
static std::string fileName;
static std::filesystem::path directoryPath; // For file logging
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
static bool CreateConsole ();
static bool RedirectConsoleIO ();
static bool DestroyConsole ();
static bool CheckInitialisation (const std::string_view& msg);
static void UpdatePatterns ();
static std::string BuildDateTimePattern();
static std::string BuildVerbosePattern ();
};
} // namespace SHADE
/*-------------------------------------------------------------------------------------*/
/* Macros */
/*-------------------------------------------------------------------------------------*/
#ifdef _DEBUG
#define SHLOG_TRACE(format, ...) SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_TRACE(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__);
#define SHLOGV_TRACE(format, ...) SHADE::SHLogger::UseVerbosePattern(); SPDLOG_LOGGER_TRACE(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__);
#endif
#define SHLOG_INFO(format, ...) SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_INFO(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__);
#define SHLOGV_INFO(format, ...) SHADE::SHLogger::UseVerbosePattern(); SPDLOG_LOGGER_INFO(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__);
#define SHLOG_WARNING(format, ...) SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_WARN(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__);
#define SHLOGV_WARNING(format, ...) SHADE::SHLogger::UseVerbosePattern(); SPDLOG_LOGGER_WARN(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__);
#define SHLOG_ERROR(format, ...) SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_ERROR(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__);
#define SHLOGV_ERROR(format, ...) SHADE::SHLogger::UseVerbosePattern(); SPDLOG_LOGGER_ERROR(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__);
#define SHLOG_CRITICAL(format, ...) SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_CRITICAL(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__);
#define SHLOGV_CRITICAL(format, ...) SHADE::SHLogger::UseVerbosePattern(); SPDLOG_LOGGER_CRITICAL(spdlog::get(SHLOGGER_NAME), format, ## __VA_ARGS__);
// Misc Logging Macros
#define SHLOG_FLOOR() SHADE::SHLogger::UseTrivialPattern(); SPDLOG_LOGGER_INFO(spdlog::get(SHLOGGER_NAME), "--------------------------------");