refactor&feat: 重写日志系统,添加代码追踪信息

master
ternaryop8479 2026-02-14 23:11:26 +08:00
parent 9136627b2a
commit 2284124628
14 changed files with 286 additions and 217 deletions

View File

@ -1,61 +1,74 @@
#ifndef ARE_INCLUDE_UTILS_LOGGER_H
#define ARE_INCLUDE_UTILS_LOGGER_H
#ifndef ARE_INCLUDE_CORE_LOGGER_H
#define ARE_INCLUDE_CORE_LOGGER_H
#include <string>
#include <memory>
namespace are {
/// @brief Log level enumeration
/**
* @enum LogLevel
* @brief Logging severity levels
*/
enum class LogLevel {
DEBUG,
INFO,
WARNING,
ERROR,
FATAL
ARE_LOG_TRACE,
ARE_LOG_DEBUG,
ARE_LOG_INFO,
ARE_LOG_WARN,
ARE_LOG_ERROR,
ARE_LOG_CRITICAL
};
/// @brief Logger interface for engine logging
/// @note This module should be implemented by the user
/**
* @class Logger
* @brief Thread-safe logging system
*
* This class provides a simple interface for logging messages with different
* severity levels. It wraps spdlog for actual logging functionality.
*/
class Logger {
public:
/// @brief Initialize logger
/// @param log_file Log file path (empty for console only)
/// @return True if initialization succeeded
static bool initialize(const std::string& log_file = "");
/// @brief Shutdown logger
/**
* @brief Initialize the logging system
* @param min_level Minimum log level to display
*/
static void init(LogLevel min_level = LogLevel::ARE_LOG_INFO);
/**
* @brief Shutdown the logging system
*/
static void shutdown();
/// @brief Log message
/// @param level Log level
/// @param message Message content
static void log(LogLevel level, const std::string& message);
/// @brief Log debug message
/// @param message Message content
static void debug(const std::string& message);
/// @brief Log info message
/// @param message Message content
static void info(const std::string& message);
/// @brief Log warning message
/// @param message Message content
static void warning(const std::string& message);
/// @brief Log error message
/// @param message Message content
static void error(const std::string& message);
/// @brief Log fatal message
/// @param message Message content
static void fatal(const std::string& message);
/// @brief Set minimum log level
/// @param level Minimum level to log
/**
* @brief Log a message with file/function/line information
* @param level Log severity level
* @param file Source file name
* @param func Function name
* @param line Line number
* @param message Log message
*/
static void log(LogLevel level, const char* file, const char* func,
int line, const std::string& message);
/**
* @brief Set minimum log level
* @param level Minimum log level to display
*/
static void set_level(LogLevel level);
private:
static std::shared_ptr<void> logger_impl_; ///< Internal logger implementation
static bool initialized_; ///< Initialization flag
};
} // namespace are
#endif // ARE_INCLUDE_UTILS_LOGGER_H
// Logging macros
#define ARE_LOG_TRACE(msg) are::Logger::log(are::LogLevel::ARE_LOG_TRACE, __FILE__, __func__, __LINE__, msg)
#define ARE_LOG_DEBUG(msg) are::Logger::log(are::LogLevel::ARE_LOG_DEBUG, __FILE__, __func__, __LINE__, msg)
#define ARE_LOG_INFO(msg) are::Logger::log(are::LogLevel::ARE_LOG_INFO, __FILE__, __func__, __LINE__, msg)
#define ARE_LOG_WARN(msg) are::Logger::log(are::LogLevel::ARE_LOG_WARN, __FILE__, __func__, __LINE__, msg)
#define ARE_LOG_ERROR(msg) are::Logger::log(are::LogLevel::ARE_LOG_ERROR, __FILE__, __func__, __LINE__, msg)
#define ARE_LOG_CRITICAL(msg) are::Logger::log(are::LogLevel::ARE_LOG_CRITICAL, __FILE__, __func__, __LINE__, msg)
#endif // ARE_INCLUDE_CORE_LOGGER_H

View File

@ -49,7 +49,7 @@ BVH::~BVH() {
bool BVH::build(const std::vector<std::shared_ptr<Mesh>>& meshes) {
clear();
Logger::info("Building BVH...");
ARE_LOG_INFO("Building BVH...");
// Extract all triangles from meshes
for (const auto& mesh : meshes) {
@ -88,7 +88,7 @@ bool BVH::build(const std::vector<std::shared_ptr<Mesh>>& meshes) {
}
if (triangles_.empty()) {
Logger::warning("No triangles to build BVH");
ARE_LOG_WARN("No triangles to build BVH");
return false;
}
@ -107,7 +107,7 @@ bool BVH::build(const std::vector<std::shared_ptr<Mesh>>& meshes) {
// Build BVH recursively
build_recursive_(0, 0, static_cast<uint>(triangles_.size()));
Logger::info("BVH built: " + std::to_string(nodes_.size()) + " nodes, " +
ARE_LOG_INFO("BVH built: " + std::to_string(nodes_.size()) + " nodes, " +
std::to_string(triangles_.size()) + " triangles");
return true;
@ -260,7 +260,7 @@ AABB BVH::calculate_centroid_bounds_(uint first_prim, uint prim_count) {
bool BVH::upload_to_gpu(Buffer& node_buffer, Buffer& triangle_buffer) {
if (nodes_.empty() || triangles_.empty()) {
Logger::error("Cannot upload empty BVH to GPU");
ARE_LOG_ERROR("Cannot upload empty BVH to GPU");
return false;
}
@ -307,7 +307,7 @@ bool BVH::upload_to_gpu(Buffer& node_buffer, Buffer& triangle_buffer) {
node_gpu.size() * sizeof(BVHNodeGpu),
node_gpu.data(),
BufferUsage::STATIC_DRAW)) {
Logger::error("Failed to upload BVH nodes to GPU");
ARE_LOG_ERROR("Failed to upload BVH nodes to GPU");
return false;
}
@ -315,11 +315,11 @@ bool BVH::upload_to_gpu(Buffer& node_buffer, Buffer& triangle_buffer) {
tri_gpu.size() * sizeof(TriangleGpu),
tri_gpu.data(),
BufferUsage::STATIC_DRAW)) {
Logger::error("Failed to upload BVH triangles to GPU");
ARE_LOG_ERROR("Failed to upload BVH triangles to GPU");
return false;
}
Logger::info("BVH uploaded to GPU successfully");
ARE_LOG_INFO("BVH uploaded to GPU successfully");
return true;
}

View File

@ -20,7 +20,7 @@ bool Denoiser::initialize(const std::shared_ptr<Shader>& shader) {
if (initialized_) return true;
if (!shader || !shader->is_valid()) {
Logger::error("Invalid denoise shader");
ARE_LOG_ERROR("Invalid denoise shader");
return false;
}
@ -28,7 +28,7 @@ bool Denoiser::initialize(const std::shared_ptr<Shader>& shader) {
create_output_texture_();
initialized_ = true;
Logger::info("Denoiser initialized");
ARE_LOG_INFO("Denoiser initialized");
return true;
}

View File

@ -21,7 +21,7 @@ GBuffer::~GBuffer() {
bool GBuffer::initialize() {
if (initialized_) {
Logger::warning("GBuffer already initialized");
ARE_LOG_WARN("GBuffer already initialized");
return true;
}
@ -68,7 +68,7 @@ bool GBuffer::initialize() {
glDrawBuffers(GBUFFER_COUNT, draw_buffers);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
Logger::error("GBuffer framebuffer is not complete");
ARE_LOG_ERROR("GBuffer framebuffer is not complete");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return false;
}
@ -76,7 +76,7 @@ bool GBuffer::initialize() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
initialized_ = true;
Logger::info("GBuffer initialized successfully");
ARE_LOG_INFO("GBuffer initialized successfully");
return true;
}
@ -101,7 +101,7 @@ void GBuffer::release() {
}
initialized_ = false;
Logger::info("GBuffer released");
ARE_LOG_INFO("GBuffer released");
}
TextureHandle GBuffer::create_texture_(uint internal_format, uint format, uint type) {
@ -118,7 +118,7 @@ TextureHandle GBuffer::create_texture_(uint internal_format, uint format, uint t
void GBuffer::render(const Scene& scene, const Shader& shader) {
if (!initialized_) {
Logger::error("GBuffer not initialized");
ARE_LOG_ERROR("GBuffer not initialized");
return;
}
@ -151,7 +151,7 @@ void GBuffer::render(const Scene& scene, const Shader& shader) {
for (const auto& mesh : meshes) {
if (!mesh->is_uploaded()) {
Logger::warning("Mesh not uploaded to GPU, skipping");
ARE_LOG_WARN("Mesh not uploaded to GPU, skipping");
continue;
}
@ -216,7 +216,7 @@ void GBuffer::resize(uint width, uint height) {
TextureHandle GBuffer::get_texture(int index) const {
if (index < 0 || index >= GBUFFER_COUNT) {
Logger::error("Invalid G-Buffer texture index");
ARE_LOG_ERROR("Invalid G-Buffer texture index");
return INVALID_HANDLE;
}
return textures_[index];

View File

@ -39,7 +39,7 @@ RayTracer::~RayTracer() {
bool RayTracer::initialize() {
if (initialized_) {
Logger::warning("RayTracer already initialized");
ARE_LOG_WARN("RayTracer already initialized");
return true;
}
@ -62,7 +62,7 @@ bool RayTracer::initialize() {
}
initialized_ = true;
Logger::info("RayTracer initialized successfully");
ARE_LOG_INFO("RayTracer initialized successfully");
return true;
}
@ -92,12 +92,12 @@ void RayTracer::release() {
bvh_built_ = false;
initialized_ = false;
Logger::info("RayTracer released");
ARE_LOG_INFO("RayTracer released");
}
bool RayTracer::rebuild_bvh(const Scene &scene) {
if (!config_.use_bvh_) {
Logger::warning("BVH is disabled in configuration");
ARE_LOG_WARN("BVH is disabled in configuration");
return false;
}
@ -105,32 +105,32 @@ bool RayTracer::rebuild_bvh(const Scene &scene) {
bvh_ = std::make_unique<BVH>();
}
Logger::info("Building BVH for ray tracing...");
ARE_LOG_INFO("Building BVH for ray tracing...");
if (!bvh_->build(scene.get_meshes())) {
Logger::error("Failed to build BVH");
ARE_LOG_ERROR("Failed to build BVH");
return false;
}
if (!bvh_->upload_to_gpu(bvh_node_buffer_, bvh_triangle_buffer_)) {
Logger::error("Failed to upload BVH to GPU");
ARE_LOG_ERROR("Failed to upload BVH to GPU");
return false;
}
bvh_built_ = true;
reset_accumulation();
Logger::info("BVH built and uploaded successfully");
ARE_LOG_INFO("BVH built and uploaded successfully");
return true;
}
void RayTracer::trace(const Scene &scene, const GBuffer &gbuffer, TextureHandle output_texture) {
if (!initialized_) {
Logger::error("RayTracer not initialized");
ARE_LOG_ERROR("RayTracer not initialized");
return;
}
if (!compute_shader_->is_valid()) {
Logger::error("Ray tracing compute shader not loaded");
ARE_LOG_ERROR("Ray tracing compute shader not loaded");
return;
}
@ -144,7 +144,7 @@ void RayTracer::trace(const Scene &scene, const GBuffer &gbuffer, TextureHandle
// Use compute shader
if (!compute_shader_ || !compute_shader_->is_valid()) {
Logger::error("Ray tracing compute shader not set or invalid");
ARE_LOG_ERROR("Ray tracing compute shader not set or invalid");
return;
}
compute_shader_->use();
@ -347,7 +347,7 @@ void RayTracer::bind_gbuffer_(const GBuffer &gbuffer) {
void RayTracer::set_compute_shader(const std::shared_ptr<Shader> &shader) {
compute_shader_ = shader;
Logger::info("Compute shader set for RayTracer");
ARE_LOG_INFO("Compute shader set for RayTracer");
}
} // namespace are

View File

@ -17,23 +17,23 @@ Renderer::~Renderer() {
bool Renderer::initialize() {
if (initialized_) {
Logger::warning("Renderer already initialized");
ARE_LOG_WARN("Renderer already initialized");
return true;
}
Logger::info("Initializing Aurora Rendering Engine...");
ARE_LOG_INFO("Initializing Aurora Rendering Engine...");
// Initialize shader manager
shader_manager_ = std::make_unique<ShaderManager>();
if (!shader_manager_->initialize()) {
Logger::error("Failed to initialize shader manager");
ARE_LOG_ERROR("Failed to initialize shader manager");
return false;
}
// Initialize G-Buffer
gbuffer_ = std::make_unique<GBuffer>(config_.width_, config_.height_);
if (!gbuffer_->initialize()) {
Logger::error("Failed to initialize G-Buffer");
ARE_LOG_ERROR("Failed to initialize G-Buffer");
return false;
}
@ -48,14 +48,14 @@ bool Renderer::initialize() {
raytracer_ = std::make_unique<RayTracer>(config_.width_, config_.height_, rt_config);
if (!raytracer_->initialize()) {
Logger::error("Failed to initialize ray tracer");
ARE_LOG_ERROR("Failed to initialize ray tracer");
return false;
}
// Pass compute shader to ray tracer
const auto& rt_shader = shader_manager_->get_raytracing_shader();
if (!rt_shader || !rt_shader->is_valid()) {
Logger::error("Ray tracing shader is invalid");
ARE_LOG_ERROR("Ray tracing shader is invalid");
return false;
}
raytracer_->set_compute_shader(rt_shader);
@ -63,19 +63,19 @@ bool Renderer::initialize() {
// Initialize screen blit
screen_blit_ = std::make_unique<ScreenBlit>();
if (!screen_blit_->initialize()) {
Logger::error("Failed to initialize screen blit");
ARE_LOG_ERROR("Failed to initialize screen blit");
return false;
}
denoiser_ = std::make_unique<Denoiser>(config_.width_, config_.height_);
const auto& denoise_shader = shader_manager_->get_denoise_shader();
if (!denoiser_->initialize(denoise_shader)) {
Logger::error("Failed to initialize denoiser");
ARE_LOG_ERROR("Failed to initialize denoiser");
return false;
}
initialized_ = true;
Logger::info("Aurora Rendering Engine initialized successfully");
ARE_LOG_INFO("Aurora Rendering Engine initialized successfully");
return true;
}
@ -83,7 +83,7 @@ void Renderer::shutdown() {
if (!initialized_)
return;
Logger::info("Shutting down Aurora Rendering Engine...");
ARE_LOG_INFO("Shutting down Aurora Rendering Engine...");
if (screen_blit_) {
screen_blit_->release();
@ -111,14 +111,14 @@ void Renderer::shutdown() {
}
initialized_ = false;
Logger::info("Aurora Rendering Engine shut down");
ARE_LOG_INFO("Aurora Rendering Engine shut down");
}
RenderStats Renderer::render(const Scene& scene, TextureHandle output_texture) {
RenderStats stats = {};
if (!initialized_) {
Logger::error("Renderer not initialized");
ARE_LOG_ERROR("Renderer not initialized");
return stats;
}
@ -130,7 +130,7 @@ RenderStats Renderer::render(const Scene& scene, TextureHandle output_texture) {
const auto& gbuffer_shader = shader_manager_->get_gbuffer_shader();
if (!gbuffer_shader || !gbuffer_shader->is_valid()) {
Logger::error("G-Buffer shader is invalid");
ARE_LOG_ERROR("G-Buffer shader is invalid");
return stats;
}
gbuffer_->render(scene, *gbuffer_shader);
@ -203,7 +203,7 @@ void Renderer::resize(uint width, uint height) {
raytracer_->resize(width, height);
denoiser_->resize(width, height);
Logger::info("Renderer resized to " + std::to_string(width) + "x" + std::to_string(height));
ARE_LOG_INFO("Renderer resized to " + std::to_string(width) + "x" + std::to_string(height));
}
}

View File

@ -43,13 +43,13 @@ ScreenBlit::~ScreenBlit() {
bool ScreenBlit::initialize() {
if (initialized_) {
Logger::warning("ScreenBlit already initialized");
ARE_LOG_WARN("ScreenBlit already initialized");
return true;
}
// Compile shader
if (!shader_.compile(VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)) {
Logger::error("Failed to compile screen blit shader");
ARE_LOG_ERROR("Failed to compile screen blit shader");
return false;
}
@ -57,7 +57,7 @@ bool ScreenBlit::initialize() {
create_quad_();
initialized_ = true;
Logger::info("ScreenBlit initialized successfully");
ARE_LOG_INFO("ScreenBlit initialized successfully");
return true;
}
@ -81,7 +81,7 @@ void ScreenBlit::release() {
void ScreenBlit::blit(TextureHandle texture, int x, int y, uint width, uint height) {
if (!initialized_) {
Logger::error("ScreenBlit not initialized");
ARE_LOG_ERROR("ScreenBlit not initialized");
return;
}

View File

@ -13,19 +13,19 @@ ShaderManager::~ShaderManager() {
bool ShaderManager::initialize() {
if (initialized_) {
Logger::warning("ShaderManager already initialized");
ARE_LOG_WARN("ShaderManager already initialized");
return true;
}
Logger::info("Loading built-in shaders...");
ARE_LOG_INFO("Loading built-in shaders...");
if (!load_builtin_shaders_()) {
Logger::error("Failed to load built-in shaders");
ARE_LOG_ERROR("Failed to load built-in shaders");
return false;
}
initialized_ = true;
Logger::info("ShaderManager initialized successfully");
ARE_LOG_INFO("ShaderManager initialized successfully");
return true;
}
@ -42,7 +42,7 @@ void ShaderManager::release() {
denoise_shader_.reset();
initialized_ = false;
Logger::info("ShaderManager released");
ARE_LOG_INFO("ShaderManager released");
}
std::shared_ptr<Shader> ShaderManager::load_shader(const std::string& name,
@ -50,18 +50,18 @@ std::shared_ptr<Shader> ShaderManager::load_shader(const std::string& name,
const std::string& fragment_path) {
auto it = shader_cache_.find(name);
if (it != shader_cache_.end()) {
Logger::info("Shader '" + name + "' loaded from cache");
ARE_LOG_INFO("Shader '" + name + "' loaded from cache");
return it->second;
}
auto shader = std::make_shared<Shader>();
if (!shader->load(vertex_path, fragment_path)) {
Logger::error("Failed to load shader '" + name + "'");
ARE_LOG_ERROR("Failed to load shader '" + name + "'");
return nullptr;
}
shader_cache_[name] = shader;
Logger::info("Shader '" + name + "' loaded successfully");
ARE_LOG_INFO("Shader '" + name + "' loaded successfully");
return shader;
}
@ -69,18 +69,18 @@ std::shared_ptr<Shader> ShaderManager::load_compute_shader(const std::string& na
const std::string& compute_path) {
auto it = shader_cache_.find(name);
if (it != shader_cache_.end()) {
Logger::info("Compute shader '" + name + "' loaded from cache");
ARE_LOG_INFO("Compute shader '" + name + "' loaded from cache");
return it->second;
}
auto shader = std::make_shared<Shader>();
if (!shader->load_compute(compute_path)) {
Logger::error("Failed to load compute shader '" + name + "'");
ARE_LOG_ERROR("Failed to load compute shader '" + name + "'");
return nullptr;
}
shader_cache_[name] = shader;
Logger::info("Compute shader '" + name + "' loaded successfully");
ARE_LOG_INFO("Compute shader '" + name + "' loaded successfully");
return shader;
}
@ -88,35 +88,35 @@ std::shared_ptr<Shader> ShaderManager::get_shader(const std::string& name) const
auto it = shader_cache_.find(name);
if (it != shader_cache_.end()) return it->second;
Logger::warning("Shader '" + name + "' not found in cache");
ARE_LOG_WARN("Shader '" + name + "' not found in cache");
return nullptr;
}
bool ShaderManager::load_builtin_shaders_() {
gbuffer_shader_ = std::make_shared<Shader>();
if (!gbuffer_shader_->load("shaders/gbuffer.vert", "shaders/gbuffer.frag")) {
Logger::error("Failed to load G-Buffer shader");
ARE_LOG_ERROR("Failed to load G-Buffer shader");
return false;
}
shader_cache_["gbuffer"] = gbuffer_shader_;
Logger::info("Loading ray tracing compute shader...");
ARE_LOG_INFO("Loading ray tracing compute shader...");
raytracing_shader_ = std::make_shared<Shader>();
if (!raytracing_shader_->load_compute("shaders/raytracing.comp")) {
Logger::error("Failed to load ray tracing shader");
ARE_LOG_ERROR("Failed to load ray tracing shader");
return false;
}
shader_cache_["raytracing"] = raytracing_shader_;
Logger::info("Ray tracing shader loaded successfully");
ARE_LOG_INFO("Ray tracing shader loaded successfully");
Logger::info("Loading denoise compute shader...");
ARE_LOG_INFO("Loading denoise compute shader...");
denoise_shader_ = std::make_shared<Shader>();
if (!denoise_shader_->load_compute("shaders/denoiser.comp")) {
Logger::error("Failed to load denoise shader");
ARE_LOG_ERROR("Failed to load denoise shader");
return false;
}
shader_cache_["denoise"] = denoise_shader_;
Logger::info("Denoise shader loaded successfully");
ARE_LOG_INFO("Denoise shader loaded successfully");
return true;
}

View File

@ -61,7 +61,7 @@ Buffer::~Buffer() {
bool Buffer::create(BufferType type, size_t size, const void* data, BufferUsage usage) {
if (handle_ != INVALID_HANDLE) {
Logger::warning("Buffer already created, releasing old buffer");
ARE_LOG_WARN("Buffer already created, releasing old buffer");
release();
}
@ -78,18 +78,18 @@ bool Buffer::create(BufferType type, size_t size, const void* data, BufferUsage
glBufferData(gl_type, size, data, gl_usage);
glBindBuffer(gl_type, 0);
Logger::info("Buffer created successfully");
ARE_LOG_INFO("Buffer created successfully");
return true;
}
void Buffer::update(size_t offset, size_t size, const void* data) {
if (handle_ == INVALID_HANDLE) {
Logger::error("Cannot update invalid buffer");
ARE_LOG_ERROR("Cannot update invalid buffer");
return;
}
if (offset + size > size_) {
Logger::error("Buffer update out of bounds");
ARE_LOG_ERROR("Buffer update out of bounds");
return;
}
@ -102,7 +102,7 @@ void Buffer::update(size_t offset, size_t size, const void* data) {
void Buffer::bind() const {
if (handle_ == INVALID_HANDLE) {
Logger::warning("Attempting to bind invalid buffer");
ARE_LOG_WARN("Attempting to bind invalid buffer");
return;
}
@ -112,7 +112,7 @@ void Buffer::bind() const {
void Buffer::bind_base(uint binding_point) const {
if (handle_ == INVALID_HANDLE) {
Logger::warning("Attempting to bind invalid buffer");
ARE_LOG_WARN("Attempting to bind invalid buffer");
return;
}

View File

@ -39,7 +39,7 @@ bool Shader::load(const std::string& vertex_path, const std::string& fragment_pa
std::string fragment_source = read_file_(fragment_path);
if (vertex_source.empty() || fragment_source.empty()) {
Logger::error("Failed to read shader files");
ARE_LOG_ERROR("Failed to read shader files");
return false;
}
@ -50,7 +50,7 @@ bool Shader::load_compute(const std::string& compute_path) {
std::string compute_source = read_file_(compute_path);
if (compute_source.empty()) {
Logger::error("Failed to read compute shader file");
ARE_LOG_ERROR("Failed to read compute shader file");
return false;
}
@ -148,7 +148,7 @@ int Shader::get_uniform_location_(const std::string& name) const { // 改为con
uniform_cache_[name] = location; // mutable允许修改
if (location == -1) {
Logger::warning("Uniform '" + name + "' not found in shader");
ARE_LOG_WARN("Uniform '" + name + "' not found in shader");
}
return location;
@ -168,7 +168,7 @@ uint Shader::compile_shader_(const std::string& source, uint type) {
std::string type_str = (type == GL_VERTEX_SHADER) ? "VERTEX" :
(type == GL_FRAGMENT_SHADER) ? "FRAGMENT" : "COMPUTE";
Logger::error("Shader compilation failed (" + type_str + "): " + std::string(info_log));
ARE_LOG_ERROR("Shader compilation failed (" + type_str + "): " + std::string(info_log));
glDeleteShader(shader);
return 0;
@ -191,7 +191,7 @@ bool Shader::link_program_(const uint* shaders, uint count) {
if (!success) {
char info_log[512];
glGetProgramInfoLog(handle_, 512, nullptr, info_log);
Logger::error("Shader linking failed: " + std::string(info_log));
ARE_LOG_ERROR("Shader linking failed: " + std::string(info_log));
glDeleteProgram(handle_);
handle_ = INVALID_HANDLE;
@ -204,7 +204,7 @@ bool Shader::link_program_(const uint* shaders, uint count) {
std::string Shader::read_file_(const std::string& path) {
std::ifstream file(path);
if (!file.is_open()) {
Logger::error("Failed to open file: " + path);
ARE_LOG_ERROR("Failed to open file: " + path);
return "";
}

View File

@ -144,7 +144,7 @@ bool Texture::load_from_file(const std::string& path, bool generate_mipmaps) {
unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, 0);
if (!data) {
Logger::error("Failed to load texture: " + path);
ARE_LOG_ERROR("Failed to load texture: " + path);
return false;
}
@ -156,7 +156,7 @@ bool Texture::load_from_file(const std::string& path, bool generate_mipmaps) {
case 3: format = TextureFormat::RGB8; break;
case 4: format = TextureFormat::RGBA8; break;
default:
Logger::error("Unsupported channel count: " + std::to_string(channels));
ARE_LOG_ERROR("Unsupported channel count: " + std::to_string(channels));
stbi_image_free(data);
return false;
}
@ -181,13 +181,13 @@ bool Texture::load_from_file(const std::string& path, bool generate_mipmaps) {
this->generate_mipmaps();
}
Logger::info("Texture loaded successfully: " + path);
ARE_LOG_INFO("Texture loaded successfully: " + path);
return true;
}
bool Texture::create(uint width, uint height, TextureFormat format) {
if (handle_ != INVALID_HANDLE) {
Logger::warning("Texture already created, releasing old texture");
ARE_LOG_WARN("Texture already created, releasing old texture");
release();
}
@ -217,12 +217,12 @@ bool Texture::create(uint width, uint height, TextureFormat format) {
bool Texture::upload(const void* data, uint width, uint height, TextureFormat format) {
if (handle_ == INVALID_HANDLE) {
Logger::error("Cannot upload to invalid texture");
ARE_LOG_ERROR("Cannot upload to invalid texture");
return false;
}
if (width != width_ || height != height_ || format != format_) {
Logger::warning("Upload parameters differ from texture creation, recreating texture");
ARE_LOG_WARN("Upload parameters differ from texture creation, recreating texture");
create(width, height, format);
}
@ -240,7 +240,7 @@ bool Texture::upload(const void* data, uint width, uint height, TextureFormat fo
void Texture::set_filter(TextureFilter min_filter, TextureFilter mag_filter) {
if (handle_ == INVALID_HANDLE) {
Logger::error("Cannot set filter on invalid texture");
ARE_LOG_ERROR("Cannot set filter on invalid texture");
return;
}
@ -252,7 +252,7 @@ void Texture::set_filter(TextureFilter min_filter, TextureFilter mag_filter) {
void Texture::set_wrap(TextureWrap wrap_s, TextureWrap wrap_t) {
if (handle_ == INVALID_HANDLE) {
Logger::error("Cannot set wrap mode on invalid texture");
ARE_LOG_ERROR("Cannot set wrap mode on invalid texture");
return;
}
@ -264,7 +264,7 @@ void Texture::set_wrap(TextureWrap wrap_s, TextureWrap wrap_t) {
void Texture::generate_mipmaps() {
if (handle_ == INVALID_HANDLE) {
Logger::error("Cannot generate mipmaps for invalid texture");
ARE_LOG_ERROR("Cannot generate mipmaps for invalid texture");
return;
}
@ -277,7 +277,7 @@ void Texture::generate_mipmaps() {
void Texture::bind(uint unit) const {
if (handle_ == INVALID_HANDLE) {
Logger::warning("Attempting to bind invalid texture");
ARE_LOG_WARN("Attempting to bind invalid texture");
return;
}

View File

@ -37,17 +37,17 @@ void Mesh::set_transform(const Mat4& transform) {
bool Mesh::upload_to_gpu() {
if (uploaded_) {
Logger::warning("Mesh already uploaded to GPU");
ARE_LOG_WARN("Mesh already uploaded to GPU");
return true;
}
if (vertices_.empty()) {
Logger::error("Cannot upload mesh: no vertices");
ARE_LOG_ERROR("Cannot upload mesh: no vertices");
return false;
}
if (indices_.empty()) {
Logger::error("Cannot upload mesh: no indices");
ARE_LOG_ERROR("Cannot upload mesh: no indices");
return false;
}
@ -91,7 +91,7 @@ bool Mesh::upload_to_gpu() {
glBindVertexArray(0);
uploaded_ = true;
Logger::info("Mesh uploaded to GPU successfully");
ARE_LOG_INFO("Mesh uploaded to GPU successfully");
return true;
}

View File

@ -20,7 +20,7 @@ static std::string trim(const std::string& str) {
bool Config::load(const std::string& path) {
std::ifstream file(path);
if (!file.is_open()) {
Logger::error("Failed to open config file: " + path);
ARE_LOG_ERROR("Failed to open config file: " + path);
return false;
}
@ -58,14 +58,14 @@ bool Config::load(const std::string& path) {
}
}
Logger::info("Config loaded: " + path + " (" + std::to_string(g_config_map.size()) + " entries)");
ARE_LOG_INFO("Config loaded: " + path + " (" + std::to_string(g_config_map.size()) + " entries)");
return true;
}
bool Config::save(const std::string& path) {
std::ofstream file(path);
if (!file.is_open()) {
Logger::error("Failed to open config file for writing: " + path);
ARE_LOG_ERROR("Failed to open config file for writing: " + path);
return false;
}
@ -73,7 +73,7 @@ bool Config::save(const std::string& path) {
file << pair.first << "=" << pair.second << std::endl;
}
Logger::info("Config saved: " + path);
ARE_LOG_INFO("Config saved: " + path);
return true;
}
@ -91,7 +91,7 @@ int Config::get_int(const std::string& key, int default_value) {
try {
return std::stoi(it->second);
} catch (...) {
Logger::warning("Failed to parse int for key: " + key);
ARE_LOG_WARN("Failed to parse int for key: " + key);
}
}
return default_value;
@ -103,7 +103,7 @@ float Config::get_float(const std::string& key, float default_value) {
try {
return std::stof(it->second);
} catch (...) {
Logger::warning("Failed to parse float for key: " + key);
ARE_LOG_WARN("Failed to parse float for key: " + key);
}
}
return default_value;

View File

@ -1,103 +1,159 @@
#include "utils/logger.h"
#include <iostream>
#include <fstream>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <mutex>
#include <cstring>
namespace are {
// Static members
static LogLevel g_min_level = LogLevel::DEBUG;
static std::ofstream g_log_file;
static bool g_initialized = false;
std::shared_ptr<void> Logger::logger_impl_ = nullptr;
bool Logger::initialized_ = false;
bool Logger::initialize(const std::string& log_file) {
if (g_initialized) {
return true;
void Logger::init(LogLevel min_level) {
if (initialized_) {
return;
}
if (!log_file.empty()) {
g_log_file.open(log_file, std::ios::out | std::ios::app);
if (!g_log_file.is_open()) {
std::cerr << "Failed to open log file: " << log_file << std::endl;
return false;
try {
// Create console sink with color support
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console_sink->set_pattern("[%H:%M:%S.%e] [%^%l%$] %v");
// Create logger with console sink
auto logger = std::make_shared<spdlog::logger>("are", console_sink);
// Set log level
switch (min_level) {
case LogLevel::ARE_LOG_TRACE:
logger->set_level(spdlog::level::trace);
break;
case LogLevel::ARE_LOG_DEBUG:
logger->set_level(spdlog::level::debug);
break;
case LogLevel::ARE_LOG_INFO:
logger->set_level(spdlog::level::info);
break;
case LogLevel::ARE_LOG_WARN:
logger->set_level(spdlog::level::warn);
break;
case LogLevel::ARE_LOG_ERROR:
logger->set_level(spdlog::level::err);
break;
case LogLevel::ARE_LOG_CRITICAL:
logger->set_level(spdlog::level::critical);
break;
}
// Flush on error or higher
logger->flush_on(spdlog::level::err);
// Set as default logger
spdlog::set_default_logger(logger);
logger_impl_ = logger;
initialized_ = true;
} catch (const std::exception& e) {
fprintf(stderr, "[ARE] Failed to initialize logger: %s\n", e.what());
}
g_initialized = true;
return true;
}
void Logger::shutdown() {
if (g_log_file.is_open()) {
g_log_file.close();
if (!initialized_) {
return;
}
g_initialized = false;
}
static std::string get_current_time() {
auto now = std::time(nullptr);
auto tm = *std::localtime(&now);
std::ostringstream oss;
oss << std::put_time(&tm, "%H:%M:%S");
return oss.str();
}
static std::string level_to_string(LogLevel level) {
switch (level) {
case LogLevel::DEBUG: return "DEBUG";
case LogLevel::INFO: return "INFO";
case LogLevel::WARNING: return "WARN";
case LogLevel::ERROR: return "ERROR";
case LogLevel::FATAL: return "FATAL";
default: return "UNKNOWN";
try {
spdlog::shutdown();
logger_impl_.reset();
initialized_ = false;
} catch (const std::exception& e) {
fprintf(stderr, "[ARE] Error during logger shutdown: %s\n", e.what());
}
}
void Logger::log(LogLevel level, const std::string& message) {
if (level < g_min_level) return;
void Logger::log(LogLevel level, const char* file, const char* func,
int line, const std::string& message) {
if (!initialized_) {
init();
}
// Extract filename from full path
const char* filename = file;
const char* last_slash = nullptr;
std::string time_str = get_current_time();
std::string level_str = level_to_string(level);
std::string formatted = "[" + time_str + "] [" + level_str + "] " + message;
// Console output
if (level >= LogLevel::ERROR) {
std::cerr << formatted << std::endl;
} else {
std::cout << formatted << std::endl;
for (const char* p = file; *p; ++p) {
if (*p == '/' || *p == '\\') {
last_slash = p;
}
}
// File output
if (g_log_file.is_open()) {
g_log_file << formatted << std::endl;
g_log_file.flush();
if (last_slash) {
filename = last_slash + 1;
}
}
void Logger::debug(const std::string& message) {
log(LogLevel::DEBUG, message);
}
// Format message with location information
std::string formatted = message + " (" + filename + "-" + func + "():" + std::to_string(line) + ")";
void Logger::info(const std::string& message) {
log(LogLevel::INFO, message);
}
void Logger::warning(const std::string& message) {
log(LogLevel::WARNING, message);
}
void Logger::error(const std::string& message) {
log(LogLevel::ERROR, message);
}
void Logger::fatal(const std::string& message) {
log(LogLevel::FATAL, message);
try {
auto logger = std::static_pointer_cast<spdlog::logger>(logger_impl_);
switch (level) {
case LogLevel::ARE_LOG_TRACE:
logger->trace(formatted);
break;
case LogLevel::ARE_LOG_DEBUG:
logger->debug(formatted);
break;
case LogLevel::ARE_LOG_INFO:
logger->info(formatted);
break;
case LogLevel::ARE_LOG_WARN:
logger->warn(formatted);
break;
case LogLevel::ARE_LOG_ERROR:
logger->error(formatted);
break;
case LogLevel::ARE_LOG_CRITICAL:
logger->critical(formatted);
break;
}
} catch (const std::exception& e) {
fprintf(stderr, "[ARE] Logging error: %s\n", e.what());
}
}
void Logger::set_level(LogLevel level) {
g_min_level = level;
if (!initialized_) {
return;
}
try {
auto logger = std::static_pointer_cast<spdlog::logger>(logger_impl_);
switch (level) {
case LogLevel::ARE_LOG_TRACE:
logger->set_level(spdlog::level::trace);
break;
case LogLevel::ARE_LOG_DEBUG:
logger->set_level(spdlog::level::debug);
break;
case LogLevel::ARE_LOG_INFO:
logger->set_level(spdlog::level::info);
break;
case LogLevel::ARE_LOG_WARN:
logger->set_level(spdlog::level::warn);
break;
case LogLevel::ARE_LOG_ERROR:
logger->set_level(spdlog::level::err);
break;
case LogLevel::ARE_LOG_CRITICAL:
logger->set_level(spdlog::level::critical);
break;
}
} catch (const std::exception& e) {
fprintf(stderr, "[ARE] Error setting log level: %s\n", e.what());
}
}
} // namespace are