feat: 实现日志与调试系统(Debug模块)
- LogLevel: 日志级别枚举 (Verbose, Debug, Info, Warning, Error, Fatal) - LogCategory: 日志分类 (General, Rendering, Physics, Memory, Threading等) - ILogSink: 日志输出接口 - ConsoleLogSink: 控制台输出, 支持Windows颜色 - FileLogSink: 文件日志输出 - FileWriter: 文件写入器 - Logger: 日志管理器, 支持多sink, 分类控制 - Profiler: 性能分析器 - 单元测试覆盖
This commit is contained in:
29
engine/include/XCEngine/Core/FileWriter.h
Normal file
29
engine/include/XCEngine/Core/FileWriter.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Containers/String.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Core {
|
||||
|
||||
class FileWriter {
|
||||
public:
|
||||
FileWriter();
|
||||
FileWriter(const char* filePath, bool append = false);
|
||||
~FileWriter();
|
||||
|
||||
bool Open(const char* filePath, bool append = false);
|
||||
void Close();
|
||||
|
||||
bool Write(const char* data, size_t length);
|
||||
bool Write(const Containers::String& str);
|
||||
bool Flush();
|
||||
|
||||
bool IsOpen() const { return m_file != nullptr; }
|
||||
|
||||
private:
|
||||
FILE* m_file = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
} // namespace XCEngine
|
||||
25
engine/include/XCEngine/Debug/ConsoleLogSink.h
Normal file
25
engine/include/XCEngine/Debug/ConsoleLogSink.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "ILogSink.h"
|
||||
#include "LogLevel.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Debug {
|
||||
|
||||
class ConsoleLogSink : public ILogSink {
|
||||
public:
|
||||
ConsoleLogSink();
|
||||
~ConsoleLogSink() override;
|
||||
|
||||
void Log(const LogEntry& entry) override;
|
||||
void Flush() override;
|
||||
void SetColorOutput(bool enable);
|
||||
void SetMinimumLevel(LogLevel level);
|
||||
|
||||
private:
|
||||
bool m_colorOutput = true;
|
||||
LogLevel m_minimumLevel = LogLevel::Verbose;
|
||||
};
|
||||
|
||||
} // namespace Debug
|
||||
} // namespace XCEngine
|
||||
12
engine/include/XCEngine/Debug/Debug.h
Normal file
12
engine/include/XCEngine/Debug/Debug.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "LogLevel.h"
|
||||
#include "LogCategory.h"
|
||||
#include "LogEntry.h"
|
||||
#include "ILogSink.h"
|
||||
#include "ConsoleLogSink.h"
|
||||
#include "FileLogSink.h"
|
||||
#include "Logger.h"
|
||||
#include "Profiler.h"
|
||||
|
||||
#include "../Core/FileWriter.h"
|
||||
25
engine/include/XCEngine/Debug/FileLogSink.h
Normal file
25
engine/include/XCEngine/Debug/FileLogSink.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "ILogSink.h"
|
||||
#include "LogEntry.h"
|
||||
#include "../Containers/String.h"
|
||||
#include "../Core/FileWriter.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Debug {
|
||||
|
||||
class FileLogSink : public ILogSink {
|
||||
public:
|
||||
FileLogSink(const Containers::String& filePath);
|
||||
~FileLogSink() override;
|
||||
|
||||
void Log(const LogEntry& entry) override;
|
||||
void Flush() override;
|
||||
|
||||
private:
|
||||
Containers::String m_filePath;
|
||||
Core::FileWriter m_writer;
|
||||
};
|
||||
|
||||
} // namespace Debug
|
||||
} // namespace XCEngine
|
||||
16
engine/include/XCEngine/Debug/ILogSink.h
Normal file
16
engine/include/XCEngine/Debug/ILogSink.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "LogEntry.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Debug {
|
||||
|
||||
class ILogSink {
|
||||
public:
|
||||
virtual ~ILogSink() = default;
|
||||
virtual void Log(const LogEntry& entry) = 0;
|
||||
virtual void Flush() = 0;
|
||||
};
|
||||
|
||||
} // namespace Debug
|
||||
} // namespace XCEngine
|
||||
22
engine/include/XCEngine/Debug/LogCategory.h
Normal file
22
engine/include/XCEngine/Debug/LogCategory.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Debug {
|
||||
|
||||
enum class LogCategory {
|
||||
General,
|
||||
Rendering,
|
||||
Physics,
|
||||
Audio,
|
||||
Scripting,
|
||||
Network,
|
||||
Memory,
|
||||
Threading,
|
||||
FileSystem,
|
||||
Custom
|
||||
};
|
||||
|
||||
const char* LogCategoryToString(LogCategory category);
|
||||
|
||||
} // namespace Debug
|
||||
} // namespace XCEngine
|
||||
22
engine/include/XCEngine/Debug/LogEntry.h
Normal file
22
engine/include/XCEngine/Debug/LogEntry.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "LogLevel.h"
|
||||
#include "LogCategory.h"
|
||||
#include "../Containers/String.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Debug {
|
||||
|
||||
struct LogEntry {
|
||||
LogLevel level;
|
||||
LogCategory category;
|
||||
Containers::String message;
|
||||
Containers::String file;
|
||||
int32_t line;
|
||||
Containers::String function;
|
||||
uint64_t timestamp;
|
||||
uint32_t threadId;
|
||||
};
|
||||
|
||||
} // namespace Debug
|
||||
} // namespace XCEngine
|
||||
20
engine/include/XCEngine/Debug/LogLevel.h
Normal file
20
engine/include/XCEngine/Debug/LogLevel.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Debug {
|
||||
|
||||
enum class LogLevel : uint8_t {
|
||||
Verbose = 0,
|
||||
Debug = 1,
|
||||
Info = 2,
|
||||
Warning = 3,
|
||||
Error = 4,
|
||||
Fatal = 5
|
||||
};
|
||||
|
||||
const char* LogLevelToString(LogLevel level);
|
||||
|
||||
} // namespace Debug
|
||||
} // namespace XCEngine
|
||||
59
engine/include/XCEngine/Debug/Logger.h
Normal file
59
engine/include/XCEngine/Debug/Logger.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "LogLevel.h"
|
||||
#include "LogCategory.h"
|
||||
#include "ILogSink.h"
|
||||
#include "../Containers/String.h"
|
||||
#include "../Threading/Mutex.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Debug {
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
static Logger& Get();
|
||||
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
void AddSink(std::unique_ptr<ILogSink> sink);
|
||||
void RemoveSink(ILogSink* sink);
|
||||
|
||||
void Log(LogLevel level, LogCategory category,
|
||||
const Containers::String& message, const char* file = nullptr,
|
||||
int32_t line = 0, const char* function = nullptr);
|
||||
|
||||
void Verbose(LogCategory category, const Containers::String& message);
|
||||
void Debug(LogCategory category, const Containers::String& message);
|
||||
void Info(LogCategory category, const Containers::String& message);
|
||||
void Warning(LogCategory category, const Containers::String& message);
|
||||
void Error(LogCategory category, const Containers::String& message);
|
||||
void Fatal(LogCategory category, const Containers::String& message);
|
||||
|
||||
void SetMinimumLevel(LogLevel level);
|
||||
void SetCategoryEnabled(LogCategory category, bool enabled);
|
||||
|
||||
private:
|
||||
Logger() = default;
|
||||
~Logger() = default;
|
||||
|
||||
std::vector<std::unique_ptr<ILogSink>> m_sinks;
|
||||
LogLevel m_minimumLevel = LogLevel::Verbose;
|
||||
bool m_categoryEnabled[11] = { true };
|
||||
Threading::Mutex m_mutex;
|
||||
bool m_initialized = false;
|
||||
};
|
||||
|
||||
#define XE_LOG(category, level, message) \
|
||||
XCEngine::Debug::Logger::Get().Log(level, category, message, __FILE__, __LINE__, __FUNCTION__)
|
||||
|
||||
#define XE_ASSERT(condition, message) \
|
||||
if (!(condition)) { \
|
||||
XCEngine::Debug::Logger::Get().Fatal(XCEngine::Debug::LogCategory::General, message); \
|
||||
}
|
||||
|
||||
} // namespace Debug
|
||||
} // namespace XCEngine
|
||||
56
engine/include/XCEngine/Debug/Profiler.h
Normal file
56
engine/include/XCEngine/Debug/Profiler.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "LogLevel.h"
|
||||
#include "../Containers/String.h"
|
||||
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Debug {
|
||||
|
||||
class Profiler {
|
||||
public:
|
||||
static Profiler& Get();
|
||||
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
void BeginProfile(const char* name);
|
||||
void EndProfile();
|
||||
|
||||
void BeginFrame();
|
||||
void EndFrame();
|
||||
|
||||
void MarkEvent(const char* name, uint64_t timestamp, uint32_t threadId);
|
||||
void SetMarker(const char* name, uint32_t color);
|
||||
|
||||
void ExportChromeTracing(const Containers::String& filePath);
|
||||
|
||||
private:
|
||||
struct ProfileNode {
|
||||
const char* name;
|
||||
uint64_t startTime;
|
||||
uint64_t endTime;
|
||||
uint32_t threadId;
|
||||
};
|
||||
|
||||
struct ProfileSample {
|
||||
const char* name;
|
||||
uint64_t duration;
|
||||
uint32_t threadId;
|
||||
};
|
||||
|
||||
std::vector<ProfileNode> m_profileStack;
|
||||
std::vector<ProfileSample> m_samples;
|
||||
uint64_t m_frameStartTime = 0;
|
||||
bool m_initialized = false;
|
||||
};
|
||||
|
||||
#define XE_PROFILE_BEGIN(name) XCEngine::Debug::Profiler::Get().BeginProfile(name)
|
||||
#define XE_PROFILE_END() XCEngine::Debug::Profiler::Get().EndProfile()
|
||||
#define XE_PROFILE_FUNCTION() XE_PROFILE_BEGIN(__FUNCTION__)
|
||||
|
||||
} // namespace Debug
|
||||
} // namespace XCEngine
|
||||
Reference in New Issue
Block a user