mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
refactor: logger (#35)
* refactor(log): convert Logger from namespace to class with static methods - Replace the Logger namespace of free functions with a Logger class containing static methods (info, error, warn, debug). - Simplify log calls by removing explicit source_location parameters; adopt `std::print` for output formatting. - Undefine common macro names (DEBUG, INFO, ERROR, WARN) to avoid collisions. - Update `renderer.cpp` to use `Logger::debug` instead of the old `Logger::log`. - Add missing `#include <source_location>` in `audio_error.hpp`. - Fix early return condition in `WorldScene::set_pause`. * refactor(camera): remove reset_camera method and first-mouse flag * refactor: replace --no-debug with logging options, add assertions, fix typo - Removed `--no-debug` CLI flag and added `--logs-path`, `--log-level`, `--enable-filelog`, `--enable-consolelog`. - Added file logging support with daily rotation, log level threshold, and console/file output control. - Added `m_init` check in `Config::get`/`set` to prevent use before initialization. - Fixed typo in `DebugCollector::destroy` (`distory` → `destory`). - Removed `debug_on` parameter from `Renderer::init`; OpenGL debug output is now unconditionally enabled in debug builds. * feat(debug): enable GL debug context flag in debug builds
This commit is contained in:
@@ -64,6 +64,7 @@ private:
|
||||
inline static int fps = 0;
|
||||
Argument m_argument;
|
||||
bool m_running = true;
|
||||
bool m_opengl_init = false;
|
||||
void init(int argc, char** argv);
|
||||
void handle_argument(int argc, char** argv);
|
||||
auto init_camera();
|
||||
|
||||
@@ -6,9 +6,12 @@ struct Argument {
|
||||
std::optional<int> port;
|
||||
std::optional<std::string> ip;
|
||||
std::optional<std::string> player;
|
||||
std::optional<bool> no_debug;
|
||||
std::optional<std::string> language;
|
||||
std::optional<std::string> video_driver;
|
||||
std::optional<bool> enable_exclusive;
|
||||
std::optional<std::string> logs_path;
|
||||
std::optional<int> log_level;
|
||||
std::optional<bool> enable_filelog;
|
||||
std::optional<bool> enable_consolelog;
|
||||
};
|
||||
} // namespace Cubed
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Cubed/tools/log.hpp"
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <source_location>
|
||||
namespace Cubed {
|
||||
inline void check_al_error(
|
||||
std::source_location loaction = std::source_location::current()) {
|
||||
|
||||
@@ -18,7 +18,6 @@ private:
|
||||
THIRD_PERSON_FRONT,
|
||||
};
|
||||
|
||||
bool m_firse_mouse = true;
|
||||
ClientPlayer* m_player;
|
||||
float m_last_mouse_x, m_last_mouse_y;
|
||||
glm::vec3 m_camera_pos;
|
||||
@@ -38,7 +37,6 @@ public:
|
||||
|
||||
void camera_init(ClientPlayer* player);
|
||||
void hot_reload();
|
||||
void reset_camera();
|
||||
void update_cursor_position_camera(float offset_x, float offset_y);
|
||||
|
||||
const glm::mat4 get_camera_lookat() const;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/toml.utils.hpp"
|
||||
|
||||
namespace Cubed {
|
||||
@@ -19,6 +20,7 @@ public:
|
||||
|
||||
template <TOML::TomlValueType T>
|
||||
T get(std::string_view key, T default_value) {
|
||||
ASSERT(m_init);
|
||||
if (auto* node = find_node(m_tbl, key)) {
|
||||
if (auto value = node->value<T>())
|
||||
return *value;
|
||||
@@ -30,6 +32,7 @@ public:
|
||||
}
|
||||
|
||||
template <TOML::TomlValueType T> void set(std::string_view key, T&& value) {
|
||||
ASSERT(m_init);
|
||||
auto pos = key.rfind('.');
|
||||
|
||||
toml::table* table;
|
||||
@@ -53,6 +56,7 @@ public:
|
||||
|
||||
private:
|
||||
toml::table m_tbl;
|
||||
bool m_init = false;
|
||||
const std::string CONGIF_PATH;
|
||||
const toml::node* find_node(const toml::table& root,
|
||||
std::string_view path) const;
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Cubed {
|
||||
class DebugCollector {
|
||||
public:
|
||||
static DebugCollector& get();
|
||||
static void distory();
|
||||
static void destory();
|
||||
DebugCollector();
|
||||
|
||||
void report(const std::string& name, std::string_view content);
|
||||
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
Renderer(TextureManager& texture_manager, Config& config);
|
||||
~Renderer();
|
||||
void reload_config();
|
||||
void init(bool debug_on);
|
||||
void init();
|
||||
const Shader& get_shader(const std::string& name) const;
|
||||
void begin_frame();
|
||||
void end_frame();
|
||||
|
||||
@@ -1,85 +1,184 @@
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <source_location>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <print>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <syncstream>
|
||||
#include <utility>
|
||||
#ifdef DEBUG
|
||||
#undef DEBUG
|
||||
#endif
|
||||
|
||||
#ifdef INFO
|
||||
#undef INFO
|
||||
#endif
|
||||
|
||||
#ifdef ERROR
|
||||
#undef ERROR
|
||||
#endif
|
||||
|
||||
#ifdef WARN
|
||||
#undef WARN
|
||||
#endif
|
||||
|
||||
namespace Cubed {
|
||||
|
||||
namespace Logger {
|
||||
enum class Level { L_TRACE, L_DEBUG, L_INFO, L_ERROR, L_WARN };
|
||||
class Logger {
|
||||
public:
|
||||
enum class Level { DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3 };
|
||||
static constexpr Level get_level(int i) {
|
||||
switch (i) {
|
||||
case std::to_underlying(Level::DEBUG):
|
||||
return Level::DEBUG;
|
||||
|
||||
template <typename... Args>
|
||||
inline void info(std::format_string<Args...> fmt, Args&&... args) {
|
||||
auto now_time = std::chrono::time_point_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now());
|
||||
|
||||
std::string msg = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||
std::osyncstream(std::cout)
|
||||
<< "\033[1;32m" << std::format("[INFO][{:%Y-%m-%d %H:%M:%S}]", now_time)
|
||||
<< msg << "\033[0m"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void error(std::format_string<Args...> fmt, Args&&... args) {
|
||||
auto now_time = std::chrono::time_point_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now());
|
||||
std::string msg = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||
std::osyncstream(std::cerr)
|
||||
<< "\033[1;31m"
|
||||
<< std::format("[ERROR][{:%Y-%m-%d %H:%M:%S}]", now_time) << msg
|
||||
<< "\033[0m"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void warn(std::format_string<Args...> fmt, Args&&... args) {
|
||||
auto now_time = std::chrono::time_point_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now());
|
||||
std::string msg = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||
std::osyncstream(std::cout)
|
||||
<< "\033[1;33m" << std::format("[WARN][{:%Y-%m-%d %H:%M:%S}]", now_time)
|
||||
<< msg << "\033[0m"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void log(Level level, std::source_location loc,
|
||||
std::format_string<Args...> fmt, Args&&... args) {
|
||||
auto now_time = std::chrono::time_point_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now());
|
||||
std::string msg = std::vformat(fmt.get(), std::make_format_args(args...));
|
||||
switch (level) {
|
||||
case Logger::Level::L_TRACE:
|
||||
std::osyncstream(std::cout)
|
||||
<< "\033[1;34m"
|
||||
<< std::format("[TRACE][{:%Y-%m-%d %H:%M:%S}]", now_time) << "["
|
||||
<< loc.file_name() << ":" << loc.line() << "]"
|
||||
<< "[" << loc.function_name() << "]" << msg << "\033[0m"
|
||||
<< "\n";
|
||||
break;
|
||||
case Logger::Level::L_DEBUG:
|
||||
std::osyncstream(std::cout)
|
||||
<< "\033[1;34m"
|
||||
<< std::format("[DEBUG][{:%Y-%m-%d %H:%M:%S}]", now_time) << msg
|
||||
<< "\033[0m"
|
||||
<< "\n";
|
||||
break;
|
||||
case Logger::Level::L_INFO:
|
||||
info(fmt, std::forward<Args>(args)...);
|
||||
break;
|
||||
case Logger::Level::L_WARN:
|
||||
warn(fmt, std::forward<Args>(args)...);
|
||||
break;
|
||||
case Logger::Level::L_ERROR:
|
||||
error(fmt, std::forward<Args>(args)...);
|
||||
break;
|
||||
case std::to_underlying(Level::INFO):
|
||||
return Level::INFO;
|
||||
case std::to_underlying(Level::WARN):
|
||||
return Level::WARN;
|
||||
case std::to_underlying(Level::ERROR):
|
||||
return Level::ERROR;
|
||||
default:
|
||||
return Level::INFO;
|
||||
}
|
||||
}
|
||||
Logger() { m_file_stream = std::make_unique<std::ofstream>(); }
|
||||
~Logger() { m_file_stream.reset(); }
|
||||
static Logger& instance() {
|
||||
static Logger inst;
|
||||
return inst;
|
||||
}
|
||||
static void set_level(Level level) { instance().m_level = level; }
|
||||
static void set_console_write(bool write) {
|
||||
instance().m_console_write = write;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Logger
|
||||
static void set_file_write(bool write) { instance().m_file_write = write; }
|
||||
|
||||
static void set_logs_path(const std::string& path) {
|
||||
std::unique_lock lock(instance().m_mutex);
|
||||
instance().m_logs_path = path;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static void info(std::format_string<Args...> fmt, Args&&... args) {
|
||||
instance().log(Level::INFO, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
static void error(std::format_string<Args...> fmt, Args&&... args) {
|
||||
instance().log(Level::ERROR, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
static void warn(std::format_string<Args...> fmt, Args&&... args) {
|
||||
instance().log(Level::WARN, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
static void debug(std::format_string<Args...> fmt, Args&&... args) {
|
||||
instance().log(Level::DEBUG, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
void log(Level level, std::format_string<Args...> fmt, Args&&... args) {
|
||||
auto now_time = std::chrono::time_point_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now());
|
||||
if (level < m_level) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto msg = std::format(fmt, std::forward<Args>(args)...);
|
||||
std::string_view level_str;
|
||||
std::string_view color;
|
||||
switch (level) {
|
||||
case Level::INFO:
|
||||
color = INFO_ANSI;
|
||||
level_str = "[INFO]";
|
||||
break;
|
||||
case Level::ERROR:
|
||||
color = ERROR_ANSI;
|
||||
level_str = "[ERROR]";
|
||||
break;
|
||||
case Level::WARN:
|
||||
color = WARN_ANSI;
|
||||
level_str = "[WARN]";
|
||||
break;
|
||||
case Level::DEBUG:
|
||||
color = DEBUG_ANSI;
|
||||
level_str = "[DEBUG]";
|
||||
break;
|
||||
}
|
||||
std::string message =
|
||||
std::format("{}[{:%Y-%m-%d %H:%M:%S}]{}", level_str, now_time, msg);
|
||||
|
||||
if (m_file_write) {
|
||||
|
||||
std::shared_lock lock{m_mutex};
|
||||
auto today = std::chrono::floor<std::chrono::days>(
|
||||
std::chrono::system_clock::now());
|
||||
auto date = std::chrono::year_month_day{today};
|
||||
|
||||
if (!m_today.ok() || date > m_today) {
|
||||
lock.unlock();
|
||||
std::unique_lock l(m_mutex);
|
||||
|
||||
auto today = std::chrono::floor<std::chrono::days>(
|
||||
std::chrono::system_clock::now());
|
||||
auto date = std::chrono::year_month_day{today};
|
||||
|
||||
if (!m_today.ok() || date > m_today) {
|
||||
m_today = date;
|
||||
try {
|
||||
std::filesystem::create_directories(m_logs_path);
|
||||
m_file_stream->close();
|
||||
std::filesystem::path log =
|
||||
m_logs_path / std::format("{:%Y-%m-%d}.log", date);
|
||||
m_file_stream->open(log, std::ios::app);
|
||||
if (!m_file_stream->is_open()) {
|
||||
std::osyncstream(std::cerr)
|
||||
<< "File Stream Open Error\n";
|
||||
}
|
||||
// direct write
|
||||
if (m_file_stream && m_file_stream->is_open()) {
|
||||
std::osyncstream sync_out{*m_file_stream};
|
||||
std::println(sync_out, "{}", message);
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::osyncstream(std::cerr)
|
||||
<< "Catch Logger Error " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (m_file_stream && m_file_stream->is_open()) {
|
||||
std::osyncstream sync_out{*m_file_stream};
|
||||
std::println(sync_out, "{}", message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_console_write) {
|
||||
std::osyncstream sync_out(level == Level::ERROR ? std::cerr
|
||||
: std::cout);
|
||||
std::println(sync_out, "{}{}{}", color, message, CLEAR_ANSI);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr std::string_view CLEAR_ANSI = "\033[0m";
|
||||
static constexpr std::string_view INFO_ANSI = "\033[1;32m";
|
||||
static constexpr std::string_view ERROR_ANSI = "\033[1;31m";
|
||||
static constexpr std::string_view DEBUG_ANSI = "\033[1;34m";
|
||||
static constexpr std::string_view WARN_ANSI = "\033[1;33m";
|
||||
std::filesystem::path m_logs_path{"logs"};
|
||||
std::shared_mutex m_mutex;
|
||||
std::atomic<bool> m_file_write{false};
|
||||
std::atomic<bool> m_console_write{true};
|
||||
std::atomic<Level> m_level{Level::INFO};
|
||||
std::chrono::year_month_day m_today{};
|
||||
std::unique_ptr<std::ofstream> m_file_stream;
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
|
||||
Reference in New Issue
Block a user