日志记录库

下载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