diff --git a/Extra2D/include/extra2d/services/logger_service.h b/Extra2D/include/extra2d/services/logger_service.h index 2be0dc2..9f17604 100644 --- a/Extra2D/include/extra2d/services/logger_service.h +++ b/Extra2D/include/extra2d/services/logger_service.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -8,6 +9,41 @@ namespace extra2d { +/** + * @brief 日志颜色结构 + */ +struct LogColor { + uint8_t r, g, b; + + constexpr LogColor() : r(255), g(255), b(255) {} + constexpr LogColor(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {} + + static constexpr LogColor White() { return LogColor(255, 255, 255); } + static constexpr LogColor Gray() { return LogColor(128, 128, 128); } + static constexpr LogColor Red() { return LogColor(255, 85, 85); } + static constexpr LogColor Green() { return LogColor(85, 255, 85); } + static constexpr LogColor Yellow() { return LogColor(255, 255, 85); } + static constexpr LogColor Blue() { return LogColor(85, 85, 255); } + static constexpr LogColor Magenta() { return LogColor(255, 85, 255); } + static constexpr LogColor Cyan() { return LogColor(85, 255, 255); } + static constexpr LogColor Orange() { return LogColor(255, 165, 0); } + + static constexpr LogColor Slate() { return LogColor(100, 116, 139); } + static constexpr LogColor SlateLight() { return LogColor(148, 163, 184); } + static constexpr LogColor Sky() { return LogColor(14, 165, 233); } + static constexpr LogColor SkyLight() { return LogColor(125, 211, 252); } + static constexpr LogColor Emerald() { return LogColor(16, 185, 129); } + static constexpr LogColor EmeraldLight() { return LogColor(110, 231, 183); } + static constexpr LogColor Amber() { return LogColor(245, 158, 11); } + static constexpr LogColor AmberLight() { return LogColor(252, 211, 77); } + static constexpr LogColor Rose() { return LogColor(244, 63, 94); } + static constexpr LogColor RoseLight() { return LogColor(253, 164, 175); } + static constexpr LogColor Violet() { return LogColor(139, 92, 246); } + static constexpr LogColor VioletLight() { return LogColor(196, 181, 253); } + static constexpr LogColor Indigo() { return LogColor(99, 102, 241); } + static constexpr LogColor IndigoLight() { return LogColor(165, 180, 252); } +}; + /** * @brief 日志级别枚举 */ @@ -15,10 +51,11 @@ enum class LogLevel { Trace = 0, Debug = 1, Info = 2, - Warn = 3, - Error = 4, - Fatal = 5, - Off = 6 + Registry = 3, + Warn = 4, + Error = 5, + Fatal = 6, + Off = 7 }; /** @@ -68,6 +105,11 @@ public: */ virtual void info(const char *fmt, ...) = 0; + /** + * @brief Registry级别日志(用于模块/服务注册显示) + */ + virtual void registry(const char *fmt, ...) = 0; + /** * @brief Warn级别日志 */ @@ -83,6 +125,31 @@ public: */ virtual void fatal(const char *fmt, ...) = 0; + /** + * @brief 设置日志级别颜色 + * @param level 日志级别 + * @param color 颜色 + */ + virtual void setLevelColor(LogLevel level, const LogColor &color) = 0; + + /** + * @brief 获取日志级别颜色 + * @param level 日志级别 + * @return 颜色 + */ + virtual LogColor getLevelColor(LogLevel level) const = 0; + + /** + * @brief 启用/禁用颜色输出 + * @param enabled 是否启用 + */ + virtual void setColorEnabled(bool enabled) = 0; + + /** + * @brief 是否启用颜色输出 + */ + virtual bool isColorEnabled() const = 0; + ServiceInfo getServiceInfo() const override { ServiceInfo info; info.name = "Logger"; @@ -113,15 +180,24 @@ public: void trace(const char *fmt, ...) override; void debug(const char *fmt, ...) override; void info(const char *fmt, ...) override; + void registry(const char *fmt, ...) override; void warn(const char *fmt, ...) override; void error(const char *fmt, ...) override; void fatal(const char *fmt, ...) override; + void setLevelColor(LogLevel level, const LogColor &color) override; + LogColor getLevelColor(LogLevel level) const override; + void setColorEnabled(bool enabled) override; + bool isColorEnabled() const override; + private: void output(LogLevel level, const char *msg); const char *getLevelString(LogLevel level); + std::string getAnsiColor(LogLevel level); LogLevel level_; + bool colorEnabled_; + LogColor levelColors_[7]; class Impl; UniquePtr impl_; @@ -167,7 +243,6 @@ void format_impl(std::string &result, const char *fmt, T &&value, } result += *p++; } - // 没有更多的 {},追加剩余参数(不应该发生) result += " "; result += to_string(std::forward(value)); format_impl(result, p, std::forward(args)...); @@ -198,23 +273,58 @@ std::string format_str(const char *fmt, Args &&...args) { } while (0) #define E2D_LOG_TRACE(...) E2D_LOG(::extra2d::LogLevel::Trace, __VA_ARGS__) - #define E2D_LOG_DEBUG(...) E2D_LOG(::extra2d::LogLevel::Debug, __VA_ARGS__) - #define E2D_LOG_INFO(...) E2D_LOG(::extra2d::LogLevel::Info, __VA_ARGS__) - +#define E2D_LOG_REGISTRY(...) \ + E2D_LOG(::extra2d::LogLevel::Registry, __VA_ARGS__) #define E2D_LOG_WARN(...) E2D_LOG(::extra2d::LogLevel::Warn, __VA_ARGS__) - #define E2D_LOG_ERROR(...) E2D_LOG(::extra2d::LogLevel::Error, __VA_ARGS__) - #define E2D_LOG_FATAL(...) E2D_LOG(::extra2d::LogLevel::Fatal, __VA_ARGS__) // 简写宏 #define E2D_INFO(...) E2D_LOG_INFO(__VA_ARGS__) +#define E2D_REGISTRY(...) E2D_LOG_REGISTRY(__VA_ARGS__) #define E2D_WARN(...) E2D_LOG_WARN(__VA_ARGS__) #define E2D_ERROR(...) E2D_LOG_ERROR(__VA_ARGS__) #define E2D_FATAL(...) E2D_LOG_FATAL(__VA_ARGS__) +// 带颜色参数的日志宏 +#define E2D_LOG_COLOR(level, color, ...) \ + do { \ + if (auto logService = ::extra2d::ServiceLocator::instance() \ + .tryGetService<::extra2d::ILogger>()) { \ + if (logService->isEnabled(level)) { \ + auto prevColor = logService->getLevelColor(level); \ + logService->setLevelColor(level, color); \ + logService->log(level, ::extra2d::format_str(__VA_ARGS__)); \ + logService->setLevelColor(level, prevColor); \ + } \ + } \ + } while (0) + +#define E2D_LOG_TRACE_COLOR(color, ...) \ + E2D_LOG_COLOR(::extra2d::LogLevel::Trace, color, __VA_ARGS__) +#define E2D_LOG_DEBUG_COLOR(color, ...) \ + E2D_LOG_COLOR(::extra2d::LogLevel::Debug, color, __VA_ARGS__) +#define E2D_LOG_INFO_COLOR(color, ...) \ + E2D_LOG_COLOR(::extra2d::LogLevel::Info, color, __VA_ARGS__) +#define E2D_LOG_REGISTRY_COLOR(color, ...) \ + E2D_LOG_COLOR(::extra2d::LogLevel::Registry, color, __VA_ARGS__) +#define E2D_LOG_WARN_COLOR(color, ...) \ + E2D_LOG_COLOR(::extra2d::LogLevel::Warn, color, __VA_ARGS__) +#define E2D_LOG_ERROR_COLOR(color, ...) \ + E2D_LOG_COLOR(::extra2d::LogLevel::Error, color, __VA_ARGS__) +#define E2D_LOG_FATAL_COLOR(color, ...) \ + E2D_LOG_COLOR(::extra2d::LogLevel::Fatal, color, __VA_ARGS__) + +// 简写带颜色宏 +#define E2D_INFO_COLOR(color, ...) E2D_LOG_INFO_COLOR(color, __VA_ARGS__) +#define E2D_REGISTRY_COLOR(color, ...) \ + E2D_LOG_REGISTRY_COLOR(color, __VA_ARGS__) +#define E2D_WARN_COLOR(color, ...) E2D_LOG_WARN_COLOR(color, __VA_ARGS__) +#define E2D_ERROR_COLOR(color, ...) E2D_LOG_ERROR_COLOR(color, __VA_ARGS__) +#define E2D_FATAL_COLOR(color, ...) E2D_LOG_FATAL_COLOR(color, __VA_ARGS__) + #ifdef E2D_DEBUG #define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__) #define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__) diff --git a/Extra2D/src/core/registry.cpp b/Extra2D/src/core/registry.cpp index 43f641c..474d9ae 100644 --- a/Extra2D/src/core/registry.cpp +++ b/Extra2D/src/core/registry.cpp @@ -1,7 +1,5 @@ #include -#include #include -#include #include namespace extra2d { @@ -13,30 +11,24 @@ Registry &Registry::instance() { bool Registry::init() { auto sorted = topologicalSort(); - - std::cout << "[Registry] Initializing " << sorted.size() << " modules..." - << std::endl; + E2D_REGISTRY("Initializing {} modules...", sorted.size()); for (auto *module : sorted) { - std::cout << "[Registry] Initializing module: " << module->name() - << std::endl; + E2D_REGISTRY("Initializing module: {}", module->name()); if (!module->init()) { - std::cerr << "[Registry] Failed to initialize module: " << module->name() - << std::endl; + E2D_ERROR("Failed to initialize module: {}", module->name()); return false; } - std::cout << "[Registry] Module " << module->name() - << " initialized successfully" << std::endl; + E2D_REGISTRY("Module {} initialized successfully", module->name()); } - std::cout << "[Registry] All modules initialized" << std::endl; + E2D_REGISTRY("All modules initialized"); return true; } void Registry::shutdown() { auto sorted = topologicalSort(); - // 反向关闭 for (auto it = sorted.rbegin(); it != sorted.rend(); ++it) { (*it)->shutdown(); } @@ -52,7 +44,6 @@ std::vector Registry::topologicalSort() { std::unordered_map inDegree; std::unordered_map> adj; - // 构建图 for (auto &[typeIdx, module] : modules_) { inDegree[module.get()] = 0; } @@ -67,7 +58,6 @@ std::vector Registry::topologicalSort() { } } - // 优先级队列(优先级小的先处理) auto cmp = [](Module *a, Module *b) { return a->priority() > b->priority(); }; std::priority_queue, decltype(cmp)> pq(cmp); @@ -77,7 +67,6 @@ std::vector Registry::topologicalSort() { } } - // 拓扑排序 while (!pq.empty()) { Module *curr = pq.top(); pq.pop(); diff --git a/Extra2D/src/services/logger_service.cpp b/Extra2D/src/services/logger_service.cpp index 032364c..28a00a9 100644 --- a/Extra2D/src/services/logger_service.cpp +++ b/Extra2D/src/services/logger_service.cpp @@ -4,18 +4,65 @@ #include #include +#ifdef _WIN32 +#include +#endif + namespace extra2d { -// ConsoleLogger 实现 +#ifdef _WIN32 +/** + * @brief 初始化 Windows 控制台(ANSI 颜色 + UTF-8) + */ +static bool enableWindowsConsoleFeatures() { + bool success = true; + + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); + if (hOut != INVALID_HANDLE_VALUE) { + DWORD dwMode = 0; + if (GetConsoleMode(hOut, &dwMode)) { + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(hOut, dwMode)) { + success = false; + } + } else { + success = false; + } + } + + SetConsoleOutputCP(CP_UTF8); + SetConsoleCP(CP_UTF8); + + return success; +} + +static bool g_windowsConsoleInitialized = false; +#endif + class ConsoleLogger::Impl { public: std::mutex mutex_; }; ConsoleLogger::ConsoleLogger() - : level_(LogLevel::Info), impl_(std::make_unique()) { + : level_(LogLevel::Info), colorEnabled_(true), + impl_(std::make_unique()) { info_.name = "ConsoleLogger"; info_.priority = ServicePriority::Core; + + levelColors_[static_cast(LogLevel::Trace)] = LogColor::Gray(); + levelColors_[static_cast(LogLevel::Debug)] = LogColor::Cyan(); + levelColors_[static_cast(LogLevel::Info)] = LogColor::SkyLight(); + levelColors_[static_cast(LogLevel::Registry)] = LogColor::IndigoLight(); + levelColors_[static_cast(LogLevel::Warn)] = LogColor::Yellow(); + levelColors_[static_cast(LogLevel::Error)] = LogColor::Red(); + levelColors_[static_cast(LogLevel::Fatal)] = LogColor::Magenta(); + +#ifdef _WIN32 + if (!g_windowsConsoleInitialized) { + g_windowsConsoleInitialized = enableWindowsConsoleFeatures(); + } +#endif } ConsoleLogger::~ConsoleLogger() = default; @@ -87,6 +134,17 @@ void ConsoleLogger::info(const char *fmt, ...) { output(LogLevel::Info, buffer); } +void ConsoleLogger::registry(const char *fmt, ...) { + if (!isEnabled(LogLevel::Registry)) + return; + char buffer[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + output(LogLevel::Registry, buffer); +} + void ConsoleLogger::warn(const char *fmt, ...) { if (!isEnabled(LogLevel::Warn)) return; @@ -120,6 +178,32 @@ void ConsoleLogger::fatal(const char *fmt, ...) { output(LogLevel::Fatal, buffer); } +void ConsoleLogger::setLevelColor(LogLevel level, const LogColor &color) { + int idx = static_cast(level); + if (idx >= 0 && idx < 7) { + levelColors_[idx] = color; + } +} + +LogColor ConsoleLogger::getLevelColor(LogLevel level) const { + int idx = static_cast(level); + if (idx >= 0 && idx < 7) { + return levelColors_[idx]; + } + return LogColor::White(); +} + +void ConsoleLogger::setColorEnabled(bool enabled) { colorEnabled_ = enabled; } + +bool ConsoleLogger::isColorEnabled() const { return colorEnabled_; } + +std::string ConsoleLogger::getAnsiColor(LogLevel level) { + const LogColor &c = getLevelColor(level); + char buf[32]; + snprintf(buf, sizeof(buf), "\033[38;2;%d;%d;%dm", c.r, c.g, c.b); + return std::string(buf); +} + void ConsoleLogger::output(LogLevel level, const char *msg) { std::lock_guard lock(impl_->mutex_); @@ -137,36 +221,16 @@ void ConsoleLogger::output(LogLevel level, const char *msg) { #endif const char *levelStr = getLevelString(level); - - // 颜色代码 - const char *color = ""; const char *reset = "\033[0m"; - switch (level) { - case LogLevel::Trace: - color = "\033[90m"; - break; - case LogLevel::Debug: - color = "\033[36m"; - break; - case LogLevel::Info: - color = "\033[32m"; - break; - case LogLevel::Warn: - color = "\033[33m"; - break; - case LogLevel::Error: - color = "\033[31m"; - break; - case LogLevel::Fatal: - color = "\033[35m"; - break; - default: - break; + if (colorEnabled_) { + std::string color = getAnsiColor(level); + printf("%s[%02d:%02d:%02d.%03d] [%s] %s%s\n", color.c_str(), tm.tm_hour, + tm.tm_min, tm.tm_sec, (int)ms.count(), levelStr, msg, reset); + } else { + printf("[%02d:%02d:%02d.%03d] [%s] %s\n", tm.tm_hour, tm.tm_min, tm.tm_sec, + (int)ms.count(), levelStr, msg); } - - printf("%s[%02d:%02d:%02d.%03d] [%s] %s%s\n", color, tm.tm_hour, tm.tm_min, - tm.tm_sec, (int)ms.count(), levelStr, msg, reset); } const char *ConsoleLogger::getLevelString(LogLevel level) { @@ -177,6 +241,8 @@ const char *ConsoleLogger::getLevelString(LogLevel level) { return "DEBUG"; case LogLevel::Info: return "INFO"; + case LogLevel::Registry: + return "REGISTRY"; case LogLevel::Warn: return "WARN"; case LogLevel::Error: