日志记录库
下载SPDLOG
日志系统是用来记录事件的一种方式(这里的事件是比较广义的),用来让我们知道程序在运行的时候到底发生了什么事情,因此我们要使用高级字符串格式化。这里不自己敲代码了,我们使用GitHub上的一个名为SPDLOG的库。
链接:https://github.com/gabime/spdlog
我们通过git clone仓库克隆来完成这件事情,在文件目录进入cmd,将其存在Hazel文件夹下vendor中的spdlog中。
git submodule add https://github.com/gabime/spdlog Hazel/vendor/spdlog
此时会发现主页多了一个.gitmodules,内容为如下。就是在某路径下创建了一个子模块,并且指出了其url。
[submodule "Hazel/vendor/spdlog"]
path = Hazel/vendor/spdlog
url = https://github.com/gabime/spdlog
我们要使用的模块的地址路径是:$(SolutionDir)Hazel\vendor\spdlog\include
将其粘贴在Hazle属性的C/C++常规的附加包含目录中:
Sandbox也加入该目录。
定制日志系统
我们可以通过一个类似全局宏的存在,根据不同的日志级别来使用类似的东西,并且考虑到以后可能更换其他的日志库来处理,所以我们希望尽量不修改客户端带代码。
我们将创建一个日志类,来封装大量的SPD日志,并最终调用一些静态函数来将参数或者其他内容转发给SPD日志。
在Hazel中创建Log.h和Log.cpp,编写以下内容:
Log.h
#pragma once
#include <memory>
#include "Core.h"
#include "spdlog/spdlog.h"
namespace Hazel
{
class HAZEL_API Log
{
public:
static void Init();
inline static std::shared_ptr<spdlog::logger>& GetCoreLogger() { return s_CoreLogger; }
inline static std::shared_ptr<spdlog::logger>& GetClientLogger() { return s_ClientLogger; }
private:
static std::shared_ptr<spdlog::logger> s_CoreLogger;
static std::shared_ptr<spdlog::logger> s_ClientLogger;
};
}
Log.cpp
#include "Log.h"
namespace Hazel
{
std::shared_ptr<spdlog::logger> Log::s_CoreLogger;
std::shared_ptr<spdlog::logger> Log::s_ClientLogger;
void Log::Init()
{
}
}
代码解释放在下部分。可能会遇到这样的报错,这是编码出了问题:


在Hazel的属性中其他选项增加/utf-8即可(此时之前的中文可能会乱码)
【选读:https://www.cnblogs.com/jinyunshaobing/p/16797330.html】

在SPDLOG官网的Wiki找到一些需要的信息,在Custom formatting部分可以找到我们想要的一些数据格式
Log.cpp
#include "Log.h"
#include <spdlog/sinks/stdout_color_sinks.h>
namespace Hazel
{
std::shared_ptr<spdlog::logger> Log::s_CoreLogger;
std::shared_ptr<spdlog::logger> Log::s_ClientLogger;
void Log::Init()
{
spdlog::set_pattern("%^[%T] %n: %v%$");
s_CoreLogger = spdlog::stdout_color_mt("HAZEL");
s_CoreLogger->set_level(spdlog::level::trace);
s_ClientLogger = spdlog::stdout_color_mt("APP");
s_ClientLogger->set_level(spdlog::level::trace);
}
}
Log.h
#pragma once
#include <memory>
#include "Core.h"
#include "spdlog/spdlog.h"
namespace Hazel
{
class HAZEL_API Log
{
public:
static void Init();
inline static std::shared_ptr<spdlog::logger>& GetCoreLogger() { return s_CoreLogger; }
inline static std::shared_ptr<spdlog::logger>& GetClientLogger() { return s_ClientLogger; }
private:
static std::shared_ptr<spdlog::logger> s_CoreLogger;
static std::shared_ptr<spdlog::logger> s_ClientLogger;
};
}
这部分代码使用了智能指针shared_ptr,使用了SPDLOG中的日志对象logger,并且在Log.cpp中编写了初始化的函数,通过set_pattern将其设定为全局默认函数,创建名叫 HAZEL 的多线程安全彩色控制台 logger,并把它赋给引擎侧静态成员。把级别开到最低 trace,所有级别(trace/debug/info/warn/error/critical)都会输出。
后续我们应该做一个引擎舒适化有关的部分,我们现在先测试他,临时放在引擎入口先使用一下。
tips:记得更换Sandbox中的Hazel.dll文件
修改入口函数等:
EntryPoint.h
#pragma once
#ifdef HZ_PLATFORM_WINDOWS
extern Hazel::Application* Hazel::CreateApplication();
int main(int argc, char** argv)
{
Hazel::Log::Init();
Hazel::Log::GetCoreLogger()->warn("Initialized Log!");
Hazel::Log::GetClientLogger()->info("Hello!");
auto app = Hazel::CreateApplication();
app->Run();
delete app;
}
#endif
Hazel.h
#pragma once
//For use by Hazel application
#include "Hazel/Application.h"
#include "Hazel/Log.h"
//------EntryPoint---------------------
#include "Hazel/EntryPoint.h"
//-------------------------------------
效果如下:

目前依旧存在的问题是每次调用这样的日志都需要输入例如Hazel::Log::GetCoreLogger()->warn(“Initialized Log!”);的文本,太麻烦,我们应该设计有关的宏来方便使用。
Log.h
#pragma once
#include <memory>
#include "Core.h"
#include "spdlog/spdlog.h"
namespace Hazel
{
class HAZEL_API Log
{
public:
static void Init();
inline static std::shared_ptr<spdlog::logger>& GetCoreLogger() { return s_CoreLogger; }
inline static std::shared_ptr<spdlog::logger>& GetClientLogger() { return s_ClientLogger; }
private:
static std::shared_ptr<spdlog::logger> s_CoreLogger;
static std::shared_ptr<spdlog::logger> s_ClientLogger;
};
}
// Core log macros
#define HZ_CORE_TRACE(...) ::Hazel::Log::GetCoreLogger()->trace(__VA_ARGS__)
#define HZ_CORE_INFO(...) ::Hazel::Log::GetCoreLogger()->info(__VA_ARGS__)
#define HZ_CORE_WARN(...) ::Hazel::Log::GetCoreLogger()->warn(__VA_ARGS__)
#define HZ_CORE_ERROR(...) ::Hazel::Log::GetCoreLogger()->error(__VA_ARGS__)
#define HZ_CORE_FATAL(...) ::Hazel::Log::GetCoreLogger()->fatal(__VA_ARGS__)
// Client log macros
#define HZ_TRACE(...) ::Hazel::Log::GetClientLogger()->trace(__VA_ARGS__)
#define HZ_INFO(...) ::Hazel::Log::GetClientLogger()->info(__VA_ARGS__)
#define HZ_WARN(...) ::Hazel::Log::GetClientLogger()->warn(__VA_ARGS__)
#define HZ_ERROR(...) ::Hazel::Log::GetClientLogger()->error(__VA_ARGS__)
#define HZ_FATAL(...) ::Hazel::Log::GetClientLogger()->fatal(__VA_ARGS__)
此时我们就可以把之前的代码修改为:
EntryPoint.h
#pragma once
#ifdef HZ_PLATFORM_WINDOWS
extern Hazel::Application* Hazel::CreateApplication();
int main(int argc, char** argv)
{
Hazel::Log::Init();
HZ_CORE_WARN("Initialized Log!");
int a = 5;
HZ_INFO("Hello! Var={0}", a);
auto app = Hazel::CreateApplication();
app->Run();
delete app;
}
#endif

